Skip to content

feat: add blob storage service(WIP) #1672

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

Open
wants to merge 29 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
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
45 changes: 45 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,51 @@ jobs:
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest

blob_uploader:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: check repo and create it if not exist
env:
REPOSITORY: blob-uploader
run: |
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
- name: Build and push
uses: docker/build-push-action@v3
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
REPOSITORY: blob-uploader
IMAGE_TAG: ${{ github.ref_name }}
with:
context: .
file: ./build/dockerfiles/blob_uploader.Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
scrolltech/${{ env.REPOSITORY }}:latest
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:latest

rollup-db-cli:
runs-on: ubuntu-latest
steps:
Expand Down
30 changes: 30 additions & 0 deletions build/dockerfiles/blob_uploader.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Download Go dependencies
FROM scrolltech/go-rust-builder:go-1.22-rust-nightly-2023-12-03 as base

WORKDIR /src
COPY go.work* ./
COPY ./rollup/go.* ./rollup/
COPY ./common/go.* ./common/
COPY ./coordinator/go.* ./coordinator/
COPY ./database/go.* ./database/
COPY ./tests/integration-test/go.* ./tests/integration-test/
COPY ./bridge-history-api/go.* ./bridge-history-api/
RUN go mod download -x

# Build blob_uploader
FROM base as builder

RUN --mount=target=. \
--mount=type=cache,target=/root/.cache/go-build \
cd /src/rollup/cmd/blob_uploader/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/blob_uploader

# Pull blob_uploader into a second stage deploy ubuntu container
FROM ubuntu:20.04

RUN apt update && apt install vim netcat-openbsd net-tools curl ca-certificates -y

ENV CGO_LDFLAGS="-ldl"

