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

feat: Sequence Sender & Aggregator #10

Merged
merged 17 commits into from
Jul 2, 2024
Merged
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
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
Loading