go-ethereum/grpc/execution/server.go
jesse snyder 7eb4e3f589
Update Protos (#16)
* uses new protos

* remove old protos
2023-06-07 09:03:46 -06:00

135 lines
4.2 KiB
Go

// Package execution provides the gRPC server for the execution layer.
//
// Its procedures will be called from the conductor. It is responsible
// for immediately executing lists of ordered transactions that come from the shared sequencer.
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/astria/execution/v1"
"github.com/ethereum/go-ethereum/log"
)
// executionServiceServer is the implementation of the ExecutionServiceServer interface.
type ExecutionServiceServer struct {
// NOTE - from the generated code:
// All implementations must embed UnimplementedExecutionServiceServer
// for forward compatibility
executionv1.UnimplementedExecutionServiceServer
consensus *catalyst.ConsensusAPI
eth *eth.Ethereum
bc *core.BlockChain
}
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)
// The Engine API has been modified to use transactions from this mempool and abide by it's ordering.
s.eth.TxPool().SetAstriaOrdered(req.Transactions)
// 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
}
// 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)
}
// remove txs from original mempool
for _, tx := range block.Transactions() {
s.eth.TxPool().RemoveTx(tx.Hash())
}
finalizedBlock := s.bc.CurrentFinalBlock()
newForkChoice := &engine.ForkchoiceStateV1{
HeadBlockHash: block.Hash(),
SafeBlockHash: block.Hash(),
FinalizedBlockHash: finalizedBlock.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{
BlockHash: fcEndResp.PayloadStatus.LatestValidHash.Bytes(),
}
return res, nil
}
func (s *ExecutionServiceServer) FinalizeBlock(ctx context.Context, req *executionv1.FinalizeBlockRequest) (*executionv1.FinalizeBlockResponse, error) {
header := s.bc.GetHeaderByHash(common.BytesToHash(req.BlockHash))
if header == nil {
return nil, fmt.Errorf("failed to get header for block hash 0x%x", req.BlockHash)
}
s.bc.SetFinalized(header)
return &executionv1.FinalizeBlockResponse{}, nil
}
func (s *ExecutionServiceServer) InitState(ctx context.Context, req *executionv1.InitStateRequest) (*executionv1.InitStateResponse, error) {
currHead := s.eth.BlockChain().CurrentHeader()
res := &executionv1.InitStateResponse{
BlockHash: currHead.Hash().Bytes(),
}
return res, nil
}