Skip to content

Commit

Permalink
Blockinfotree fix (#114)
Browse files Browse the repository at this point in the history
* fixed blockinfotree uint convertions

* refactor code and sync fixes

* fix a uint64 parse

* fix debug limit

* removed hardcoded values
  • Loading branch information
V-Staykov authored Feb 8, 2024
1 parent 5822fdb commit 8ff1cb7
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 167 deletions.
4 changes: 2 additions & 2 deletions cmd/rpcdaemon/commands/zkevm_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ func (api *ZkEvmAPIImpl) getBlockRangeWitness(ctx context.Context, db kv.RoDB, s
return nil, err
}

err = batch.CreateBucket(hermez_db.GLOBAL_EXIT_ROOTS)
err = batch.CreateBucket(hermez_db.BLOCK_GLOBAL_EXIT_ROOTS)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -741,7 +741,7 @@ func getLatestSequencedBatchNo(tx kv.Tx) (uint64, error) {
}

func getGlobalExitRoot(tx kv.Tx, l2Block uint64) (common.Hash, error) {
d, err := tx.GetOne(hermez_db.GLOBAL_EXIT_ROOTS, hermez_db.Uint64ToBytes(l2Block))
d, err := tx.GetOne(hermez_db.BLOCK_GLOBAL_EXIT_ROOTS, hermez_db.Uint64ToBytes(l2Block))
if err != nil {
return common.Hash{}, err
}
Expand Down
130 changes: 51 additions & 79 deletions core/blockchain_zkevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"github.com/ledgerwatch/erigon/chain"

"github.com/ledgerwatch/erigon-lib/kv"
dstypes "github.com/ledgerwatch/erigon/zk/datastream/types"

"github.com/ledgerwatch/erigon/common/math"
"github.com/ledgerwatch/erigon/consensus"
Expand All @@ -36,15 +35,17 @@ import (
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/smt/pkg/blockinfo"
"github.com/ledgerwatch/erigon/zk/utils"
)

// ExecuteBlockEphemerally runs a block from provided stateReader and
// writes the result to the provided stateWriter
func ExecuteBlockEphemerallyZk(
chainConfig *chain.Config, vmConfig *vm.Config,
chainConfig *chain.Config,
vmConfig *vm.Config,
blockHashFunc func(n uint64) libcommon.Hash,
engine consensus.Engine, block *types.Block,
engine consensus.Engine,
prevBlockHash *libcommon.Hash,
block *types.Block,
stateReader state.StateReader,
stateWriter state.WriterWithChangeSets,
chainReader consensus.ChainHeaderReader,
Expand All @@ -57,10 +58,10 @@ func ExecuteBlockEphemerallyZk(
block.Uncles()
ibs := state.New(stateReader)
header := block.Header()

usedGas := new(uint64)
blockTransaction := block.Transactions()
blockGasLimit := block.GasLimit()
gp := new(GasPool)
gp.AddGas(block.GasLimit())
gp.AddGas(blockGasLimit)

var (
rejectedTxs []*RejectedTx
Expand All @@ -78,7 +79,7 @@ func ExecuteBlockEphemerallyZk(
}

if !vmConfig.ReadOnly {
if err := InitializeBlockExecution(engine, chainReader, block.Header(), block.Transactions(), block.Uncles(), chainConfig, ibs, excessDataGas); err != nil {
if err := InitializeBlockExecution(engine, chainReader, header, blockTransaction, block.Uncles(), chainConfig, ibs, excessDataGas); err != nil {
return nil, err
}
}
Expand All @@ -87,17 +88,8 @@ func ExecuteBlockEphemerallyZk(
misc.ApplyDAOHardFork(ibs)
}

// the state root of the previous block is written into state
// this should be fine since we get block 0 from the datastream
stateRoot, err := roHermezDb.GetStateRoot(block.NumberU64() - 1)
if err != nil {
return nil, err
}

blockNum := block.NumberU64()

gers := []*dstypes.GerUpdate{}

//[zkevm] - get the last batch number so we can check for empty batches in between it and the new one
lastBatchInserted, err := roHermezDb.GetBatchNoByL2Block(blockNum - 1)
if err != nil {
Expand All @@ -117,60 +109,35 @@ func ExecuteBlockEphemerallyZk(
return nil, err
}

if gersInBetween != nil {
gers = append(gers, gersInBetween...)
}

blockGer, l1BlockHash, err := roHermezDb.GetBlockGlobalExitRoot(blockNum)
if err != nil {
return nil, err
}

blockGerUpdate := dstypes.GerUpdate{
GlobalExitRoot: blockGer,
Timestamp: header.Time,
}
gers = append(gers, &blockGerUpdate)

var emptyHash = libcommon.Hash{0}

for _, ger := range gers {
if ger.GlobalExitRoot == emptyHash {
// etrog - if l1blockhash is set, this is an etrog GER
if err := utils.WriteGlobalExitRootEtrog(stateWriter, ger.GlobalExitRoot); err != nil {
return nil, err
}
} else {
// [zkevm] - add GER if there is one for this batch
if err := utils.WriteGlobalExitRoot(stateReader, stateWriter, ger.GlobalExitRoot, ger.Timestamp); err != nil {
return nil, err
}
}
}

// [zkevm] - finished writing global exit root to state

ibs.PreExecuteStateSet(chainConfig, block.NumberU64(), block.Time(), &stateRoot)
blockTime := block.Time()
ibs.SyncerPreExecuteStateSet(chainConfig, blockNum, blockTime, prevBlockHash, &blockGer, &l1BlockHash, &gersInBetween)

blockInfoTree := blockinfo.NewBlockInfoTree()
parentHash := block.ParentHash()
coinbase := block.Coinbase()
if err := blockInfoTree.InitBlockHeader(
&parentHash,
&coinbase,
blockNum,
block.GasLimit(),
block.Time(),
&blockGer,
&l1BlockHash,
); err != nil {
return nil, err
if chainConfig.IsForkID7Etrog(blockNum) {
coinbase := block.Coinbase()

if err := blockInfoTree.InitBlockHeader(
prevBlockHash,
&coinbase,
blockNum,
blockGasLimit,
blockTime,
&blockGer,
&l1BlockHash,
); err != nil {
return nil, err
}
}

noop := state.NewNoopWriter()
cumulativeGasUsed := uint64(0)
logIndex := int64(0)
for txIndex, tx := range block.Transactions() {
usedGas := new(uint64)

for txIndex, tx := range blockTransaction {
ibs.Prepare(tx.Hash(), block.Hash(), txIndex)
writeTrace := false
if vmConfig.Debug && vmConfig.Tracer == nil {
Expand All @@ -182,7 +149,7 @@ func ExecuteBlockEphemerallyZk(
writeTrace = true
}

gp.Reset(block.GasLimit())
gp.Reset(blockGasLimit)

effectiveGasPricePercentage, err := roHermezDb.GetEffectiveGasPricePercentage(tx.Hash())
if err != nil {
Expand Down Expand Up @@ -213,30 +180,35 @@ func ExecuteBlockEphemerallyZk(
ibs.ScalableSetSmtRootHash(roHermezDb)
}

//block info tree
cumulativeGasUsed += receipt.GasUsed
_, err = blockInfoTree.SetBlockTx(
txIndex,
receipt,
logIndex,
cumulativeGasUsed,
effectiveGasPricePercentage,
)
if err != nil {
return nil, err
if chainConfig.IsForkID7Etrog(blockNum) {
//block info tree
_, err = blockInfoTree.SetBlockTx(
txIndex,
receipt,
logIndex,
*usedGas,
effectiveGasPricePercentage,
)
if err != nil {
return nil, err
}
}

// increment logIndex for next turn
// log idex counts all the logs in all txs in the block
logIndex += int64(len(receipt.Logs))
}

// [zkevm] - set the block info tree root
root, err := blockInfoTree.SetBlockGasUsed(cumulativeGasUsed)
if err != nil {
return nil, err
var l1InfoRoot libcommon.Hash
if chainConfig.IsForkID7Etrog(blockNum) {
// [zkevm] - set the block info tree root
root, err := blockInfoTree.SetBlockGasUsed(*usedGas)
if err != nil {
return nil, err
}
l1InfoRoot = libcommon.BigToHash(root)
}
l1InfoRoot := libcommon.BigToHash(root)

ibs.PostExecuteStateSet(chainConfig, block.NumberU64(), &l1InfoRoot)

receiptSha := types.DeriveSha(receipts)
Expand All @@ -259,7 +231,7 @@ func ExecuteBlockEphemerallyZk(
//}
}
if !vmConfig.ReadOnly {
txs := block.Transactions()
txs := blockTransaction
if _, _, _, err := FinalizeBlockExecution(engine, stateReader, block.Header(), txs, block.Uncles(), stateWriter, chainConfig, ibs, receipts, block.Withdrawals(), chainReader, false, excessDataGas); err != nil {
return nil, err
}
Expand Down
69 changes: 61 additions & 8 deletions core/state/intra_block_state_zkevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import (
)

var (
LAST_BLOCK_STORAGE_POS = libcommon.HexToHash("0x0")
STATE_ROOT_STORAGE_POS = libcommon.HexToHash("0x1")
TIMESTAMP_STORAGE_POS = libcommon.HexToHash("0x2")
BLOCK_INFO_ROOT_STORAGE_POS = libcommon.HexToHash("0x3")
ADDRESS_SCALABLE_L2 = libcommon.HexToAddress("0x000000000000000000000000000000005ca1ab1e")
GER_MANAGER_ADDRESS = libcommon.HexToAddress("0xa40D5f56745a118D0906a34E69aeC8C0Db1cB8fA")
LAST_BLOCK_STORAGE_POS = libcommon.HexToHash("0x0")
STATE_ROOT_STORAGE_POS = libcommon.HexToHash("0x1")
TIMESTAMP_STORAGE_POS = libcommon.HexToHash("0x2")
BLOCK_INFO_ROOT_STORAGE_POS = libcommon.HexToHash("0x3")
ADDRESS_SCALABLE_L2 = libcommon.HexToAddress("0x000000000000000000000000000000005ca1ab1e")
GER_MANAGER_ADDRESS = libcommon.HexToAddress("0xa40D5f56745a118D0906a34E69aeC8C0Db1cB8fA")
GLOBAL_EXIT_ROOT_STORAGE_POS = libcommon.HexToHash("0x0")
)

type ReadOnlyHermezDb interface {
Expand Down Expand Up @@ -64,6 +65,49 @@ func (sdb *IntraBlockState) PreExecuteStateSet(chainConfig *chain.Config, blockN
}
}

func (sdb *IntraBlockState) SyncerPreExecuteStateSet(chainConfig *chain.Config, blockNumber uint64, blockTimestamp uint64, stateRoot, blockGer, l1BlockHash *libcommon.Hash, gerUpdates *[]*dstypes.GerUpdate) {
if !sdb.Exist(ADDRESS_SCALABLE_L2) {
// create account if not exists
sdb.CreateAccount(ADDRESS_SCALABLE_L2, true)
}

//save block number
sdb.scalableSetBlockNum(blockNumber)
emptyHash := libcommon.Hash{}

//ETROG
if chainConfig.IsForkID7Etrog(blockNumber) {
currentTimestamp := sdb.ScalableGetTimestamp()
if blockTimestamp > currentTimestamp {
sdb.ScalableSetTimestamp(blockTimestamp)
}

//save prev block hash
sdb.scalableSetBlockHash(blockNumber-1, stateRoot)

//save ger with l1blockhash
if blockGer != nil && *blockGer != emptyHash {
sdb.WriteGerManagerL1BlockHash(*blockGer, *l1BlockHash)
}
} else {
if blockGer != nil && *blockGer != emptyHash {
blockGerUpdate := dstypes.GerUpdate{
GlobalExitRoot: *blockGer,
Timestamp: blockTimestamp,
}
*gerUpdates = append(*gerUpdates, &blockGerUpdate)
}

for _, ger := range *gerUpdates {
//save ger
if ger != nil {
sdb.WriteGlobalExitRootTimestamp(ger.GlobalExitRoot, ger.Timestamp)
}
}

}
}

func (sdb *IntraBlockState) scalableSetBlockInfoRoot(l1InfoRoot *libcommon.Hash) {
l1InfoRootBigU := uint256.NewInt(0).SetBytes(l1InfoRoot.Bytes())

Expand Down Expand Up @@ -128,7 +172,7 @@ func (sdb *IntraBlockState) ScalableSetBlockNumberToHash(blockNumber uint64, rod

func (sdb *IntraBlockState) ReadGerManagerL1BlockHash(ger libcommon.Hash) libcommon.Hash {
d1 := common.LeftPadBytes(ger.Bytes(), 32)
d2 := common.LeftPadBytes(uint256.NewInt(0).Bytes(), 32)
d2 := common.LeftPadBytes(GLOBAL_EXIT_ROOT_STORAGE_POS.Bytes(), 32)
mapKey := keccak256.Hash(d1, d2)
mkh := libcommon.BytesToHash(mapKey)
key := uint256.NewInt(0)
Expand All @@ -141,13 +185,22 @@ func (sdb *IntraBlockState) ReadGerManagerL1BlockHash(ger libcommon.Hash) libcom

func (sdb *IntraBlockState) WriteGerManagerL1BlockHash(ger, l1BlockHash libcommon.Hash) {
d1 := common.LeftPadBytes(ger.Bytes(), 32)
d2 := common.LeftPadBytes(uint256.NewInt(0).Bytes(), 32)
d2 := common.LeftPadBytes(GLOBAL_EXIT_ROOT_STORAGE_POS.Bytes(), 32)
mapKey := keccak256.Hash(d1, d2)
mkh := libcommon.BytesToHash(mapKey)
val := uint256.NewInt(0).SetBytes(l1BlockHash.Bytes())
sdb.SetState(GER_MANAGER_ADDRESS, &mkh, *val)
}

func (sdb *IntraBlockState) WriteGlobalExitRootTimestamp(ger libcommon.Hash, timestamp uint64) {
d1 := common.LeftPadBytes(ger.Bytes(), 32)
d2 := common.LeftPadBytes(GLOBAL_EXIT_ROOT_STORAGE_POS.Bytes(), 32)
mapKey := keccak256.Hash(d1, d2)
mkh := libcommon.BytesToHash(mapKey)
val := uint256.NewInt(0).SetUint64(timestamp)
sdb.SetState(GER_MANAGER_ADDRESS, &mkh, *val)
}

func (sdb *IntraBlockState) ScalableGetTimestamp() uint64 {
timestamp := uint256.NewInt(0)

Expand Down
17 changes: 15 additions & 2 deletions eth/stagedsync/stage_execute_zkevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ func SpawnExecuteBlocksStageZk(s *StageState, u Unwinder, tx kv.RwTx, toBlock ui

initialBlock := stageProgress + 1
eridb := erigon_db.NewErigonDb(tx)

prevheaderHash, err := rawdb.ReadCanonicalHash(tx, stageProgress)
if err != nil {
return err
}
header, err := cfg.blockReader.Header(ctx, tx, prevheaderHash, stageProgress)
if err != nil {
return err
}
prevBlockHash := header.Root
Loop:
for blockNum := stageProgress + 1; blockNum <= to; blockNum++ {
stageProgress = blockNum
Expand Down Expand Up @@ -165,7 +175,7 @@ Loop:
if err = updateZkEVMBlockCfg(&cfg, hermezDb, logPrefix); err != nil {
return err
}
if err = executeBlockZk(block, header, tx, batch, cfg, *cfg.vmConfig, writeChangeSets, writeReceipts, writeCallTraces, initialCycle, stateStream, hermezDb); err != nil {
if err = executeBlockZk(block, &prevBlockHash, header, tx, batch, cfg, *cfg.vmConfig, writeChangeSets, writeReceipts, writeCallTraces, initialCycle, stateStream, hermezDb); err != nil {
if !errors.Is(err, context.Canceled) {
log.Warn(fmt.Sprintf("[%s] Execution failed", logPrefix), "block", blockNum, "hash", block.Hash().String(), "err", err)
if cfg.hd != nil {
Expand Down Expand Up @@ -233,6 +243,8 @@ Loop:
later.
*/
headerHash := header.Hash()
prevBlockHash = headerHash

rawdb.WriteHeader(tx, header)
err = rawdb.WriteCanonicalHash(tx, headerHash, blockNum)
if err != nil {
Expand Down Expand Up @@ -300,6 +312,7 @@ Loop:

func executeBlockZk(
block *types.Block,
prevBlockHash *common.Hash,
header *types.Header,
tx kv.RwTx,
batch ethdb.Database,
Expand Down Expand Up @@ -339,7 +352,7 @@ func executeBlockZk(
var execRs *core.EphemeralExecResult
getHashFn := core.GetHashFn(block.Header(), getHeader)

execRs, err = core.ExecuteBlockEphemerallyZk(cfg.chainConfig, &vmConfig, getHashFn, cfg.engine, block, stateReader, stateWriter, ChainReaderImpl{config: cfg.chainConfig, tx: tx, blockReader: cfg.blockReader}, getTracer, tx, roHermezDb)
execRs, err = core.ExecuteBlockEphemerallyZk(cfg.chainConfig, &vmConfig, getHashFn, cfg.engine, prevBlockHash, block, stateReader, stateWriter, ChainReaderImpl{config: cfg.chainConfig, tx: tx, blockReader: cfg.blockReader}, getTracer, tx, roHermezDb)

if err != nil {
return err
Expand Down
Loading

0 comments on commit 8ff1cb7

Please sign in to comment.