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

remove the body of the l1 blocks from the payload sent into the enclave. #2046

Merged
merged 3 commits into from
Sep 5, 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
9 changes: 8 additions & 1 deletion go/common/enclave.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/json"
"math/big"

"github.com/ethereum/go-ethereum/core/types"

"github.com/ten-protocol/go-ten/go/common/errutil"

"github.com/ten-protocol/go-ten/go/common/tracers"
Expand All @@ -24,6 +26,11 @@ type Status struct {
L2Head *big.Int
}

type TxAndReceipt struct {
Tx *types.Transaction
Receipt *types.Receipt
}

const (
Running StatusCode = iota // the enclave is running, accepting L1 blocks
AwaitingSecret // the enclave has not received the network secret and cannot process L1 blocks
Expand Down Expand Up @@ -55,7 +62,7 @@ type Enclave interface {
// It is the responsibility of the host to gossip the returned rollup
// For good functioning the caller should always submit blocks ordered by height
// submitting a block before receiving ancestors of it, will result in it being ignored
SubmitL1Block(ctx context.Context, block *L1Block, receipts L1Receipts, isLatest bool) (*BlockSubmissionResponse, SystemError)
SubmitL1Block(ctx context.Context, blockHeader *types.Header, receipts []*TxAndReceipt, isLatest bool) (*BlockSubmissionResponse, SystemError)

// SubmitTx - user transactions
SubmitTx(ctx context.Context, tx EncryptedTx) (*responses.RawTx, SystemError)
Expand Down
26 changes: 13 additions & 13 deletions go/common/gethutil/gethutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var EmptyHash = gethcommon.Hash{}

// LCA - returns the latest common ancestor of the 2 blocks or an error if no common ancestor is found
// it also returns the blocks that became canonical, and the once that are now the fork
func LCA(ctx context.Context, newCanonical *types.Block, oldCanonical *types.Block, resolver storage.BlockResolver) (*common.ChainFork, error) {
func LCA(ctx context.Context, newCanonical *types.Header, oldCanonical *types.Header, resolver storage.BlockResolver) (*common.ChainFork, error) {
b, cp, ncp, err := internalLCA(ctx, newCanonical, oldCanonical, resolver, []common.L1BlockHash{}, []common.L1BlockHash{})
return &common.ChainFork{
NewCanonical: newCanonical,
Expand All @@ -29,37 +29,37 @@ func LCA(ctx context.Context, newCanonical *types.Block, oldCanonical *types.Blo
}, err
}

func internalLCA(ctx context.Context, newCanonical *types.Block, oldCanonical *types.Block, resolver storage.BlockResolver, canonicalPath []common.L1BlockHash, nonCanonicalPath []common.L1BlockHash) (*types.Block, []common.L1BlockHash, []common.L1BlockHash, error) {
if newCanonical.NumberU64() == common.L1GenesisHeight || oldCanonical.NumberU64() == common.L1GenesisHeight {
func internalLCA(ctx context.Context, newCanonical *types.Header, oldCanonical *types.Header, resolver storage.BlockResolver, canonicalPath []common.L1BlockHash, nonCanonicalPath []common.L1BlockHash) (*types.Header, []common.L1BlockHash, []common.L1BlockHash, error) {
if newCanonical.Number.Uint64() == common.L1GenesisHeight || oldCanonical.Number.Uint64() == common.L1GenesisHeight {
return newCanonical, canonicalPath, nonCanonicalPath, nil
}
if newCanonical.Hash() == oldCanonical.Hash() {
// this is where we reach the common ancestor, which we add to the canonical path
return newCanonical, append(canonicalPath, newCanonical.Hash()), nonCanonicalPath, nil
}
if newCanonical.NumberU64() > oldCanonical.NumberU64() {
p, err := resolver.FetchBlock(ctx, newCanonical.ParentHash())
if newCanonical.Number.Uint64() > oldCanonical.Number.Uint64() {
p, err := resolver.FetchBlock(ctx, newCanonical.ParentHash)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", newCanonical.ParentHash(), err)
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", newCanonical.ParentHash, err)
}

return internalLCA(ctx, p, oldCanonical, resolver, append(canonicalPath, newCanonical.Hash()), nonCanonicalPath)
}
if oldCanonical.NumberU64() > newCanonical.NumberU64() {
p, err := resolver.FetchBlock(ctx, oldCanonical.ParentHash())
if oldCanonical.Number.Uint64() > newCanonical.Number.Uint64() {
p, err := resolver.FetchBlock(ctx, oldCanonical.ParentHash)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", oldCanonical.ParentHash(), err)
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", oldCanonical.ParentHash, err)
}

return internalLCA(ctx, newCanonical, p, resolver, canonicalPath, append(nonCanonicalPath, oldCanonical.Hash()))
}
parentBlockA, err := resolver.FetchBlock(ctx, newCanonical.ParentHash())
parentBlockA, err := resolver.FetchBlock(ctx, newCanonical.ParentHash)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", newCanonical.ParentHash(), err)
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", newCanonical.ParentHash, err)
}
parentBlockB, err := resolver.FetchBlock(ctx, oldCanonical.ParentHash())
parentBlockB, err := resolver.FetchBlock(ctx, oldCanonical.ParentHash)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", oldCanonical.ParentHash(), err)
return nil, nil, nil, fmt.Errorf("could not retrieve parent block %s. Cause: %w", oldCanonical.ParentHash, err)
}

return internalLCA(ctx, parentBlockA, parentBlockB, resolver, append(canonicalPath, newCanonical.Hash()), append(nonCanonicalPath, oldCanonical.Hash()))
Expand Down
51 changes: 21 additions & 30 deletions go/common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,61 +125,52 @@ type (
// To work properly, all of the receipts are required, due to rlp encoding pruning some of the information.
// The receipts must also be in the correct order.
type BlockAndReceipts struct {
Block *L1Block
ReceiptsMap map[int]*types.Receipt // sparse map with obscuro-relevant receipts in it
Receipts *types.Receipts
BlockHeader *types.Header
TxsWithReceipts []*TxAndReceipt
successfulTransactions *types.Transactions
}

// ParseBlockAndReceipts - will create a container struct that has preprocessed the receipts
// and verified if they indeed match the receipt root hash in the block.
func ParseBlockAndReceipts(block *L1Block, receipts *L1Receipts) (*BlockAndReceipts, error) {
if len(block.Transactions()) != len(*receipts) {
// the receipts list is currently a *sparse* list of relevant receipts, it needs to have the same length as the
// transactions list even though some of the entries may be nil
return nil, fmt.Errorf("transactions and receipts are not the same length")
}

func ParseBlockAndReceipts(block *types.Header, receipts []*TxAndReceipt) (*BlockAndReceipts, error) {
br := BlockAndReceipts{
Block: block,
Receipts: receipts,
ReceiptsMap: make(map[int]*types.Receipt, len(block.Transactions())),
successfulTransactions: nil,
}

for idx, receipt := range *receipts {
br.ReceiptsMap[idx] = receipt
BlockHeader: block,
TxsWithReceipts: receipts,
}

return &br, nil
}

// SuccessfulTransactions - returns slice containing only the transactions that have receipts with successful status.
func (br *BlockAndReceipts) SuccessfulTransactions() *types.Transactions {
func (br *BlockAndReceipts) Receipts() L1Receipts {
rec := make(L1Receipts, 0)
for _, txsWithReceipt := range br.TxsWithReceipts {
rec = append(rec, txsWithReceipt.Receipt)
}
return rec
}

// RelevantTransactions - returns slice containing only the transactions that have receipts with successful status.
func (br *BlockAndReceipts) RelevantTransactions() *types.Transactions {
if br.successfulTransactions != nil {
return br.successfulTransactions
}

txs := br.Block.Transactions()
st := make(types.Transactions, 0)

for idx, tx := range txs {
receipt, ok := br.ReceiptsMap[idx]
if ok && receipt.Status == types.ReceiptStatusSuccessful {
st = append(st, tx)
for _, tx := range br.TxsWithReceipts {
if tx.Receipt.Status == types.ReceiptStatusSuccessful {
st = append(st, tx.Tx)
}
}

br.successfulTransactions = &st
return br.successfulTransactions
}

// ChainFork - represents the result of walking the chain when processing a fork
type ChainFork struct {
NewCanonical *types.Block
OldCanonical *types.Block
NewCanonical *types.Header
OldCanonical *types.Header

CommonAncestor *types.Block
CommonAncestor *types.Header
CanonicalPath []L1BlockHash
NonCanonicalPath []L1BlockHash
}
Expand Down
4 changes: 2 additions & 2 deletions go/enclave/components/batch_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ func (executor *batchExecutor) CreateGenesisState(
return genesisBatch, deployTx, nil
}

func (executor *batchExecutor) populateOutboundCrossChainData(ctx context.Context, batch *core.Batch, block *types.Block, receipts types.Receipts) error {
func (executor *batchExecutor) populateOutboundCrossChainData(ctx context.Context, batch *core.Batch, block *types.Header, receipts types.Receipts) error {
crossChainMessages, err := executor.crossChainProcessors.Local.ExtractOutboundMessages(ctx, receipts)
if err != nil {
executor.logger.Error("Failed extracting L2->L1 messages", log.ErrKey, err, log.CmpKey, log.CrossChainCmp)
Expand Down Expand Up @@ -395,7 +395,7 @@ func (executor *batchExecutor) populateOutboundCrossChainData(ctx context.Contex
len(batch.Header.CrossChainMessages)), log.CmpKey, log.CrossChainCmp)

batch.Header.LatestInboundCrossChainHash = block.Hash()
batch.Header.LatestInboundCrossChainHeight = block.Number()
batch.Header.LatestInboundCrossChainHeight = block.Number

return nil
}
Expand Down
8 changes: 4 additions & 4 deletions go/enclave/components/batch_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (br *batchRegistry) HasGenesisBatch() (bool, error) {
return br.HeadBatchSeq() != nil, nil
}

func (br *batchRegistry) BatchesAfter(ctx context.Context, batchSeqNo uint64, upToL1Height uint64, rollupLimiter limiters.RollupLimiter) ([]*core.Batch, []*types.Block, error) {
func (br *batchRegistry) BatchesAfter(ctx context.Context, batchSeqNo uint64, upToL1Height uint64, rollupLimiter limiters.RollupLimiter) ([]*core.Batch, []*types.Header, error) {
// sanity check
headBatch, err := br.storage.FetchBatchHeaderBySeqNo(ctx, br.HeadBatchSeq().Uint64())
if err != nil {
Expand All @@ -124,10 +124,10 @@ func (br *batchRegistry) BatchesAfter(ctx context.Context, batchSeqNo uint64, up
}

resultBatches := make([]*core.Batch, 0)
resultBlocks := make([]*types.Block, 0)
resultBlocks := make([]*types.Header, 0)

currentBatchSeq := batchSeqNo
var currentBlock *types.Block
var currentBlock *types.Header
for currentBatchSeq <= headBatch.SequencerOrderNo.Uint64() {
batch, err := br.storage.FetchBatchBySeqNo(ctx, currentBatchSeq)
if err != nil {
Expand All @@ -142,7 +142,7 @@ func (br *batchRegistry) BatchesAfter(ctx context.Context, batchSeqNo uint64, up
return nil, nil, fmt.Errorf("could not retrieve block. Cause: %w", err)
}
currentBlock = block
if block.NumberU64() > upToL1Height {
if block.Number.Uint64() > upToL1Height {
break
}
resultBlocks = append(resultBlocks, block)
Expand Down
28 changes: 15 additions & 13 deletions go/enclave/components/block_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"time"

"github.com/ethereum/go-ethereum/core/types"

"github.com/ten-protocol/go-ten/go/common/async"
"github.com/ten-protocol/go-ten/go/enclave/core"
"github.com/ten-protocol/go-ten/go/enclave/gas"
Expand Down Expand Up @@ -58,7 +60,7 @@ func NewBlockProcessor(storage storage.Storage, cc *crosschain.Processors, gasOr
}

func (bp *l1BlockProcessor) Process(ctx context.Context, br *common.BlockAndReceipts) (*BlockIngestionType, error) {
defer core.LogMethodDuration(bp.logger, measure.NewStopwatch(), "L1 block processed", log.BlockHashKey, br.Block.Hash())
defer core.LogMethodDuration(bp.logger, measure.NewStopwatch(), "L1 block processed", log.BlockHashKey, br.BlockHeader.Hash())

ingestion, err := bp.tryAndInsertBlock(ctx, br)
if err != nil {
Expand All @@ -67,21 +69,21 @@ func (bp *l1BlockProcessor) Process(ctx context.Context, br *common.BlockAndRece

if !ingestion.PreGenesis {
// This requires block to be stored first ... but can permanently fail a block
err = bp.crossChainProcessors.Remote.StoreCrossChainMessages(ctx, br.Block, *br.Receipts)
err = bp.crossChainProcessors.Remote.StoreCrossChainMessages(ctx, br.BlockHeader, br.Receipts())
if err != nil {
return nil, errors.New("failed to process cross chain messages")
}

err = bp.crossChainProcessors.Remote.StoreCrossChainValueTransfers(ctx, br.Block, *br.Receipts)
err = bp.crossChainProcessors.Remote.StoreCrossChainValueTransfers(ctx, br.BlockHeader, br.Receipts())
if err != nil {
return nil, fmt.Errorf("failed to process cross chain transfers. Cause: %w", err)
}
}

// todo @siliev - not sure if this is the best way to update the price, will pick up random stale blocks from forks?
bp.gasOracle.ProcessL1Block(br.Block)
bp.gasOracle.ProcessL1Block(br.BlockHeader)

h := br.Block.Hash()
h := br.BlockHeader.Hash()
bp.currentL1Head = &h
bp.lastIngestedBlock.Mark()
return ingestion, nil
Expand All @@ -98,7 +100,7 @@ func (bp *l1BlockProcessor) HealthCheck() (bool, error) {
}

func (bp *l1BlockProcessor) tryAndInsertBlock(ctx context.Context, br *common.BlockAndReceipts) (*BlockIngestionType, error) {
block := br.Block
block := br.BlockHeader

// We insert the block into the L1 chain and store it.
// in case the block already exists in the database, this will be treated like a fork, because the head changes to
Expand All @@ -118,13 +120,13 @@ func (bp *l1BlockProcessor) tryAndInsertBlock(ctx context.Context, br *common.Bl
return nil, fmt.Errorf("1. could not store block. Cause: %w", err)
}

bp.logger.Trace("Block inserted successfully",
log.BlockHeightKey, block.NumberU64(), log.BlockHashKey, block.Hash(), "ingestionType", ingestionType)
bp.logger.Trace("BlockHeader inserted successfully",
log.BlockHeightKey, block.Number, log.BlockHashKey, block.Hash(), "ingestionType", ingestionType)

return ingestionType, nil
}

func (bp *l1BlockProcessor) ingestBlock(ctx context.Context, block *common.L1Block) (*BlockIngestionType, error) {
func (bp *l1BlockProcessor) ingestBlock(ctx context.Context, block *types.Header) (*BlockIngestionType, error) {
// todo (#1056) - this is minimal L1 tracking/validation, and should be removed when we are using geth's blockchain or lightchain structures for validation
prevL1Head, err := bp.GetHead(ctx)
if err != nil {
Expand All @@ -135,7 +137,7 @@ func (bp *l1BlockProcessor) ingestBlock(ctx context.Context, block *common.L1Blo
return nil, fmt.Errorf("could not retrieve head block. Cause: %w", err)
}
// we do a basic sanity check, comparing the received block to the head block on the chain
if block.ParentHash() != prevL1Head.Hash() {
if block.ParentHash != prevL1Head.Hash() {
isCanon, err := bp.storage.IsBlockCanonical(ctx, block.Hash())
if err != nil {
return nil, fmt.Errorf("could not check if block is canonical. Cause: %w", err)
Expand All @@ -147,8 +149,8 @@ func (bp *l1BlockProcessor) ingestBlock(ctx context.Context, block *common.L1Blo
chainFork, err := gethutil.LCA(ctx, block, prevL1Head, bp.storage)
if err != nil {
bp.logger.Trace("cannot calculate the fork for received block",
"blkHeight", block.NumberU64(), log.BlockHashKey, block.Hash(),
"l1HeadHeight", prevL1Head.NumberU64(), "l1HeadHash", prevL1Head.Hash(),
"blkHeight", block.Number.Uint64(), log.BlockHashKey, block.Hash(),
"l1HeadHeight", prevL1Head.Number.Uint64(), "l1HeadHash", prevL1Head.Hash(),
log.ErrKey, err,
)
return nil, errutil.ErrBlockAncestorNotFound
Expand All @@ -163,7 +165,7 @@ func (bp *l1BlockProcessor) ingestBlock(ctx context.Context, block *common.L1Blo
return &BlockIngestionType{ChainFork: nil, PreGenesis: false}, nil
}

func (bp *l1BlockProcessor) GetHead(ctx context.Context) (*common.L1Block, error) {
func (bp *l1BlockProcessor) GetHead(ctx context.Context) (*types.Header, error) {
if bp.currentL1Head == nil {
return nil, errutil.ErrNotFound
}
Expand Down
3 changes: 1 addition & 2 deletions go/enclave/components/consumer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/trie"
)

func TestInvalidBlocksAreRejected(t *testing.T) {
Expand All @@ -25,7 +24,7 @@ func TestInvalidBlocksAreRejected(t *testing.T) {

for _, header := range invalidHeaders {
loopHeader := header
_, err := blockConsumer.ingestBlock(context.Background(), types.NewBlock(&loopHeader, nil, nil, &trie.StackTrie{}))
_, err := blockConsumer.ingestBlock(context.Background(), &loopHeader)
if err == nil {
t.Errorf("expected block with invalid header to be rejected but was accepted")
}
Expand Down
8 changes: 4 additions & 4 deletions go/enclave/components/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type BlockIngestionType struct {
// ChainFork contains information about the status of the new block in the chain
ChainFork *common.ChainFork

// Block that is already on the canonical chain
// BlockHeader that is already on the canonical chain
OldCanonicalBlock bool
}

Expand All @@ -39,14 +39,14 @@ func (bit *BlockIngestionType) IsFork() bool {

type L1BlockProcessor interface {
Process(ctx context.Context, br *common.BlockAndReceipts) (*BlockIngestionType, error)
GetHead(context.Context) (*common.L1Block, error)
GetHead(context.Context) (*types.Header, error)
GetCrossChainContractAddress() *gethcommon.Address
HealthCheck() (bool, error)
}

// BatchExecutionContext - Contains all of the data that each batch depends on
type BatchExecutionContext struct {
BlockPtr common.L1BlockHash // Block is needed for the cross chain messages
BlockPtr common.L1BlockHash // BlockHeader is needed for the cross chain messages
ParentPtr common.L2BatchHash
Transactions common.L2Transactions
AtTime uint64
Expand Down Expand Up @@ -88,7 +88,7 @@ type BatchExecutor interface {

type BatchRegistry interface {
// BatchesAfter - Given a hash, will return batches following it until the head batch and the l1 blocks referenced by those batches
BatchesAfter(ctx context.Context, batchSeqNo uint64, upToL1Height uint64, rollupLimiter limiters.RollupLimiter) ([]*core.Batch, []*types.Block, error)
BatchesAfter(ctx context.Context, batchSeqNo uint64, upToL1Height uint64, rollupLimiter limiters.RollupLimiter) ([]*core.Batch, []*types.Header, error)

// GetBatchStateAtHeight - creates a stateDB for the block number
GetBatchStateAtHeight(ctx context.Context, blockNumber *gethrpc.BlockNumber) (*state.StateDB, error)
Expand Down
Loading
Loading