Skip to content

Commit

Permalink
feat: Sequence Sender & Aggregator (#10)
Browse files Browse the repository at this point in the history
* feat: sequence sender and aggregator
  • Loading branch information
ToniRamirezM authored and Stefan-Ethernal committed Sep 17, 2024
1 parent f256553 commit 26e7139
Show file tree
Hide file tree
Showing 86 changed files with 15,442 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/.DS_Store
.vscode
.env
/dist/
cmd/__debug_bin
22 changes: 11 additions & 11 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,32 @@ linters:
disable-all: true
enable:
- whitespace # Tool for detection of leading and trailing whitespace
- wsl # Forces you to use empty lines
# - wsl # Forces you to use empty lines
- wastedassign # Finds wasted assignment statements
- unconvert # Unnecessary type conversions
- tparallel # Detects inappropriate usage of t.Parallel() method in your Go test codes
- thelper # Detects golang test helpers without t.Helper() call and checks the consistency of test helpers
- stylecheck # Stylecheck is a replacement for golint
- prealloc # Finds slice declarations that could potentially be pre-allocated
# - stylecheck # Stylecheck is a replacement for golint
# - prealloc # Finds slice declarations that could potentially be pre-allocated
- predeclared # Finds code that shadows one of Go's predeclared identifiers
- nolintlint # Ill-formed or insufficient nolint directives
- nlreturn # Checks for a new line before return and branch statements to increase code clarity
# - nolintlint # Ill-formed or insufficient nolint directives
# - nlreturn # Checks for a new line before return and branch statements to increase code clarity
- misspell # Misspelled English words in comments
- makezero # Finds slice declarations with non-zero initial length
- lll # Long lines
# - lll # Long lines
- importas # Enforces consistent import aliases
- gosec # Security problems
- gofmt # Whether the code was gofmt-ed
- goimports # Unused imports
- goconst # Repeated strings that could be replaced by a constant
- forcetypeassert # Finds forced type assertions
# - forcetypeassert # Finds forced type assertions
- dogsled # Checks assignments with too many blank identifiers (e.g. x, , , _, := f())
- dupl # Code clone detection
# - dupl # Code clone detection
- errname # Checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error
- errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13
- gocritic
# - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13
# - gocritic
- errcheck # Errcheck is a go lint rule for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
- godox # Godox is a linter for TODOs and FIXMEs left in the code
# - godox # Godox is a linter for TODOs and FIXMEs left in the code

linters-settings:
gofmt:
Expand Down
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# CONTAINER FOR BUILDING BINARY
FROM golang:1.22.4 AS build

# INSTALL DEPENDENCIES
RUN go install github.com/gobuffalo/packr/v2/[email protected]
COPY go.mod go.sum /src/
RUN cd /src && go mod download

# BUILD BINARY
COPY . /src
RUN cd /src/aggregator/db && packr2
RUN cd /src && make build

# CONTAINER FOR RUNNING BINARY
FROM alpine:3.18.4
COPY --from=build /src/dist/cdk /app/cdk
RUN apk update && apk add postgresql15-client
EXPOSE 8123
CMD ["/bin/sh", "-c", "/app/cdk run"]
116 changes: 116 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
include version.mk

ARCH := $(shell arch)

ifeq ($(ARCH),x86_64)
ARCH = amd64
else
ifeq ($(ARCH),aarch64)
ARCH = arm64
endif
endif
GOBASE := $(shell pwd)
GOBIN := $(GOBASE)/dist
GOENVVARS := GOBIN=$(GOBIN) CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH)
GOBINARY := cdk
GOCMD := $(GOBASE)/cmd

LDFLAGS += -X 'github.com/0xPolygon/cdk.Version=$(VERSION)'
LDFLAGS += -X 'github.com/0xPolygon/cdk.GitRev=$(GITREV)'
LDFLAGS += -X 'github.com/0xPolygon/cdk.GitBranch=$(GITBRANCH)'
LDFLAGS += -X 'github.com/0xPolygon/cdk.BuildDate=$(DATE)'

# Variables
VENV = .venv
VENV_PYTHON = $(VENV)/bin/python
SYSTEM_PYTHON = $(or $(shell which python3), $(shell which python))
PYTHON = $(or $(wildcard $(VENV_PYTHON)), "install_first_venv")
GENERATE_SCHEMA_DOC = $(VENV)/bin/generate-schema-doc
GENERATE_DOC_PATH = "docs/config-file/"
GENERATE_DOC_TEMPLATES_PATH = "docs/config-file/templates/"

# Check dependencies
# Check for Go
.PHONY: check-go
check-go:
@which go > /dev/null || (echo "Error: Go is not installed" && exit 1)

# Check for Docker
.PHONY: check-docker
check-docker:
@which docker > /dev/null || (echo "Error: docker is not installed" && exit 1)

# Check for Docker-compose
.PHONY: check-docker-compose
check-docker-compose:
@which docker-compose > /dev/null || (echo "Error: docker-compose is not installed" && exit 1)

# Check for Protoc
.PHONY: check-protoc
check-protoc:
@which protoc > /dev/null || (echo "Error: Protoc is not installed" && exit 1)

# Check for Curl
.PHONY: check-curl
check-curl:
@which curl > /dev/null || (echo "Error: curl is not installed" && exit 1)

# Targets that require the checks
build: check-go
lint: check-go
build-docker: check-docker
build-docker-nc: check-docker
stop: check-docker check-docker-compose
install-linter: check-go check-curl
generate-code-from-proto: check-protoc

.PHONY: build
build: ## Builds the binary locally into ./dist
$(GOENVVARS) go build -ldflags "all=$(LDFLAGS)" -o $(GOBIN)/$(GOBINARY) $(GOCMD)

