Skip to content

Commit

Permalink
receipts processing (#769)
Browse files Browse the repository at this point in the history
* receipts processing

* restrict hacks to l1recovery only
  • Loading branch information
kstoykov authored Jul 11, 2024
1 parent ba8295f commit 3896a9b
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 71 deletions.
7 changes: 7 additions & 0 deletions chain/chain_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ type Config struct {
ForkID7EtrogBlock *big.Int `json:"forkID7EtrogBlock,omitempty"`
ForkID88ElderberryBlock *big.Int `json:"forkID88ElderberryBlock,omitempty"`
ForkID9Elderberry2Block *big.Int `json:"forkID9FeijoaBlock,omitempty"`
ForkID12BananaBlock *big.Int `json:"forkID12BananaBlock,omitempty"`

SupportGasless bool `json:"supportGasless,omitempty"`
}
Expand Down Expand Up @@ -140,6 +141,8 @@ func (c *Config) SetForkIdBlock(forkIdNumber constants.ForkId, blockNum uint64)
c.ForkID88ElderberryBlock = new(big.Int).SetUint64(blockNum)
case constants.ForkID9Elderberry2:
c.ForkID9Elderberry2Block = new(big.Int).SetUint64(blockNum)
case constants.ForkID12Banana:
c.ForkID12BananaBlock = new(big.Int).SetUint64(blockNum)
default:
return fmt.Errorf("unknown fork id number %d", forkIdNumber)
}
Expand Down Expand Up @@ -272,6 +275,10 @@ func (c *Config) IsForkId9Elderberry2(num uint64) bool {
return isForked(c.ForkID9Elderberry2Block, num)
}

func (c *Config) IsForkID12Banana(num uint64) bool {
return isForked(c.ForkID12BananaBlock, num)
}

