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

Adding features to mempool to support our pre-ordered txs #2

Merged
merged 21 commits into from
Apr 10, 2023
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
57 changes: 43 additions & 14 deletions .github/workflows/astria-build-and-publish-image.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,59 @@
name: Build and Publish Docker image

# Trigger on pushes to astria branch, new semantic version tags, and pull request updates
on:
workflow_dispatch:
push:
branches:
- astria # Running this job only for astria branch
- "astria"
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+"
# trigger on pull request updates when target is `astria` branch
pull_request:
branches:
- "astria"

jobs:
build-and-publish-latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2 # Checking out the repo
# Checking out the repo
- uses: actions/checkout@v2
# Setting up Go
- uses: actions/setup-go@v4
with:
go-version: "^1.20.x" # The Go version to download (if necessary) and use.
- run: go version

# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin

# TODO - build for amd64 and arm64?
# FIXME - version needs to be autoincrement, probably from git tags?
- name: Build latest Docker image
run: |
docker build \
--build-arg COMMIT=${GITHUB_SHA} \
--build-arg VERSION=0.1 \
--build-arg BUILDNUM=${GITHUB_RUN_NUMBER} \
--tag ghcr.io/astriaorg/go-ethereum:latest .
- name: Push latest Docker image
run: docker push ghcr.io/astriaorg/go-ethereum:latest
# Generate correct tabs and labels
- name: Docker metadata
id: metadata
uses: docker/metadata-action@v4
with:
images: |
ghcr.io/astriaorg/go-ethereum
tags: |
type=ref,event=pr
type=semver,pattern={{major}}.{{minor}}.{{patch}}
type=sha
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
# It takes over 30 minutes to build the arm image right now, so we only build it on tags which is what we use for releases.
platforms: ${{ contains(github.ref, 'refs/tags/v') && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth
FROM alpine:latest

RUN apk add --no-cache ca-certificates
# Astria - add bash and jq to support start-geth.sh in conductor
RUN apk add bash jq
# Astria - copy genesis.json so it can be used in start-geth.sh
COPY genesis.json /genesis.json
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/

# Astria - add 50051 for GRPC
Expand Down
4 changes: 3 additions & 1 deletion cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/grpc/execution"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/internal/version"
Expand Down Expand Up @@ -174,7 +175,8 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {

// Configure gRPC if requested.
if ctx.IsSet(utils.GRPCEnabledFlag.Name) {
utils.RegisterGRPCService(stack, backend, &cfg.Node)
service := execution.NewExecutionServiceServer(eth)
utils.RegisterGRPCService(stack, service, &cfg.Node)
}

// Add the Ethereum Stats daemon if requested.
Expand Down
9 changes: 4 additions & 5 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb/remotedb"
"github.com/ethereum/go-ethereum/ethstats"
"github.com/ethereum/go-ethereum/graphql"
executionv1 "github.com/ethereum/go-ethereum/grpc/gen/proto/execution/v1"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/les"
Expand Down Expand Up @@ -2042,9 +2043,7 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend
Fatalf("Failed to create the LES server: %v", err)
}
}
if err := ethcatalyst.Register(stack, backend); err != nil {
Fatalf("Failed to register the Engine API service: %v", err)
}

stack.RegisterAPIs(tracers.APIs(backend.APIBackend))
return backend.APIBackend, backend
}
Expand All @@ -2066,8 +2065,8 @@ func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, filterSyst

