Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
tudor-malene committed Jun 24, 2024
1 parent 7e3b0ec commit 4de8aa6
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 97 deletions.
44 changes: 25 additions & 19 deletions go/enclave/components/batch_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"maps"
"math/big"
"sort"
"sync"
Expand Down Expand Up @@ -194,14 +195,14 @@ func (executor *batchExecutor) ComputeBatch(ctx context.Context, context *BatchE
syntheticTransactions := append(xchainTxs, freeTransactions...)

// fromTxIndex - Here we start from the 0 index. This will be the same for a validator.
successfulTxs, excludedTxs, txReceipts, err := executor.processTransactions(ctx, batch, 0, transactionsToProcess, stateDB, context.ChainConfig, false)
successfulTxs, excludedTxs, txReceipts, createdContracts, err := executor.processTransactions(ctx, batch, 0, transactionsToProcess, stateDB, context.ChainConfig, false)
if err != nil {
return nil, fmt.Errorf("could not process transactions. Cause: %w", err)
}

// fromTxIndex - Here we start from the len of the successful transactions; As long as we have the exact same successful transactions in a batch,
// we will start from the same place.
ccSuccessfulTxs, _, ccReceipts, err := executor.processTransactions(ctx, batch, len(successfulTxs), syntheticTransactions, stateDB, context.ChainConfig, true)
ccSuccessfulTxs, _, ccReceipts, createdContractsSyn, err := executor.processTransactions(ctx, batch, len(successfulTxs), syntheticTransactions, stateDB, context.ChainConfig, true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -244,10 +245,11 @@ func (executor *batchExecutor) ComputeBatch(ctx context.Context, context *BatchE
l.BlockHash = copyBatch.Hash()
}
}

maps.Copy(createdContracts, createdContractsSyn)
return &ComputedBatch{
Batch: &copyBatch,
Receipts: allReceipts,
Batch: &copyBatch,
Receipts: allReceipts,
CreatedContracts: createdContracts,
Commit: func(deleteEmptyObjects bool) (gethcommon.Hash, error) {
executor.stateDBMutex.Lock()
defer executor.stateDBMutex.Unlock()
Expand All @@ -262,7 +264,7 @@ func (executor *batchExecutor) ComputeBatch(ctx context.Context, context *BatchE
}, nil
}

func (executor *batchExecutor) ExecuteBatch(ctx context.Context, batch *core.Batch) (types.Receipts, error) {
func (executor *batchExecutor) ExecuteBatch(ctx context.Context, batch *core.Batch) (types.Receipts, map[gethcommon.Hash][]*gethcommon.Address, error) {
defer core.LogMethodDuration(executor.logger, measure.NewStopwatch(), "Executed batch", log.BatchHashKey, batch.Hash())

// Validators recompute the entire batch using the same batch context
Expand All @@ -281,20 +283,20 @@ func (executor *batchExecutor) ExecuteBatch(ctx context.Context, batch *core.Bat
BaseFee: batch.Header.BaseFee,
}, false) // this execution is not used when first producing a batch, we never want to fail for empty batches
if err != nil {
return nil, fmt.Errorf("failed computing batch %s. Cause: %w", batch.Hash(), err)
return nil, nil, fmt.Errorf("failed computing batch %s. Cause: %w", batch.Hash(), err)
}

if cb.Batch.Hash() != batch.Hash() {
// todo @stefan - generate a validator challenge here and return it
executor.logger.Error(fmt.Sprintf("Error validating batch. Calculated: %+v Incoming: %+v", cb.Batch.Header, batch.Header))
return nil, fmt.Errorf("batch is in invalid state. Incoming hash: %s Computed hash: %s", batch.Hash(), cb.Batch.Hash())
return nil, nil, fmt.Errorf("batch is in invalid state. Incoming hash: %s Computed hash: %s", batch.Hash(), cb.Batch.Hash())
}

if _, err := cb.Commit(true); err != nil {
return nil, fmt.Errorf("cannot commit stateDB for incoming valid batch %s. Cause: %w", batch.Hash(), err)
return nil, nil, fmt.Errorf("cannot commit stateDB for incoming valid batch %s. Cause: %w", batch.Hash(), err)
}

return cb.Receipts, nil
return cb.Receipts, cb.CreatedContracts, nil
}

func (executor *batchExecutor) CreateGenesisState(
Expand Down Expand Up @@ -434,11 +436,12 @@ func (executor *batchExecutor) processTransactions(
stateDB *state.StateDB,
cc *params.ChainConfig,
noBaseFee bool,
) ([]*common.L2Tx, []*common.L2Tx, []*types.Receipt, error) {
) ([]*common.L2Tx, []*common.L2Tx, []*types.Receipt, map[gethcommon.Hash][]*gethcommon.Address, error) {
var executedTransactions []*common.L2Tx
var excludedTransactions []*common.L2Tx
var txReceipts []*types.Receipt
txResults := evm.ExecuteTransactions(
createdContracts := make(map[gethcommon.Hash][]*gethcommon.Address)
txResults, err := evm.ExecuteTransactions(
ctx,
txs,
stateDB,
Expand All @@ -452,24 +455,27 @@ func (executor *batchExecutor) processTransactions(
executor.batchGasLimit,
executor.logger,
)
if err != nil {
return nil, nil, nil, nil, err
}
for _, tx := range txs {
result, f := txResults[tx.Tx.Hash()]
if !f {
return nil, nil, nil, fmt.Errorf("there should be an entry for each transaction")
return nil, nil, nil, nil, fmt.Errorf("there should be an entry for each transaction")
}
rec, foundReceipt := result.(*types.Receipt)
if foundReceipt {
if result.Receipt != nil {
executedTransactions = append(executedTransactions, tx.Tx)
txReceipts = append(txReceipts, rec)
txReceipts = append(txReceipts, result.Receipt)
createdContracts[tx.Tx.Hash()] = result.CreatedContracts
} else {
// Exclude all errors
// Exclude failed transactions
excludedTransactions = append(excludedTransactions, tx.Tx)
executor.logger.Debug("Excluding transaction from batch", log.TxKey, tx.Tx.Hash(), log.BatchHashKey, batch.Hash(), "cause", result)
executor.logger.Debug("Excluding transaction from batch", log.TxKey, tx.Tx.Hash(), log.BatchHashKey, batch.Hash(), "cause", result.Err)
}
}
sort.Sort(sortByTxIndex(txReceipts))

return executedTransactions, excludedTransactions, txReceipts, nil
return executedTransactions, excludedTransactions, txReceipts, createdContracts, nil
}

type sortByTxIndex []*types.Receipt
Expand Down
6 changes: 4 additions & 2 deletions go/enclave/components/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ type BatchExecutionContext struct {
type ComputedBatch struct {
Batch *core.Batch
Receipts types.Receipts
Commit func(bool) (gethcommon.Hash, error)
// while executing the batch, we collect the newly created contracts mapped by the transaction that created them
CreatedContracts map[gethcommon.Hash][]*gethcommon.Address
Commit func(bool) (gethcommon.Hash, error)
}

type BatchExecutor interface {
Expand All @@ -76,7 +78,7 @@ type BatchExecutor interface {
ComputeBatch(ctx context.Context, batchContext *BatchExecutionContext, failForEmptyBatch bool) (*ComputedBatch, error)

// ExecuteBatch - executes the transactions and xchain messages, returns the receipts, and updates the stateDB
ExecuteBatch(context.Context, *core.Batch) (types.Receipts, error)
ExecuteBatch(context.Context, *core.Batch) (types.Receipts, map[gethcommon.Hash][]*gethcommon.Address, error)

// CreateGenesisState - will create and commit the genesis state in the stateDB for the given block hash,
// and uint64 timestamp representing the time now. In this genesis state is where one can
Expand Down
4 changes: 2 additions & 2 deletions go/enclave/components/rollup_compression.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ func (rc *RollupCompression) executeAndSaveIncompleteBatches(ctx context.Context
if err != nil {
return err
}
err = rc.storage.StoreExecutedBatch(ctx, genBatch.Header, nil)
err = rc.storage.StoreExecutedBatch(ctx, genBatch.Header, nil, nil)
if err != nil {
return err
}
Expand Down Expand Up @@ -514,7 +514,7 @@ func (rc *RollupCompression) executeAndSaveIncompleteBatches(ctx context.Context
if err != nil {
return err
}
err = rc.storage.StoreExecutedBatch(ctx, computedBatch.Batch.Header, computedBatch.Receipts)
err = rc.storage.StoreExecutedBatch(ctx, computedBatch.Batch.Header, computedBatch.Receipts, computedBatch.CreatedContracts)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion go/enclave/enclave.go
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ func replayBatchesToValidState(ctx context.Context, storage storage.Storage, reg
}

// calculate the stateDB after this batch and store it in the cache
_, err := batchExecutor.ExecuteBatch(ctx, batch)
_, _, err := batchExecutor.ExecuteBatch(ctx, batch)
if err != nil {
return err
}
Expand Down
45 changes: 33 additions & 12 deletions go/enclave/evm/evm_facade.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ import (

var ErrGasNotEnoughForL1 = errors.New("gas limit too low to pay for execution and l1 fees")

type TxExecResult struct {
Receipt *types.Receipt
CreatedContracts []*gethcommon.Address
Err error
}

// ExecuteTransactions
// header - the header of the rollup where this transaction will be included
// fromTxIndex - for the receipts and events, the evm needs to know for each transaction the order in which it was executed in the block.
Expand All @@ -54,17 +60,17 @@ func ExecuteTransactions(
noBaseFee bool,
batchGasLimit uint64,
logger gethlog.Logger,
) map[common.TxHash]interface{} { // todo - return error
) (map[common.TxHash]*TxExecResult, error) {
chain, vmCfg := initParams(storage, gethEncodingService, config, noBaseFee, logger)
gp := gethcore.GasPool(batchGasLimit)
zero := uint64(0)
usedGas := &zero
result := map[common.TxHash]interface{}{}
result := map[common.TxHash]*TxExecResult{}

ethHeader, err := gethEncodingService.CreateEthHeaderForBatch(ctx, header)
if err != nil {
logger.Crit("Could not convert to eth header", log.ErrKey, err)
return nil
logger.Error("Could not convert to eth header", log.ErrKey, err)
return nil, err
}

hash := header.Hash()
Expand All @@ -77,7 +83,9 @@ func ExecuteTransactions(
// this should not open up any attack vectors on the randomness.
tCountRollback := 0
for i, t := range txs {
r, err := executeTransaction(
txResult := &TxExecResult{}
result[t.Tx.Hash()] = txResult
r, createdContracts, err := executeTransaction(
s,
chainConfig,
chain,
Expand All @@ -92,7 +100,7 @@ func ExecuteTransactions(
)
if err != nil {
tCountRollback++
result[t.Tx.Hash()] = err
txResult.Err = err
// only log tx execution errors if they are unexpected
logFailedTx := logger.Info
if errors.Is(err, gethcore.ErrNonceTooHigh) || errors.Is(err, gethcore.ErrNonceTooLow) || errors.Is(err, gethcore.ErrFeeCapTooLow) || errors.Is(err, ErrGasNotEnoughForL1) {
Expand All @@ -101,11 +109,13 @@ func ExecuteTransactions(
logFailedTx("Failed to execute tx:", log.TxKey, t.Tx.Hash(), log.CtrErrKey, err)
continue
}
result[t.Tx.Hash()] = r

logReceipt(r, logger)
txResult.Receipt = r
txResult.CreatedContracts = createdContracts
}
s.Finalise(true)
return result
return result, nil
}

const (
Expand All @@ -127,16 +137,27 @@ func executeTransaction(
tCount int,
batchHash common.L2BatchHash,
batchHeight uint64,
) (*types.Receipt, error) {
) (*types.Receipt, []*gethcommon.Address, error) {
var createdContracts []*gethcommon.Address
rules := cc.Rules(big.NewInt(0), true, 0)
from, err := types.Sender(types.LatestSigner(cc), t.Tx)
if err != nil {
return nil, err
return nil, nil, err
}
s.Prepare(rules, from, gethcommon.Address{}, t.Tx.To(), nil, nil)
snap := s.Snapshot()
s.SetTxContext(t.Tx.Hash(), tCount)

s.SetLogger(&tracing.Hooks{
// called when the code of a contract changes.
OnCodeChange: func(addr gethcommon.Address, prevCodeHash gethcommon.Hash, prevCode []byte, codeHash gethcommon.Hash, code []byte) {
// only proceed for new deployments.
if len(prevCode) > 0 {
return
}
createdContracts = append(createdContracts, &addr)
},
})
before := header.MixDigest
// calculate a random value per transaction
header.MixDigest = crypto.CalculateTxRnd(before.Bytes(), tCount)
Expand Down Expand Up @@ -226,10 +247,10 @@ func executeTransaction(
header.MixDigest = before
if err != nil {
s.RevertToSnapshot(snap)
return receipt, err
return receipt, nil, err
}

return receipt, nil
return receipt, createdContracts, nil
}

func logReceipt(r *types.Receipt, logger gethlog.Logger) {
Expand Down
8 changes: 4 additions & 4 deletions go/enclave/nodetype/sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func (s *sequencer) createGenesisBatch(ctx context.Context, block *common.L1Bloc
return fmt.Errorf("failed signing created batch. Cause: %w", err)
}

if err := s.StoreExecutedBatch(ctx, batch, nil); err != nil {
if err := s.StoreExecutedBatch(ctx, batch, nil, nil); err != nil {
return fmt.Errorf("1. failed storing batch. Cause: %w", err)
}

Expand Down Expand Up @@ -301,7 +301,7 @@ func (s *sequencer) produceBatch(
return nil, fmt.Errorf("failed signing created batch. Cause: %w", err)
}

if err := s.StoreExecutedBatch(ctx, cb.Batch, cb.Receipts); err != nil {
if err := s.StoreExecutedBatch(ctx, cb.Batch, cb.Receipts, cb.CreatedContracts); err != nil {
return nil, fmt.Errorf("2. failed storing batch. Cause: %w", err)
}

Expand All @@ -319,7 +319,7 @@ func (s *sequencer) produceBatch(

// StoreExecutedBatch - stores an executed batch in one go. This can be done for the sequencer because it is guaranteed
// that all dependencies are in place for the execution to be successful.
func (s *sequencer) StoreExecutedBatch(ctx context.Context, batch *core.Batch, receipts types.Receipts) error {
func (s *sequencer) StoreExecutedBatch(ctx context.Context, batch *core.Batch, receipts types.Receipts, newContracts map[gethcommon.Hash][]*gethcommon.Address) error {
defer core.LogMethodDuration(s.logger, measure.NewStopwatch(), "Registry StoreBatch() exit", log.BatchHashKey, batch.Hash())

// Check if this batch is already stored.
Expand All @@ -337,7 +337,7 @@ func (s *sequencer) StoreExecutedBatch(ctx context.Context, batch *core.Batch, r
return fmt.Errorf("failed to store batch. Cause: %w", err)
}

if err := s.storage.StoreExecutedBatch(ctx, batch.Header, receipts); err != nil {
if err := s.storage.StoreExecutedBatch(ctx, batch.Header, receipts, newContracts); err != nil {
return fmt.Errorf("failed to store batch. Cause: %w", err)
}

Expand Down
6 changes: 3 additions & 3 deletions go/enclave/nodetype/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ func (val *obsValidator) ExecuteStoredBatches(ctx context.Context) error {
Transactions: txs,
}

receipts, err := val.batchExecutor.ExecuteBatch(ctx, batch)
receipts, contracts, err := val.batchExecutor.ExecuteBatch(ctx, batch)
if err != nil {
return fmt.Errorf("could not execute batchHeader %s. Cause: %w", batchHeader.Hash(), err)
}
err = val.storage.StoreExecutedBatch(ctx, batchHeader, receipts)
err = val.storage.StoreExecutedBatch(ctx, batchHeader, receipts, contracts)
if err != nil {
return fmt.Errorf("could not store executed batchHeader %s. Cause: %w", batchHeader.Hash(), err)
}
Expand Down Expand Up @@ -179,7 +179,7 @@ func (val *obsValidator) handleGenesis(ctx context.Context, batch *common.BatchH
return fmt.Errorf("received invalid genesis batch")
}

err = val.storage.StoreExecutedBatch(ctx, genBatch.Header, nil)
err = val.storage.StoreExecutedBatch(ctx, genBatch.Header, nil, nil)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion go/enclave/storage/enclavedb/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ func ReadEoa(ctx context.Context, dbTx *sql.Tx, addr gethcommon.Address) (uint64
return id, nil
}

func WriteContractAddress(ctx context.Context, dbTX *sql.Tx, contractAddress gethcommon.Address, ownerAddress uint64) (*uint64, error) {
func WriteContractAddress(ctx context.Context, dbTX *sql.Tx, contractAddress *gethcommon.Address, ownerAddress uint64) (*uint64, error) {
insert := "insert into contract (address, owner) values (?,?)"
res, err := dbTX.ExecContext(ctx, insert, contractAddress.Bytes(), ownerAddress)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions go/enclave/storage/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ type BatchResolver interface {
// StoreBatch stores an un-executed batch.
StoreBatch(ctx context.Context, batch *core.Batch, convertedHash gethcommon.Hash) error
// StoreExecutedBatch - store the batch after it was executed
StoreExecutedBatch(ctx context.Context, batch *common.BatchHeader, receipts []*types.Receipt) error
StoreExecutedBatch(ctx context.Context, batch *common.BatchHeader, receipts []*types.Receipt, contracts map[gethcommon.Hash][]*gethcommon.Address) error

// StoreRollup
StoreRollup(ctx context.Context, rollup *common.ExtRollup, header *common.CalldataRollupHeader) error
Expand Down Expand Up @@ -152,7 +152,6 @@ type Storage interface {

ReadEOA(ctx context.Context, addr gethcommon.Address) (*uint64, error)

SaveContract(ctx context.Context, contractAddr, sender gethcommon.Address) error
ReadContractAddress(ctx context.Context, addr gethcommon.Address) (*uint64, error)
ReadContractOwner(ctx context.Context, address gethcommon.Address) (*gethcommon.Address, error)
}
Expand Down
Loading

0 comments on commit 4de8aa6

Please sign in to comment.