// CheckCompatible checks whether scheduled fork transitions have been imported
// with a mismatching chain configuration.
func (c *Config) CheckCompatible(newcfg *Config, height uint64) *chain.ConfigCompatError {
Expand Down
89 changes: 50 additions & 39 deletions core/blockchain_zkevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,45 +116,8 @@ func ExecuteBlockEphemerallyZk(
vmConfig.Tracer = nil
}

//[hack]TODO: remove this after bug is fixed
localReceipt := receipt.Clone()
if !chainConfig.IsForkID8Elderberry(blockNum) && errors.Is(execResult.Err, vm.ErrUnsupportedPrecompile) {
localReceipt.Status = 1
}

// forkid8 the poststate is empty
// forkid8 also fixed the bugs with logs and cumulative gas used
if !chainConfig.IsForkID8Elderberry(blockNum) {
// the stateroot in the transactions that comes from the datastream
// is the one after smart contract writes so it can't be used
// but since pre forkid7 blocks have 1 tx only, we can use the block root
if chainConfig.IsForkID7Etrog(blockNum) {
// receipt root holds the intermediate stateroot after the tx
intermediateState, err := roHermezDb.GetIntermediateTxStateRoot(blockNum, tx.Hash())
if err != nil {
return nil, err
}
receipt.PostState = intermediateState.Bytes()
} else {
receipt.PostState = header.Root.Bytes()
}

//[hack] log0 pre forkid8 are not included in the rpc logs
// also pre forkid8 comulative gas used is same as gas used
var fixedLogs types.Logs
for _, l := range receipt.Logs {
if len(l.Topics) == 0 && len(l.Data) == 0 {
continue
}
fixedLogs = append(fixedLogs, l)
}
receipt.Logs = fixedLogs
receipt.CumulativeGasUsed = receipt.GasUsed
}

for _, l := range receipt.Logs {
l.ApplyPaddingToLogsData(chainConfig.IsForkID8Elderberry(blockNum), chainConfig.IsForkId9Elderberry2(blockNum))
}
localReceipt := CreateReceiptForBlockInfoTree(receipt, chainConfig, blockNum, execResult)
ProcessReceiptForBlockExecution(receipt, roHermezDb, chainConfig, blockNum, header, tx)

if err != nil {
if !vmConfig.StatelessExec {
Expand Down Expand Up @@ -363,3 +326,51 @@ func FinalizeBlockExecutionWithHistoryWrite(

return newBlock, newTxs, newReceipt, nil
}

func CreateReceiptForBlockInfoTree(receipt *types.Receipt, chainConfig *chain.Config, blockNum uint64, execResult *ExecutionResult) *types.Receipt {
// [hack]TODO: remove this after bug is fixed
localReceipt := receipt.Clone()
if !chainConfig.IsForkID8Elderberry(blockNum) && errors.Is(execResult.Err, vm.ErrUnsupportedPrecompile) {
localReceipt.Status = 1
}

return localReceipt
}

func ProcessReceiptForBlockExecution(receipt *types.Receipt, roHermezDb state.ReadOnlyHermezDb, chainConfig *chain.Config, blockNum uint64, header *types.Header, tx types.Transaction) error {
// forkid8 the poststate is empty
// forkid8 also fixed the bugs with logs and cumulative gas used
if !chainConfig.IsForkID8Elderberry(blockNum) {
// the stateroot in the transactions that comes from the datastream
// is the one after smart contract writes so it can't be used
// but since pre forkid7 blocks have 1 tx only, we can use the block root
if chainConfig.IsForkID7Etrog(blockNum) {
// receipt root holds the intermediate stateroot after the tx
intermediateState, err := roHermezDb.GetIntermediateTxStateRoot(blockNum, tx.Hash())
if err != nil {
return err
}
receipt.PostState = intermediateState.Bytes()
} else {
receipt.PostState = header.Root.Bytes()
}

//[hack] log0 pre forkid8 are not included in the rpc logs
// also pre forkid8 comulative gas used is same as gas used
var fixedLogs types.Logs
for _, l := range receipt.Logs {
if len(l.Topics) == 0 && len(l.Data) == 0 {
continue
}
fixedLogs = append(fixedLogs, l)
}
receipt.Logs = fixedLogs
receipt.CumulativeGasUsed = receipt.GasUsed
}

for _, l := range receipt.Logs {
l.ApplyPaddingToLogsData(chainConfig.IsForkID8Elderberry(blockNum), chainConfig.IsForkID12Banana(blockNum))
}

return nil
}
4 changes: 2 additions & 2 deletions core/types/log_zkevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ func (_this *Log) Clone() *Log {
}
}

func (_this *Log) ApplyPaddingToLogsData(isForkId8, isForkId9 bool) {
func (_this *Log) ApplyPaddingToLogsData(isForkId8, isForkId12 bool) {
d := _this.Data
mSize := len(d)

if isForkId8 || isForkId9 {
if isForkId8 && !isForkId12 {
d = applyHexPadBug(d, mSize)
} else {
// [zkEvm] fill 0 at the end
Expand Down
1 change: 1 addition & 0 deletions zk/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ const (
ForkID9Elderberry2 ForkId = 9
ForkID10 ForkId = 10
ForkID11 ForkId = 11
ForkID12Banana ForkId = 12
)
13 changes: 9 additions & 4 deletions zk/stages/stage_sequence_execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func SpawnSequencingStage(
getHashFn := core.GetHashFn(header, getHeader)
blockContext := core.NewEVMBlockContext(header, getHashFn, cfg.engine, &cfg.zk.AddressSequencer, parentBlock.ExcessDataGas())

if err = processInjectedInitialBatch(ctx, cfg, s, sdb, forkId, header, parentBlock, &blockContext); err != nil {
if err = processInjectedInitialBatch(ctx, cfg, s, sdb, forkId, header, parentBlock, &blockContext, l1Recovery); err != nil {
return err
}

Expand All @@ -118,6 +118,7 @@ func SpawnSequencingStage(

var addedTransactions []types.Transaction
var addedReceipts []*types.Receipt
var addedExecutionResults []*core.ExecutionResult
var clonedBatchCounters *vm.BatchCounterCollector

var decodedBlock zktx.DecodedBatchL2Data
Expand Down Expand Up @@ -284,6 +285,7 @@ func SpawnSequencingStage(
clonedBatchCounters = batchCounters.Clone()
addedTransactions = []types.Transaction{}
addedReceipts = []*types.Receipt{}
addedExecutionResults = []*core.ExecutionResult{}
effectiveGases = []uint8{}
header, parentBlock, err = prepareHeader(tx, blockNumber, deltaTimestamp, limboHeaderTimestamp, forkId, nextBatchData.Coinbase)
if err != nil {
Expand Down Expand Up @@ -401,6 +403,7 @@ func SpawnSequencingStage(
}

var receipt *types.Receipt
var execResult *core.ExecutionResult
for i, transaction := range blockTransactions {
var effectiveGas uint8

Expand All @@ -416,7 +419,7 @@ func SpawnSequencingStage(
}

if !batchDataOverflow {
receipt, overflow, err = attemptAddTransaction(cfg, sdb, ibs, batchCounters, &blockContext, header, transaction, effectiveGas, l1Recovery, forkId, l1InfoIndex)
receipt, execResult, overflow, err = attemptAddTransaction(cfg, sdb, ibs, batchCounters, &blockContext, header, transaction, effectiveGas, l1Recovery, forkId, l1InfoIndex)
if err != nil {
if limboRecovery {
panic("limbo transaction has already been executed once so they must not fail while re-executing")
Expand Down Expand Up @@ -478,6 +481,7 @@ func SpawnSequencingStage(

addedTransactions = append(addedTransactions, transaction)
addedReceipts = append(addedReceipts, receipt)
addedExecutionResults = append(addedExecutionResults, execResult)
effectiveGases = append(effectiveGases, effectiveGas)

hasAnyTransactionsInThisBatch = true
Expand Down Expand Up @@ -507,7 +511,7 @@ func SpawnSequencingStage(
} else {
for idx, transaction := range addedTransactions {
effectiveGas := effectiveGases[idx]
receipt, innerOverflow, err := attemptAddTransaction(cfg, sdb, ibs, batchCounters, &blockContext, header, transaction, effectiveGas, false, forkId, l1InfoIndex)
receipt, execResult, innerOverflow, err := attemptAddTransaction(cfg, sdb, ibs, batchCounters, &blockContext, header, transaction, effectiveGas, false, forkId, l1InfoIndex)
if err != nil {
return err
}
Expand All @@ -516,6 +520,7 @@ func SpawnSequencingStage(
panic(fmt.Sprintf("overflowed twice during execution while adding tx with index %d", idx))
}
addedReceipts[idx] = receipt
addedExecutionResults[idx] = execResult
}
runLoopBlocks = false // close the batch because there are no counters left
}
Expand All @@ -524,7 +529,7 @@ func SpawnSequencingStage(
return err
}

block, err = doFinishBlockAndUpdateState(ctx, cfg, s, sdb, ibs, header, parentBlock, forkId, thisBatch, ger, l1BlockHash, addedTransactions, addedReceipts, effectiveGases, infoTreeIndexProgress)
block, err = doFinishBlockAndUpdateState(ctx, cfg, s, sdb, ibs, header, parentBlock, forkId, thisBatch, ger, l1BlockHash, addedTransactions, addedReceipts, addedExecutionResults, effectiveGases, infoTreeIndexProgress, l1Recovery)
if err != nil {
return err
}
Expand Down
14 changes: 12 additions & 2 deletions zk/stages/stage_sequence_execute_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import (
"github.com/ledgerwatch/erigon/zk/erigon_db"
"github.com/ledgerwatch/erigon/zk/hermez_db"
zktypes "github.com/ledgerwatch/erigon/zk/types"
"github.com/ledgerwatch/secp256k1"
"github.com/ledgerwatch/erigon/zk/utils"
"github.com/ledgerwatch/secp256k1"
)

func handleStateForNewBlockStarting(
Expand Down Expand Up @@ -81,7 +81,9 @@ func finaliseBlock(
l1BlockHash common.Hash,
transactions []types.Transaction,
receipts types.Receipts,
execResults []*core.ExecutionResult,
effectiveGases []uint8,
l1Recovery bool,
) (*types.Block, error) {
stateWriter := state.NewPlainStateWriter(sdb.tx, sdb.tx, newHeader.Number.Uint64()).SetAccumulator(accumulator)
chainReader := stagedsync.ChainReader{
Expand All @@ -108,17 +110,25 @@ func finaliseBlock(
return nil, err
}
}
localReceipt := core.CreateReceiptForBlockInfoTree(receipts[i], cfg.chainConfig, newHeader.Number.Uint64(), execResults[i])
txInfos = append(txInfos, blockinfo.ExecutedTxInfo{
Tx: tx,
EffectiveGasPrice: effectiveGases[i],
Receipt: receipts[i],
Receipt: localReceipt,
Signer: &from,
})
}

if err := postBlockStateHandling(cfg, ibs, sdb.hermezDb, newHeader, ger, l1BlockHash, parentBlock.Root(), txInfos); err != nil {
return nil, err
}

if l1Recovery {
for i, receipt := range receipts {
core.ProcessReceiptForBlockExecution(receipt, sdb.hermezDb.HermezDbReader, cfg.chainConfig, newHeader.Number.Uint64(), newHeader, transactions[i])
}
}

finalBlock, finalTransactions, finalReceipts, err := core.FinalizeBlockExecutionWithHistoryWrite(
cfg.engine,
sdb.stateReader,
Expand Down
21 changes: 12 additions & 9 deletions zk/stages/stage_sequence_execute_injected_batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"errors"

"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
Expand All @@ -29,6 +30,7 @@ func processInjectedInitialBatch(
header *types.Header,
parentBlock *types.Block,
blockContext *evmtypes.BlockContext,
l1Recovery bool,
) error {
injected, err := sdb.hermezDb.GetL1InjectedBatch(0)
if err != nil {
Expand Down Expand Up @@ -61,16 +63,17 @@ func processInjectedInitialBatch(
return err
}

txn, receipt, effectiveGas, err := handleInjectedBatch(cfg, sdb, ibs, blockContext, injected, header, parentBlock, forkId)
txn, receipt, execResult, effectiveGas, err := handleInjectedBatch(cfg, sdb, ibs, blockContext, injected, header, parentBlock, forkId)
if err != nil {
return err
}

txns := types.Transactions{*txn}
receipts := types.Receipts{receipt}
execResults := []*core.ExecutionResult{execResult}
effectiveGases := []uint8{effectiveGas}

_, err = doFinishBlockAndUpdateState(ctx, cfg, s, sdb, ibs, header, parentBlock, forkId, injectedBatchNumber, injected.LastGlobalExitRoot, injected.L1ParentHash, txns, receipts, effectiveGases, 0)
_, err = doFinishBlockAndUpdateState(ctx, cfg, s, sdb, ibs, header, parentBlock, forkId, injectedBatchNumber, injected.LastGlobalExitRoot, injected.L1ParentHash, txns, receipts, execResults, effectiveGases, 0, l1Recovery)
return err
}

Expand All @@ -83,26 +86,26 @@ func handleInjectedBatch(
header *types.Header,
parentBlock *types.Block,
forkId uint64,
) (*types.Transaction, *types.Receipt, uint8, error) {
) (*types.Transaction, *types.Receipt, *core.ExecutionResult, uint8, error) {
decodedBlocks, err := zktx.DecodeBatchL2Blocks(injected.Transaction, forkId)
if err != nil {
return nil, nil, 0, err
return nil, nil, nil, 0, err
}
if len(decodedBlocks) == 0 || len(decodedBlocks) > 1 {
return nil, nil, 0, errors.New("expected 1 block for the injected batch")
return nil, nil, nil, 0, errors.New("expected 1 block for the injected batch")
}
if len(decodedBlocks[0].Transactions) == 0 {
return nil, nil, 0, errors.New("expected 1 transaction in the injected batch")
return nil, nil, nil, 0, errors.New("expected 1 transaction in the injected batch")
}

batchCounters := vm.NewBatchCounterCollector(sdb.smt.GetDepth(), uint16(forkId), cfg.zk.VirtualCountersSmtReduction, cfg.zk.ShouldCountersBeUnlimited(false), nil)

// process the tx and we can ignore the counters as an overflow at this stage means no network anyway
effectiveGas := DeriveEffectiveGasPrice(cfg, decodedBlocks[0].Transactions[0])
receipt, _, err := attemptAddTransaction(cfg, sdb, ibs, batchCounters, blockContext, header, decodedBlocks[0].Transactions[0], effectiveGas, false, forkId, 0 /* use 0 for l1InfoIndex in injected batch */)
receipt, execResult, _, err := attemptAddTransaction(cfg, sdb, ibs, batchCounters, blockContext, header, decodedBlocks[0].Transactions[0], effectiveGas, false, forkId, 0 /* use 0 for l1InfoIndex in injected batch */)
if err != nil {
return nil, nil, 0, err
return nil, nil, nil, 0, err
}

return &decodedBlocks[0].Transactions[0], receipt, effectiveGas, nil
return &decodedBlocks[0].Transactions[0], receipt, execResult, effectiveGas, nil
}
Loading

0 comments on commit 3896a9b

Please sign in to comment.