// RegisterGRPCService adds the gRPC API to the node.
// It was done this way so that our grpc execution server can access the ethapi.Backend
func RegisterGRPCService(stack *node.Node, backend ethapi.Backend, cfg *node.Config) {
if err := node.NewGRPCServerHandler(stack, backend, cfg); err != nil {
func RegisterGRPCService(stack *node.Node, execServer executionv1.ExecutionServiceServer, cfg *node.Config) {
if err := node.NewGRPCServerHandler(stack, execServer, cfg); err != nil {
Fatalf("Failed to register the gRPC service: %v", err)
}
}
Expand Down
1 change: 0 additions & 1 deletion consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
}
// Verify the block's difficulty based on its timestamp and parent's difficulty
expected := ethash.CalcDifficulty(chain, header.Time, parent)

if expected.Cmp(header.Difficulty) != 0 {
return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected)
}
Expand Down
117 changes: 117 additions & 0 deletions core/txpool/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ type TxPool struct {
pendingNonces *noncer // Pending state tracking virtual nonces
currentMaxGas uint64 // Current gas limit for transaction caps

astria *astriaOrdered
locals *accountSet // Set of local transaction to exempt from eviction rules
journal *journal // Journal of local transaction to back up to disk

Expand Down Expand Up @@ -926,6 +927,108 @@ func (pool *TxPool) AddLocal(tx *types.Transaction) error {
return errs[0]
}

func (pool *TxPool) SetAstriaOrdered(rawTxs [][]byte) {
txs := []*types.Transaction{}
for idx, rawTx := range rawTxs {
tx := new(types.Transaction)
err := tx.UnmarshalBinary(rawTx)
if err != nil {
log.Warn("failed to unmarshal raw astria tx bytes", rawTx, "at index", idx, "error:", err)
continue
}

err = pool.astriaValidate(tx)
if err != nil {
log.Warn("astria tx failed validation at index", idx, "error:", err)
continue
}

txs = append(txs, tx)
}

pool.astria = newAstriaOrdered(types.Transactions(txs))
}

func (pool *TxPool) ClearAstriaOrdered() {
if pool.astria == nil {
return
}
pool.astria.clear()
}

func (pool *TxPool) AstriaOrdered() *types.Transactions {
// sus but whatever
if pool.astria == nil {
return &types.Transactions{}
}
return &pool.astria.txs
}

// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *TxPool) astriaValidate(tx *types.Transaction) error {
// Accept only legacy transactions until EIP-2718/2930 activates.
if !pool.eip2718 && tx.Type() != types.LegacyTxType {
return core.ErrTxTypeNotSupported
}
// Reject dynamic fee transactions until EIP-1559 activates.
if !pool.eip1559 && tx.Type() == types.DynamicFeeTxType {
return core.ErrTxTypeNotSupported
}
// Reject transactions over defined size to prevent DOS attacks
if tx.Size() > txMaxSize {
return ErrOversizedData
}
// Check whether the init code size has been exceeded.
if pool.shanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)
}
// Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur if you create a transaction using the RPC.
if tx.Value().Sign() < 0 {
return ErrNegativeValue
}
// Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas < tx.Gas() {
return ErrGasLimit
}
// Sanity check for extremely large numbers
if tx.GasFeeCap().BitLen() > 256 {
return core.ErrFeeCapVeryHigh
}
if tx.GasTipCap().BitLen() > 256 {
return core.ErrTipVeryHigh
}
// Ensure gasFeeCap is greater than or equal to gasTipCap.
if tx.GasFeeCapIntCmp(tx.GasTipCap()) < 0 {
return core.ErrTipAboveFeeCap
}
// Make sure the transaction is signed properly.
from, err := types.Sender(pool.signer, tx)
if err != nil {
return ErrInvalidSender
}
// Ensure the transaction adheres to nonce ordering
if pool.currentState.GetNonce(from) > tx.Nonce() {
return core.ErrNonceTooLow
}
// Transactor should have enough funds to cover the costs
// cost == V + GP * GL
balance := pool.currentState.GetBalance(from)
if balance.Cmp(tx.Cost()) < 0 {
return core.ErrInsufficientFunds
}
// Ensure the transaction has more gas than the basic tx fee.
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai)
if err != nil {
return err
}
if tx.Gas() < intrGas {
return core.ErrIntrinsicGas
}
return nil
}

// AddRemotes enqueues a batch of transactions into the pool if they are valid. If the
// senders are not among the locally tracked ones, full pricing constraints will apply.
//
Expand Down Expand Up @@ -1647,6 +1750,20 @@ func (a addressesByHeartbeat) Len() int { return len(a) }
func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) }
func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

type astriaOrdered struct {
txs types.Transactions
}

func newAstriaOrdered(txs types.Transactions) *astriaOrdered {
return &astriaOrdered{
txs: txs,
}
}

func (ao *astriaOrdered) clear() {
ao.txs = *&types.Transactions{}
}

// accountSet is simply a set of addresses to check for existence, and a signer
// capable of deriving addresses from transactions.
type accountSet struct {
Expand Down
39 changes: 20 additions & 19 deletions genesis.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
{
"config": {
"chainId": 1337,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"ethash": {}
},
"difficulty": "10000",
"gasLimit": "8000000",
"alloc": {
"0x46B77EFDFB20979E1C29ec98DcE73e3eCbF64102": { "balance": "300000000000000000000" }
}
}
"chainId": 1337,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"terminalTotalDifficulty": 0,
"ethash": {}
},
"difficulty": "10000000",
"gasLimit": "8000000",
"alloc": {
"0x46B77EFDFB20979E1C29ec98DcE73e3eCbF64102": { "balance": "300000000000000000000" }
}
}
6 changes: 4 additions & 2 deletions grpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ brew install leveldb
# build geth
make geth

# run geth
./build/bin/geth --goerli --grpc --grpc.addr "0.0.0.0" --grpc.port 50051
# generating protobuf files
buf generate buf.build/astria/execution-apis
```

See [private_network.md](../private_network.md) for running a local geth node.

### Running with remote Docker image:
```bash
docker run --rm \
Expand Down
Loading