COPY --from=builder /bin/blob_uploader /bin/
WORKDIR /app
ENTRYPOINT ["blob_uploader"]
5 changes: 5 additions & 0 deletions build/dockerfiles/blob_uploader.Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
assets/
docs/
l2geth/
rpc-gateway/
*target/*
4 changes: 4 additions & 0 deletions common/testdata/blobdata.json

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions common/types/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,53 @@ func (s TxStatus) String() string {
return fmt.Sprintf("Unknown TxStatus (%d)", int32(s))
}
}

// BlobUploadStatus represents the status of a blob upload
type BlobUploadStatus int

const (
// BlobUploadStatusUndefined indicates an undefined status
BlobUploadStatusUndefined BlobUploadStatus = iota
// BlobUploadStatusPending indicates a pending upload status
BlobUploadStatusPending
// BlobUploadStatusUploaded indicates a successful upload status
BlobUploadStatusUploaded
// BlobUploadStatusFailed indicates a failed upload status
BlobUploadStatusFailed
)

func (s BlobUploadStatus) String() string {
switch s {
case BlobUploadStatusPending:
return "BlobUploadStatusPending"
case BlobUploadStatusUploaded:
return "BlobUploadStatusUploaded"
case BlobUploadStatusFailed:
return "BlobUploadStatusFailed"
default:
return fmt.Sprintf("Unknown BlobUploadStatus (%d)", int32(s))
}
}

// BlobStoragePlatform represents the platform a blob upload to
type BlobStoragePlatform int

const (
// BlobStoragePlatformUndefined indicates an undefined platform
BlobStoragePlatformUndefined BlobStoragePlatform = iota
// BlobStoragePlatformS3 represents AWS S3
BlobStoragePlatformS3
// BlobStoragePlatformArweave represents storage blockchain Arweave
BlobStoragePlatformArweave
)

func (s BlobStoragePlatform) String() string {
switch s {
case BlobStoragePlatformS3:
return "BlobStoragePlatformS3"
case BlobStoragePlatformArweave:
return "BlobStoragePlatformArweave"
default:
return fmt.Sprintf("Unknown BlobStoragePlatform (%d)", int32(s))
}
}
23 changes: 23 additions & 0 deletions common/utils/blob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package utils

import (
"crypto/sha256"
"fmt"

"github.com/scroll-tech/go-ethereum/crypto/kzg4844"
)

// CalculateVersionedBlobHash calculate the kzg4844 versioned blob hash from a blob
func CalculateVersionedBlobHash(blob kzg4844.Blob) ([32]byte, error) {
// calculate kzg4844 commitment from blob
commit, err := kzg4844.BlobToCommitment(&blob)
if err != nil {
return [32]byte{}, fmt.Errorf("failed to get blob commitment, err: %w", err)
}

// calculate kzg4844 versioned blob hash from blob commitment
hasher := sha256.New()
vh := kzg4844.CalcBlobHashV1(hasher, &commit)

return vh, nil
}
51 changes: 51 additions & 0 deletions common/utils/blob_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package utils

import (
"encoding/hex"
"encoding/json"
"os"
"testing"

"github.com/scroll-tech/go-ethereum/crypto/kzg4844"
)

type BlobData struct {
VersionedBlobHash string `json:"versionedBlobHash"`
BlobData string `json:"blobData"`
}

// TestCalculateVersionedBlobHash tests the CalculateVersionedBlobHash function
func TestCalculateVersionedBlobHash(t *testing.T) {
// Read the test data
data, err := os.ReadFile("../testdata/blobdata.json")
if err != nil {
t.Fatalf("Failed to read blobdata.json: %v", err)
}

var blobData BlobData
if err := json.Unmarshal(data, &blobData); err != nil {
t.Fatalf("Failed to parse blobdata.json: %v", err)
}

blobBytes, err := hex.DecodeString(blobData.BlobData)
if err != nil {
t.Fatalf("Failed to decode blob data: %v", err)
}

// Convert []byte to kzg4844.Blob
var blob kzg4844.Blob
copy(blob[:], blobBytes)

// Calculate the hash
calculatedHashBytes, err := CalculateVersionedBlobHash(blob)
if err != nil {
t.Fatalf("Failed to calculate versioned blob hash: %v", err)
}

calculatedHash := hex.EncodeToString(calculatedHashBytes[:])

if calculatedHash != blobData.VersionedBlobHash {
t.Fatalf("Hash mismatch: got %s, want %s", calculatedHash, blobData.VersionedBlobHash)
}

}
1 change: 1 addition & 0 deletions coordinator/internal/types/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"fmt"

"scroll-tech/common/types/message"
)

Expand Down
6 changes: 3 additions & 3 deletions database/migrate/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,20 @@ func testResetDB(t *testing.T) {
cur, err := Current(pgDB)
assert.NoError(t, err)
// total number of tables.
assert.Equal(t, int64(26), cur)
assert.Equal(t, int64(27), cur)
}

func testMigrate(t *testing.T) {
assert.NoError(t, Migrate(pgDB))
cur, err := Current(pgDB)
assert.NoError(t, err)
assert.Equal(t, int64(26), cur)
assert.Equal(t, int64(27), cur)
}

func testRollback(t *testing.T) {
version, err := Current(pgDB)
assert.NoError(t, err)
assert.Equal(t, int64(26), version)
assert.Equal(t, int64(27), version)

assert.NoError(t, Rollback(pgDB, nil))

Expand Down
35 changes: 35 additions & 0 deletions database/migrate/migrations/00027_ blob_upload.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
-- +goose Up
-- +goose StatementBegin

CREATE TABLE blob_upload (
batch_index BIGINT NOT NULL,

platform SMALLINT NOT NULL,
status SMALLINT NOT NULL,

-- metadata
created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP(0) DEFAULT NULL,

PRIMARY KEY (batch_index, platform)
);

COMMENT ON COLUMN blob_upload.status IS 'undefined, pending, uploaded, failed';

CREATE INDEX IF NOT EXISTS idx_blob_upload_batch_index ON blob_upload(batch_index) WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_blob_upload_platform ON blob_upload(platform) WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_blob_upload_status ON blob_upload(status) WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_blob_upload_status_platform ON blob_upload(status, platform) WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_blob_upload_batch_index_status_platform ON blob_upload(batch_index, status, platform) WHERE deleted_at IS NULL;

-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
DROP TABLE blob_upload;
-- +goose StatementEnd
4 changes: 1 addition & 3 deletions go.work
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
go 1.22

toolchain go1.22.2
go 1.22.4

use (
./bridge-history-api
Expand Down
Loading
Loading