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

* Adding features to mempool to support our pre-ordered txs

* Add framing for gRPC to execute blocks

* Remove public engine API call

* Fix circular dependencies

* Updated to use new Init, and fill out starting attributes

* Add clear astriaordered, cleanup

* readme fix

* add bash and jq to final docker image

* make txpool interface

* no more panics, update DoBlock to also update state + store block

* cleanup

* set post-merge at genesis

* cleanup

* doc update

* remove txpool interface changes

* cleanup

* cleanup

* build and push images wih tags defined by git tags

* build for multiple architectures. use docker-metadata action for semver

* add push: true

* only build arm for git tags/releases

---------

Co-authored-by: Jesse Snyder <jessetsnyder@gmail.com>
Co-authored-by: elizabeth <elizabethjbinks@gmail.com>
This commit is contained in:
Jordan Oroshiba 2023-04-10 10:21:41 -07:00 committed by GitHub
parent 5ec91e0268
commit f91e86a130
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 607 additions and 143 deletions

View file

@ -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 }}

View file

@ -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

View file

@ -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"
@ -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.

View file

@ -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"
@ -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
}
@ -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)
}
}

View file

@ -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)
}

View file

@ -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
@ -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.
//
@ -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 {

View file

@ -11,9 +11,10 @@
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"terminalTotalDifficulty": 0,
"ethash": {}
},
"difficulty": "10000",
"difficulty": "10000000",
"gasLimit": "8000000",
"alloc": {
"0x46B77EFDFB20979E1C29ec98DcE73e3eCbF64102": { "balance": "300000000000000000000" }

View file

@ -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 \

View file

@ -6,10 +6,16 @@ package execution
import (
"context"
"fmt"
"time"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/catalyst"
executionv1 "github.com/ethereum/go-ethereum/grpc/gen/proto/execution/v1"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
)
@ -20,45 +26,96 @@ type ExecutionServiceServer struct {
// for forward compatibility
executionv1.UnimplementedExecutionServiceServer
// TODO - will need access to the consensus api to call functions for building a block
// e.g. getPayload, newPayload, forkchoiceUpdated
consensus *catalyst.ConsensusAPI
eth *eth.Ethereum
Backend ethapi.Backend
// TODO - will need access to forkchoice on first run.
// this will probably be passed in when calling NewServer
bc *core.BlockChain
}
// FIXME - how do we know which hash to start with? will probably need another api function like
// GetHeadHash() to get the head hash of the forkchoice
func NewExecutionServiceServer(eth *eth.Ethereum) *ExecutionServiceServer {
consensus := catalyst.NewConsensusAPI(eth)
bc := eth.BlockChain()
return &ExecutionServiceServer{
eth: eth,
consensus: consensus,
bc: bc,
}
}
func (s *ExecutionServiceServer) DoBlock(ctx context.Context, req *executionv1.DoBlockRequest) (*executionv1.DoBlockResponse, error) {
log.Info("DoBlock called request", "request", req)
prevHeadHash := common.BytesToHash(req.PrevStateRoot)
// NOTE - Request.Header.ParentHash needs to match forkchoice head hash
// ParentHash should be the forkchoice head of the last block
// The Engine API has been modified to use transactions from this mempool and abide by it's ordering.
s.eth.TxPool().SetAstriaOrdered(req.Transactions)
// TODO - need to call consensus api to build a block
// Do the whole Engine API in a single loop
startForkChoice := &engine.ForkchoiceStateV1{
HeadBlockHash: prevHeadHash,
SafeBlockHash: prevHeadHash,
FinalizedBlockHash: prevHeadHash,
}
payloadAttributes := &engine.PayloadAttributes{
Timestamp: uint64(req.GetTimestamp().GetSeconds()),
Random: common.Hash{},
SuggestedFeeRecipient: common.Address{},
}
fcStartResp, err := s.consensus.ForkchoiceUpdatedV1(*startForkChoice, payloadAttributes)
if err != nil {
return nil, err
}
// txs := bytesToTransactions(req.Transactions)
// for _, tx := range txs {
// s.Backend.SendTx(ctx, tx)
// }
// super janky but this is what the payload builder requires :/ (miner.worker.buildPayload())
// we should probably just execute + store the block directly instead of using the engine api.
time.Sleep(time.Second)
payloadResp, err := s.consensus.GetPayloadV1(*fcStartResp.PayloadID)
if err != nil {
log.Error("failed to call GetPayloadV1", "err", err)
return nil, err
}
// call blockchain.InsertChain to actually execute and write the blocks to state
block, err := engine.ExecutableDataToBlock(*payloadResp)
if err != nil {
return nil, err
}
blocks := types.Blocks{
block,
}
n, err := s.bc.InsertChain(blocks)
if err != nil {
return nil, err
}
if n != 1 {
return nil, fmt.Errorf("failed to insert block into blockchain (n=%d)", n)
}
newForkChoice := &engine.ForkchoiceStateV1{
HeadBlockHash: block.Hash(),
SafeBlockHash: block.Hash(),
FinalizedBlockHash: block.Hash(),
}
fcEndResp, err := s.consensus.ForkchoiceUpdatedV1(*newForkChoice, nil)
if err != nil {
log.Error("failed to call ForkchoiceUpdatedV1", "err", err)
return nil, err
}
res := &executionv1.DoBlockResponse{
// TODO - get state root from last block
StateRoot: []byte{0x00},
// TODO: RENAME THIS - this is not the state root!! it's the block hash
StateRoot: fcEndResp.PayloadStatus.LatestValidHash.Bytes(),
}
return res, nil
}
// convert bytes to transactions
func bytesToTransactions(b [][]byte) []*types.Transaction {
txs := []*types.Transaction{}
for _, txBytes := range b {
tx := &types.Transaction{}
tx.UnmarshalBinary(txBytes)
txs = append(txs, tx)
func (s *ExecutionServiceServer) InitState(ctx context.Context, req *executionv1.InitStateRequest) (*executionv1.InitStateResponse, error) {
currHead := s.eth.BlockChain().CurrentHeader()
res := &executionv1.InitStateResponse{
// TODO: RENAME THIS - this is not the state root!! it's the block hash
StateRoot: currHead.Hash().Bytes(),
}
return txs
return res, nil
}

View file

@ -9,6 +9,7 @@ package executionv1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
@ -25,8 +26,9 @@ type DoBlockRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Header []byte `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
PrevStateRoot []byte `protobuf:"bytes,1,opt,name=prev_state_root,json=prevStateRoot,proto3" json:"prev_state_root,omitempty"`
Transactions [][]byte `protobuf:"bytes,2,rep,name=transactions,proto3" json:"transactions,omitempty"`
Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
}
func (x *DoBlockRequest) Reset() {
@ -61,9 +63,9 @@ func (*DoBlockRequest) Descriptor() ([]byte, []int) {
return file_proto_execution_v1_execution_proto_rawDescGZIP(), []int{0}
}
func (x *DoBlockRequest) GetHeader() []byte {
func (x *DoBlockRequest) GetPrevStateRoot() []byte {
if x != nil {
return x.Header
return x.PrevStateRoot
}
return nil
}
@ -75,6 +77,13 @@ func (x *DoBlockRequest) GetTransactions() [][]byte {
return nil
}
func (x *DoBlockRequest) GetTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.Timestamp
}
return nil
}
type DoBlockResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -122,39 +131,140 @@ func (x *DoBlockResponse) GetStateRoot() []byte {
return nil
}
type InitStateRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *InitStateRequest) Reset() {
*x = InitStateRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_execution_v1_execution_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InitStateRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InitStateRequest) ProtoMessage() {}
func (x *InitStateRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_execution_v1_execution_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InitStateRequest.ProtoReflect.Descriptor instead.
func (*InitStateRequest) Descriptor() ([]byte, []int) {
return file_proto_execution_v1_execution_proto_rawDescGZIP(), []int{2}
}
type InitStateResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
StateRoot []byte `protobuf:"bytes,1,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
}
func (x *InitStateResponse) Reset() {
*x = InitStateResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_execution_v1_execution_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InitStateResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InitStateResponse) ProtoMessage() {}
func (x *InitStateResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_execution_v1_execution_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InitStateResponse.ProtoReflect.Descriptor instead.
func (*InitStateResponse) Descriptor() ([]byte, []int) {
return file_proto_execution_v1_execution_proto_rawDescGZIP(), []int{3}
}
func (x *InitStateResponse) GetStateRoot() []byte {
if x != nil {
return x.StateRoot
}
return nil
}
var File_proto_execution_v1_execution_proto protoreflect.FileDescriptor
var file_proto_execution_v1_execution_proto_rawDesc = []byte{
0x0a, 0x22, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f,
0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x76, 0x31, 0x22, 0x4c, 0x0a, 0x0e, 0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x22, 0x30, 0x0a, 0x0f, 0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f,
0x6f, 0x74, 0x32, 0x5a, 0x0a, 0x10, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31,
0x2e, 0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1d, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44,
0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0xb8,
0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,
0x2e, 0x76, 0x31, 0x42, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72,
0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x74,
0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x65,
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x45, 0x58, 0x58,
0xaa, 0x02, 0x0c, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0xca,
0x02, 0x0c, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0xe2, 0x02,
0x18, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50,
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x45, 0x78, 0x65, 0x63,
0x75, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x96, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x73,
0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x0d, 0x70, 0x72, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x22,
0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02,
0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x30, 0x0a, 0x0f,
0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x12,
0x0a, 0x10, 0x49, 0x6e, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x22, 0x32, 0x0a, 0x11, 0x49, 0x6e, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65,
0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61,
0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x32, 0xa8, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x65, 0x63, 0x75,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x44,
0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,
0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x49, 0x6e, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65,
0x12, 0x1e, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
0x49, 0x6e, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1f, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
0x49, 0x6e, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x42, 0xb8, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f,
0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x6f,
0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76,
0x31, 0x3b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0xa2, 0x02, 0x03,
0x45, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x56, 0x31, 0xca, 0x02, 0x0c, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56,
0x31, 0xe2, 0x02, 0x18, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31,
0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x45,
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -169,19 +279,25 @@ func file_proto_execution_v1_execution_proto_rawDescGZIP() []byte {
return file_proto_execution_v1_execution_proto_rawDescData
}
var file_proto_execution_v1_execution_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_proto_execution_v1_execution_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proto_execution_v1_execution_proto_goTypes = []interface{}{
(*DoBlockRequest)(nil), // 0: execution.v1.DoBlockRequest
(*DoBlockResponse)(nil), // 1: execution.v1.DoBlockResponse
(*InitStateRequest)(nil), // 2: execution.v1.InitStateRequest
(*InitStateResponse)(nil), // 3: execution.v1.InitStateResponse
(*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp
}
var file_proto_execution_v1_execution_proto_depIdxs = []int32{
0, // 0: execution.v1.ExecutionService.DoBlock:input_type -> execution.v1.DoBlockRequest
1, // 1: execution.v1.ExecutionService.DoBlock:output_type -> execution.v1.DoBlockResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
4, // 0: execution.v1.DoBlockRequest.timestamp:type_name -> google.protobuf.Timestamp
0, // 1: execution.v1.ExecutionService.DoBlock:input_type -> execution.v1.DoBlockRequest
2, // 2: execution.v1.ExecutionService.InitState:input_type -> execution.v1.InitStateRequest
1, // 3: execution.v1.ExecutionService.DoBlock:output_type -> execution.v1.DoBlockResponse
3, // 4: execution.v1.ExecutionService.InitState:output_type -> execution.v1.InitStateResponse
3, // [3:5] is the sub-list for method output_type
1, // [1:3] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proto_execution_v1_execution_proto_init() }
@ -214,6 +330,30 @@ func file_proto_execution_v1_execution_proto_init() {
return nil
}
}
file_proto_execution_v1_execution_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InitStateRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_execution_v1_execution_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InitStateResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@ -221,7 +361,7 @@ func file_proto_execution_v1_execution_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_execution_v1_execution_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},

View file

@ -20,6 +20,7 @@ const _ = grpc.SupportPackageIsVersion7
const (
ExecutionService_DoBlock_FullMethodName = "/execution.v1.ExecutionService/DoBlock"
ExecutionService_InitState_FullMethodName = "/execution.v1.ExecutionService/InitState"
)
// ExecutionServiceClient is the client API for ExecutionService service.
@ -27,6 +28,7 @@ const (
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ExecutionServiceClient interface {
DoBlock(ctx context.Context, in *DoBlockRequest, opts ...grpc.CallOption) (*DoBlockResponse, error)
InitState(ctx context.Context, in *InitStateRequest, opts ...grpc.CallOption) (*InitStateResponse, error)
}
type executionServiceClient struct {
@ -46,11 +48,21 @@ func (c *executionServiceClient) DoBlock(ctx context.Context, in *DoBlockRequest
return out, nil
}
func (c *executionServiceClient) InitState(ctx context.Context, in *InitStateRequest, opts ...grpc.CallOption) (*InitStateResponse, error) {
out := new(InitStateResponse)
err := c.cc.Invoke(ctx, ExecutionService_InitState_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ExecutionServiceServer is the server API for ExecutionService service.
// All implementations must embed UnimplementedExecutionServiceServer
// for forward compatibility
type ExecutionServiceServer interface {
DoBlock(context.Context, *DoBlockRequest) (*DoBlockResponse, error)
InitState(context.Context, *InitStateRequest) (*InitStateResponse, error)
mustEmbedUnimplementedExecutionServiceServer()
}
@ -61,6 +73,9 @@ type UnimplementedExecutionServiceServer struct {
func (UnimplementedExecutionServiceServer) DoBlock(context.Context, *DoBlockRequest) (*DoBlockResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DoBlock not implemented")
}
func (UnimplementedExecutionServiceServer) InitState(context.Context, *InitStateRequest) (*InitStateResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method InitState not implemented")
}
func (UnimplementedExecutionServiceServer) mustEmbedUnimplementedExecutionServiceServer() {}
// UnsafeExecutionServiceServer may be embedded to opt out of forward compatibility for this service.
@ -92,6 +107,24 @@ func _ExecutionService_DoBlock_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
func _ExecutionService_InitState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(InitStateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ExecutionServiceServer).InitState(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ExecutionService_InitState_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ExecutionServiceServer).InitState(ctx, req.(*InitStateRequest))
}
return interceptor(ctx, in, info, handler)
}
// ExecutionService_ServiceDesc is the grpc.ServiceDesc for ExecutionService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@ -103,6 +136,10 @@ var ExecutionService_ServiceDesc = grpc.ServiceDesc{
MethodName: "DoBlock",
Handler: _ExecutionService_DoBlock_Handler,
},
{
MethodName: "InitState",
Handler: _ExecutionService_InitState_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "proto/execution/v1/execution.proto",

View file

@ -877,6 +877,88 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*
return receipt.Logs, nil
}
// This is a copy of commitTransactions, but updated to take a list of txs instead of using heap
func (w *worker) commitAstriaTransactions(env *environment, txs *types.Transactions, interrupt *int32) error {
gasLimit := env.header.GasLimit
if env.gasPool == nil {
env.gasPool = new(core.GasPool).AddGas(gasLimit)
}
var coalescedLogs []*types.Log
for _, tx := range *txs {
// Check interruption signal and abort building if it's fired.
if interrupt != nil {
if signal := atomic.LoadInt32(interrupt); signal != commitInterruptNone {
return signalToErr(signal)
}
}
// If we don't have enough gas for any further transactions then we're done.
if env.gasPool.Gas() < params.TxGas {
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
break
}
// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
from, _ := types.Sender(env.signer, tx)
// Check whether the tx is replay protected. If we're not in the EIP155 hf
// phase, start ignoring the sender until we do.
if tx.Protected() && !w.chainConfig.IsEIP155(env.header.Number) {
log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.chainConfig.EIP155Block)
continue
}
// Start executing the transaction
env.state.SetTxContext(tx.Hash(), env.tcount)
logs, err := w.commitTransaction(env, tx)
switch {
case errors.Is(err, core.ErrGasLimitReached):
// Pop the current out-of-gas transaction without shifting in the next from the account
log.Trace("Gas limit exceeded for current block", "sender", from)
case errors.Is(err, core.ErrNonceTooLow):
// New head notification data race between the transaction pool and miner, shift
log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce())
case errors.Is(err, core.ErrNonceTooHigh):
// Reorg notification data race between the transaction pool and miner, skip account =
log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce())
case errors.Is(err, nil):
// Everything ok, collect the logs and shift in the next transaction from the same account
coalescedLogs = append(coalescedLogs, logs...)
env.tcount++
case errors.Is(err, types.ErrTxTypeNotSupported):
// Pop the unsupported transaction without shifting in the next from the account
log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
default:
// Strange error, discard the transaction and get the next in line (note, the
// nonce-too-high clause will prevent us from executing in vain).
log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err)
}
}
if !w.isRunning() && len(coalescedLogs) > 0 {
// We don't push the pendingLogsEvent while we are sealing. The reason is that
// when we are sealing, the worker will regenerate a sealing block every 3 seconds.
// In order to avoid pushing the repeated pendingLog, we disable the pending log pushing.
// make a copy, the state caches the logs and these logs get "upgraded" from pending to mined
// logs by filling in the block hash when the block was mined by the local miner. This can
// cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed.
cpy := make([]*types.Log, len(coalescedLogs))
for i, l := range coalescedLogs {
cpy[i] = new(types.Log)
*cpy[i] = *l
}
w.pendingLogsFeed.Send(cpy)
}
return nil
}
func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32) error {
gasLimit := env.header.GasLimit
if env.gasPool == nil {
@ -1068,28 +1150,14 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
// into the given sealing block. The transaction selection and ordering strategy can
// be customized with the plugin in the future.
func (w *worker) fillTransactions(interrupt *int32, env *environment) error {
// Split the pending transactions into locals and remotes
// Fill the block with all available pending transactions.
pending := w.eth.TxPool().Pending(true)
localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending
for _, account := range w.eth.TxPool().Locals() {
if txs := remoteTxs[account]; len(txs) > 0 {
delete(remoteTxs, account)
localTxs[account] = txs
}
}
if len(localTxs) > 0 {
txs := types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee)
if err := w.commitTransactions(env, txs, interrupt); err != nil {
return err
}
}
if len(remoteTxs) > 0 {
txs := types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee)
if err := w.commitTransactions(env, txs, interrupt); err != nil {
// Use pre ordered array of txs
astriaTxs := w.eth.TxPool().AstriaOrdered()
if len(*astriaTxs) > 0 {
if err := w.commitAstriaTransactions(env, astriaTxs, interrupt); err != nil {
return err
}
}
w.eth.TxPool().ClearAstriaOrdered()
return nil
}

View file

@ -4,9 +4,7 @@ import (
"net"
"sync"
"github.com/ethereum/go-ethereum/grpc/execution"
executionv1 "github.com/ethereum/go-ethereum/grpc/gen/proto/execution/v1"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"google.golang.org/grpc"
)
@ -18,28 +16,24 @@ type GRPCServerHandler struct {
endpoint string
server *grpc.Server
executionServiceServer *execution.ExecutionServiceServer
executionServiceServer *executionv1.ExecutionServiceServer
}
// NewServer creates a new gRPC server.
// It registers the execution service server.
// It registers the gRPC server with the node so it can be stopped on shutdown.
func NewGRPCServerHandler(node *Node, backend ethapi.Backend, cfg *Config) error {
func NewGRPCServerHandler(node *Node, execService executionv1.ExecutionServiceServer, cfg *Config) error {
server := grpc.NewServer()
executionServiceServer := &execution.ExecutionServiceServer{
Backend: backend,
}
log.Info("gRPC server enabled", "endpoint", cfg.GRPCEndpoint())
serverHandler := &GRPCServerHandler{
endpoint: cfg.GRPCEndpoint(),
server: server,
executionServiceServer: executionServiceServer,
executionServiceServer: &execService,
}
executionv1.RegisterExecutionServiceServer(server, executionServiceServer)
executionv1.RegisterExecutionServiceServer(server, execService)
node.RegisterGRPCServer(serverHandler)
return nil

View file

@ -274,12 +274,14 @@ func (n *Node) openEndpoints() error {
// start RPC endpoints
err := n.startRPC()
if err != nil {
n.log.Error("failed to start RPC endpoints", "err", err)
n.stopRPC()
n.server.Stop()
}
// start GRPC endpoints
err = n.startGRPC()
if err != nil {
n.log.Error("failed to start gRPC endpoints", "err", err)
n.stopGRPC()
}
return err

View file

@ -1,12 +1,25 @@
# private network
### astria
1. Make a new account in Metamask (or whichever method you prefer). Copy paste the address into `genesis.json`'s `alloc` field. This account will be allocated 300 ETH at startup.
2. Replace the etherbase in the following with your account (it doesn't really matter though, since mining doesn't require signing). Then, run:
2. To build and initialize Geth:
```bash
make geth
./build/bin/geth --datadir ~/.astriageth/ init genesis.json
./build/bin/geth --datadir ~/.astriageth/ --http --http.port=8545 --ws --ws.port=8545 --networkid=1337 --http.corsdomain='*' --ws.origins='*' --mine --miner.threads 1 --miner.etherbase=0xDB8c0F738639Da247bC67251548a186b2107bf4d
```
To run without mining (ie. using the conductor):
```bash
./build/bin/geth --datadir ~/.astriageth/ --http --http.port=8545 --ws --ws.port=8545 --networkid=1337 --http.corsdomain='*' --ws.origins='*' --grpc --grpc.addr=localhost --grpc.port 50051
```
4. Open up Metamask and go to the Localhost 8545 network. You should see your account has 300 ETH. You can now transfer this to other accounts.
### ethash
To run with mining (which you don't want if running Astria):
1. Remove the `"terminalTotalDifficulty": 0,` line in `genesis.json`. Then run steps 1-2 as above.
2. Replace the etherbase in the following with your account (it doesn't really matter though, since mining doesn't require signing). Then,
```bash
./build/bin/geth --datadir ~/.astriageth/ --http --http.port=8545 --ws --ws.port=8545 --networkid=1337 --http.corsdomain='*' --ws.origins='*' --mine --miner.threads 1 --miner.etherbase=0x46B77EFDFB20979E1C29ec98DcE73e3eCbF64102 --grpc --grpc.addr=localhost --grpc.port 50051
```