.PHONY: build-docker
build-docker: ## Builds a docker image with the cdk binary
docker build -t cdk -f ./Dockerfile .

.PHONY: build-docker-nc
build-docker-nc: ## Builds a docker image with the cdk binary - but without build cache
docker build --no-cache=true -t cdk -f ./Dockerfile .

.PHONY: stop
stop: ## Stops all services
docker-compose down

.PHONY: test
test:
go test -count=1 -short -race -p 1 -timeout 60s ./...

.PHONY: install-linter
install-linter: ## Installs the linter
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$(go env GOPATH)/bin v1.54.2

.PHONY: lint
lint: ## Runs the linter
export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/golangci-lint run

$(VENV_PYTHON):
rm -rf $(VENV)
$(SYSTEM_PYTHON) -m venv $(VENV)

venv: $(VENV_PYTHON)

.PHONY: generate-code-from-proto
generate-code-from-proto: ## Generates code from proto files
cd proto/src/proto/aggregator/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../aggregator/prover --go-grpc_out=../../../../../aggregator/prover --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative aggregator.proto
cd proto/src/proto/datastream/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../state/datastream --go-grpc_out=../../../../../state/datastream --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative datastream.proto


## Help display.
## Pulls comments from beside commands and prints a nicely formatted
## display with the commands and their usage information.
.DEFAULT_GOAL := help

.PHONY: help
help: ## Prints this help
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| sort \
| awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
81 changes: 81 additions & 0 deletions aggregator/agglayer_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package aggregator

import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"time"

"github.com/0xPolygon/cdk-rpc/rpc"
"github.com/0xPolygon/cdk-rpc/types"
"github.com/ethereum/go-ethereum/common"
)

// AgglayerClientInterface is the interface that defines the methods that the AggLayerClient will implement
type AgglayerClientInterface interface {
SendTx(signedTx SignedTx) (common.Hash, error)
WaitTxToBeMined(hash common.Hash, ctx context.Context) error
}

// AggLayerClient is the client that will be used to interact with the AggLayer
type AggLayerClient struct {
url string
}

// NewAggLayerClient returns a client ready to be used
func NewAggLayerClient(url string) *AggLayerClient {
return &AggLayerClient{
url: url,
}
}

// SendTx sends a signed transaction to the AggLayer
func (c *AggLayerClient) SendTx(signedTx SignedTx) (common.Hash, error) {
response, err := rpc.JSONRPCCall(c.url, "interop_sendTx", signedTx)
if err != nil {
return common.Hash{}, err
}

if response.Error != nil {
return common.Hash{}, fmt.Errorf("%v %v", response.Error.Code, response.Error.Message)
}

var result types.ArgHash
err = json.Unmarshal(response.Result, &result)
if err != nil {
return common.Hash{}, err
}

return result.Hash(), nil
}

// WaitTxToBeMined waits for a transaction to be mined
func (c *AggLayerClient) WaitTxToBeMined(hash common.Hash, ctx context.Context) error {
ticker := time.NewTicker(time.Second)
for {
select {
case <-ctx.Done():
return errors.New("context finished before tx was mined")
case <-ticker.C:
response, err := rpc.JSONRPCCall(c.url, "interop_getTxStatus", hash)
if err != nil {
return err
}

if response.Error != nil {
return fmt.Errorf("%v %v", response.Error.Code, response.Error.Message)
}

var result string
err = json.Unmarshal(response.Result, &result)
if err != nil {
return err
}
if strings.ToLower(result) == "done" {
return nil
}
}
}
}
63 changes: 63 additions & 0 deletions aggregator/agglayer_tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package aggregator

import (
"crypto/ecdsa"

"github.com/0xPolygon/cdk-rpc/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)

// ZKP is the struct that contains the zero-knowledge proof
type ZKP struct {
NewStateRoot common.Hash `json:"newStateRoot"`
NewLocalExitRoot common.Hash `json:"newLocalExitRoot"`
Proof types.ArgBytes `json:"proof"`
}

// Tx is the struct that contains the verified batch transaction
type Tx struct {
RollupID uint32
LastVerifiedBatch types.ArgUint64 `json:"lastVerifiedBatch"`
NewVerifiedBatch types.ArgUint64 `json:"newVerifiedBatch"`
ZKP ZKP `json:"ZKP"`
}

// Hash returns a hash that uniquely identifies the tx
func (t *Tx) Hash() common.Hash {
return common.BytesToHash(crypto.Keccak256(
[]byte(t.LastVerifiedBatch.Hex()),
[]byte(t.NewVerifiedBatch.Hex()),
t.ZKP.NewStateRoot[:],
t.ZKP.NewLocalExitRoot[:],
[]byte(t.ZKP.Proof.Hex()),
))
}

// Sign returns a signed batch by the private key
func (t *Tx) Sign(privateKey *ecdsa.PrivateKey) (*SignedTx, error) {
hashToSign := t.Hash()
sig, err := crypto.Sign(hashToSign.Bytes(), privateKey)
if err != nil {
return nil, err
}
return &SignedTx{
Tx: *t,
Signature: sig,
}, nil
}

// SignedTx is the struct that contains the signed batch transaction
type SignedTx struct {
Tx Tx `json:"tx"`
Signature types.ArgBytes `json:"signature"`
}

// Signer returns the address of the signer
func (s *SignedTx) Signer() (common.Address, error) {
pubKey, err := crypto.SigToPub(s.Tx.Hash().Bytes(), s.Signature)
if err != nil {
return common.Address{}, err
}
return crypto.PubkeyToAddress(*pubKey), nil
}
Loading

0 comments on commit 26e7139

Please sign in to comment.