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

Datastream Scalable Roots #3

Merged
merged 6 commits into from
Dec 12, 2023
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
3 changes: 1 addition & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
zkevm-roots.json filter=lfs diff=lfs merge=lfs -text
zkevm-roots-testnet.json filter=lfs diff=lfs merge=lfs -text

14 changes: 1 addition & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,6 @@ zkEVM-Erigon is a fork of Erigon, currently in Alpha, optimized for syncing with

***

## Prerequisites

- [Git LFS](https://git-lfs.com/)

For syncing different networks, you will need the corresponding network-specific files e.g. `zkevm-roots-testnet.json`. To do this run the following commands:
- `git lfs install` - Initializes the Git LFS
- `git lfs pull` - Downloads the actual LFS files

These contain some pre-calculated roots from the RPC which are later validated by the local node in the intermediate hashes stage.

***

## zkevm-specific API Support

In order to enable the zkevm_ namespace, please add 'zkevm' to the http.api flag (see the example config below).
Expand All @@ -41,7 +29,7 @@ In order to enable the zkevm_ namespace, please add 'zkevm' to the http.api flag
## Limitations/Warnings

- The golden poseidon hashing will be much faster on x86, so developers on Mac may experience slowness on Apple silicone
- Falling behind by > 20 blocks (at some point this will be configurable) will cause a SMT rebuild - which will take some time for longer chains
- Falling behind by > 500 blocks (at some point this will be configurable) will cause a SMT rebuild - which will take some time for longer chains

***

Expand Down
8 changes: 7 additions & 1 deletion cmd/evm/internal/t8ntool/transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import (
"github.com/ledgerwatch/erigon/rlp"
"github.com/ledgerwatch/erigon/tests"
"github.com/ledgerwatch/erigon/turbo/trie"
"github.com/ledgerwatch/erigon/zk/hermez_db"
)

const (
Expand Down Expand Up @@ -302,12 +303,17 @@ func Main(ctx *cli.Context) error {
}
defer tx.Rollback()

hermezDb, err := hermez_db.NewHermezDb(tx)
if err != nil {
return err
}

reader, writer := MakePreState(chainConfig.Rules(0, 0), tx, prestate.Pre)
// serenity engine can be used for pre-merge blocks as well, as it
// redirects to the ethash engine based on the block number
engine := serenity.New(&ethash.FakeEthash{})

result, err := core.ExecuteBlockEphemerally(chainConfig, &vmConfig, getHash, engine, block, reader, writer, nil, getTracer, tx)
result, err := core.ExecuteBlockEphemerally(chainConfig, &vmConfig, getHash, engine, block, reader, writer, nil, getTracer, tx, hermezDb)

if hashError != nil {
return NewError(ErrorMissingBlockhash, fmt.Errorf("blockhash error: %v", err))
Expand Down
2 changes: 1 addition & 1 deletion cmd/hack/hack.go
Original file line number Diff line number Diff line change
Expand Up @@ -1444,7 +1444,7 @@ func main() {
printCurrentBlockNumber(*chaindata)

case "bucket":
printBucket(*chaindata, state.RpcRootsBucketName)
printBucket(*chaindata, kv.PlainState)

case "buckets":
printBuckets(*chaindata, *bucket)
Expand Down
2 changes: 1 addition & 1 deletion cmd/integration/commands/state_domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ func (b *blockProcessor) applyBlock(
ibs.Prepare(tx.Hash(), block.Hash(), i)
ct := exec3.NewCallTracer()
b.vmConfig.Tracer = ct
receipt, _, err := core.ApplyTransaction(b.chainConfig, getHashFn, b.engine, nil, gp, ibs, b.writer, header, tx, usedGas, b.vmConfig, parentHeader.ExcessDataGas)
receipt, _, err := core.ApplyTransaction(b.chainConfig, getHashFn, b.engine, nil, gp, ibs, b.writer, header, tx, usedGas, b.vmConfig, parentHeader.ExcessDataGas, 100) // TODO [zkevm] - fix for build, but may need to pass correct value
if err != nil {
return nil, fmt.Errorf("could not apply tx %d [%x] failed: %w", i, tx.Hash(), err)
}
Expand Down
5 changes: 0 additions & 5 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,6 @@ var (
Usage: "RPC rate limit in requests per second.",
Value: 0,
}
RpcRootsFileFlag = cli.StringFlag{
Name: "zkevm.rpc-roots-file",
Usage: "File to store the RPC roots in",
Value: "",
}
RpcBatchConcurrencyFlag = cli.UintFlag{
Name: "rpc.batch.concurrency",
Usage: "Does limit amount of goroutines to process 1 batch request. Means 1 bach request can't overload server. 1 batch still can have unlimited amount of request",
Expand Down
13 changes: 3 additions & 10 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ type EphemeralExecResult struct {
StateSyncReceipt *types.Receipt `json:"-"`
}

type EffectivePricePercentageGetter interface {
GetEffectiveGasPricePercentage(txHash libcommon.Hash) (uint8, error)
}

// ExecuteBlockEphemerally runs a block from provided stateReader and
// writes the result to the provided stateWriter
func ExecuteBlockEphemerally(
Expand All @@ -90,7 +86,7 @@ func ExecuteBlockEphemerally(
chainReader consensus.ChainHeaderReader,
getTracer func(txIndex int, txHash libcommon.Hash) (vm.EVMLogger, error),
dbTx kv.RwTx,
effectivePricePercentageGetter EffectivePricePercentageGetter,
roHermezDb state.ReadOnlyHermezDb,
) (*EphemeralExecResult, error) {

defer BlockExecutionTimer.UpdateDuration(time.Now())
Expand Down Expand Up @@ -140,7 +136,7 @@ func ExecuteBlockEphemerally(

gp.Reset(block.GasLimit())

effectiveGasPricePercentage, err := effectivePricePercentageGetter.GetEffectiveGasPricePercentage(tx.Hash())
effectiveGasPricePercentage, err := roHermezDb.GetEffectiveGasPricePercentage(tx.Hash())
if err != nil {
return nil, err
}
Expand All @@ -166,14 +162,11 @@ func ExecuteBlockEphemerally(
}
}

// [zkevm] - set smt root for each tx, unless last tx in block (see ibs block commit)
//if i != block.Transactions().Len()-1 {
// [zkevm] - set smt root hash in magic account
err = ibs.ScalableSetSmtRootHash(dbTx)
err = ibs.ScalableSetSmtRootHash(roHermezDb)
if err != nil {
return nil, err
}
//}
}

receiptSha := types.DeriveSha(receipts)
Expand Down
68 changes: 7 additions & 61 deletions core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,10 @@ import (
"fmt"
"sort"

"encoding/binary"
"encoding/hex"
"math/big"
"strings"

"github.com/holiman/uint256"
"github.com/iden3/go-iden3-crypto/keccak256"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/kv"
types2 "github.com/ledgerwatch/erigon-lib/types"
"github.com/ledgerwatch/erigon/chain"
"github.com/ledgerwatch/erigon/common"
Expand All @@ -41,6 +36,11 @@ import (
"github.com/ledgerwatch/erigon/turbo/trie"
)

type ReadOnlyHermezDb interface {
GetEffectiveGasPricePercentage(txHash libcommon.Hash) (uint8, error)
GetStateRoot(l2BlockNo uint64) (libcommon.Hash, error)
}

type revision struct {
id int
journalIndex int
Expand All @@ -49,8 +49,6 @@ type revision struct {
// SystemAddress - sender address for internal state updates.
var SystemAddress = libcommon.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")

const RpcRootsBucketName = "HermezRpcRoot"

// BalanceIncrease represents the increase of balance of an account that did not require
// reading the account first
type BalanceIncrease struct {
Expand Down Expand Up @@ -822,7 +820,7 @@ func (sdb *IntraBlockState) ScalableSetTxNum() {
sdb.SetState(saddr, &sl0, *txNum)
}

func (sdb *IntraBlockState) ScalableSetSmtRootHash(dbTx kv.RwTx) error {
func (sdb *IntraBlockState) ScalableSetSmtRootHash(roHermezDb ReadOnlyHermezDb) error {
saddr := libcommon.HexToAddress("0x000000000000000000000000000000005ca1ab1e")
sl0 := libcommon.HexToHash("0x0")

Expand All @@ -835,7 +833,7 @@ func (sdb *IntraBlockState) ScalableSetSmtRootHash(dbTx kv.RwTx) error {
mapKey := keccak256.Hash(d1, d2)
mkh := libcommon.BytesToHash(mapKey)

rpcHash, err := getDbRoot(dbTx, txNum.Uint64())
rpcHash, err := roHermezDb.GetStateRoot(txNum.Uint64())
if err != nil {
return err
}
Expand All @@ -848,55 +846,3 @@ func (sdb *IntraBlockState) ScalableSetSmtRootHash(dbTx kv.RwTx) error {

return nil
}

func trimHexString(s string) string {
if strings.HasPrefix(s, "0x") {
s = s[2:]
}

for i := 0; i < len(s); i++ {
if s[i] != '0' {
return "0x" + s[i:]
}
}

return "0x0"
}

func verifyRoot(dbTx kv.RwTx, hash string, txNum uint64) (*libcommon.Hash, error) {
rpcHash, err := getDbRoot(dbTx, txNum)
if err != nil {
return nil, err
}
h := libcommon.HexToHash(hash)

if rpcHash.Big().Cmp(big.NewInt(0)) == 0 {
return &h, fmt.Errorf("RPC root hash is zero")
}

trimmedRpcHash := trimHexString(rpcHash.String())

fmt.Printf("rpcHash: %s\n", trimmedRpcHash)
fmt.Printf("hash: %s\n", hash)

if trimmedRpcHash != hash {
return &h, fmt.Errorf("root hash mismatch")
}

return &h, nil
}

func getDbRoot(dbTx kv.RwTx, txNum uint64) (*libcommon.Hash, error) {
rootHash, err := dbTx.GetOne(RpcRootsBucketName, UintBytes(txNum))
if err != nil {
return nil, err
}
h := libcommon.BytesToHash(rootHash)
return &h, nil
}

func UintBytes(no uint64) []byte {
noBytes := make([]byte, 8)
binary.BigEndian.PutUint64(noBytes, no)
return noBytes
}
1 change: 0 additions & 1 deletion eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ type Zk struct {
L1GERManagerContractAddress common.Address
L1FirstBlock uint64
RpcRateLimits int
RpcRootsFile string

RebuildTreeAfter uint64
}
Expand Down
17 changes: 0 additions & 17 deletions eth/stagedsync/default_stages.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ func DefaultZkStages(
cumulativeIndex CumulativeIndexCfg,
blockHashCfg BlockHashesCfg,
senders SendersCfg,
rpcRootsCfg zkStages.RpcRootsCfg,
exec ExecuteBlockCfg,
hashState HashStateCfg,
zkInterHashesCfg zkStages.ZkInterHashesCfg,
Expand Down Expand Up @@ -400,22 +399,6 @@ func DefaultZkStages(
return PruneSendersStage(p, tx, senders, ctx)
},
},
{
ID: sync_stages.RpcRoots,
Description: "Download RPC roots",
Forward: func(firstCycle bool, badBlockUnwind bool, s *sync_stages.StageState, u sync_stages.Unwinder, tx kv.RwTx, quiet bool) error {
if badBlockUnwind {
return nil
}
return zkStages.SpawnStageRpcRoots(s, u, ctx, tx, rpcRootsCfg, test, firstCycle, quiet)
},
Unwind: func(firstCycle bool, u *sync_stages.UnwindState, s *sync_stages.StageState, tx kv.RwTx) error {
return zkStages.UnwindRpcRootsStage(u, tx, rpcRootsCfg, ctx)
},
Prune: func(firstCycle bool, p *sync_stages.PruneState, tx kv.RwTx) error {
return zkStages.PruneRpcRootsStage(p, tx, rpcRootsCfg, ctx)
},
},
{
ID: sync_stages.Execution,
Description: "Execute blocks w/o hash checks",
Expand Down
4 changes: 2 additions & 2 deletions eth/stagedsync/stage_execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func executeBlock(
writeCallTraces bool,
initialCycle bool,
stateStream bool,
effectivePricePercentageGetter core.EffectivePricePercentageGetter,
roHermezDb state.ReadOnlyHermezDb,
) error {
blockNum := block.NumberU64()

Expand Down Expand Up @@ -212,7 +212,7 @@ func executeBlock(
} else {
// for zkEVM no receipts
//vmConfig.NoReceipts = true
execRs, err = core.ExecuteBlockEphemerally(cfg.chainConfig, &vmConfig, getHashFn, cfg.engine, block, stateReader, stateWriter, ChainReaderImpl{config: cfg.chainConfig, tx: tx, blockReader: cfg.blockReader}, getTracer, tx, effectivePricePercentageGetter)
execRs, err = core.ExecuteBlockEphemerally(cfg.chainConfig, &vmConfig, getHashFn, cfg.engine, block, stateReader, stateWriter, ChainReaderImpl{config: cfg.chainConfig, tx: tx, blockReader: cfg.blockReader}, getTracer, tx, roHermezDb)
}
if err != nil {
return err
Expand Down
1 change: 0 additions & 1 deletion sync_stages/stages.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ var (
L1Sequences SyncStage = "L1Sequences"
L1VerificationsBatchNo SyncStage = "L1VerificationsBatchNo"
Batches SyncStage = "Batches"
RpcRoots SyncStage = "RpcRoots"
HighestHashableL2BlockNo SyncStage = "HighestHashableL2BlockNo"
VerificationsStateRootCheck SyncStage = "VerificationStateRootCheck"
ForkId SyncStage = "ForkId"
Expand Down
1 change: 0 additions & 1 deletion turbo/cli/default_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,5 +175,4 @@ var DefaultFlags = []cli.Flag{
&utils.L1FirstBlockFlag,
&utils.RpcRateLimitsFlag,
&utils.RebuildTreeAfterFlag,
&utils.RpcRootsFileFlag,
}
2 changes: 0 additions & 2 deletions turbo/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ func ApplyFlagsForZkConfig(ctx *cli.Context, cfg *ethconfig.Config) {
L1FirstBlock: ctx.Uint64(utils.L1FirstBlockFlag.Name),
RpcRateLimits: ctx.Int(utils.RpcRateLimitsFlag.Name),
RebuildTreeAfter: ctx.Uint64(utils.RebuildTreeAfterFlag.Name),
RpcRootsFile: ctx.String(utils.RpcRootsFileFlag.Name),
}

checkFlag(utils.L2ChainIdFlag.Name, cfg.Zk.L2ChainId)
Expand All @@ -319,7 +318,6 @@ func ApplyFlagsForZkConfig(ctx *cli.Context, cfg *ethconfig.Config) {
checkFlag(utils.L1FirstBlockFlag.Name, cfg.Zk.L1FirstBlock)
checkFlag(utils.RpcRateLimitsFlag.Name, cfg.Zk.RpcRateLimits)
checkFlag(utils.RebuildTreeAfterFlag.Name, cfg.Zk.RebuildTreeAfter)
// don't check RpcRootsFile as it will get set by network as a default if not overriden by flag
}

func ApplyFlagsForEthConfigCobra(f *pflag.FlagSet, cfg *ethconfig.Config) {
Expand Down
16 changes: 0 additions & 16 deletions turbo/stages/stageloop.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/consensus/misc"
"github.com/ledgerwatch/erigon/core/rawdb"
corestate "github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/eth/ethconfig"
Expand Down Expand Up @@ -84,20 +83,6 @@ func StageLoop(
) {
defer close(waitForDone)
initialCycle := true
trw, err := db.BeginRw(ctx)
if err != nil {
log.Error("Failed to start transaction to add new zkevm batch tables", "err", err)
return
}
err = trw.CreateBucket(corestate.RpcRootsBucketName)
if err != nil {
log.Error(fmt.Sprintf("Failed to create %s bucket", corestate.RpcRootsBucketName), "err", err)
return
}
if err := trw.Commit(); err != nil {
log.Error("Failed to commit transaction to add new zkevm batch tables", "err", err)
return
}

for {
start := time.Now()
Expand Down Expand Up @@ -500,7 +485,6 @@ func NewDefaultZkStages(ctx context.Context,
stagedsync.StageCumulativeIndexCfg(db),
stagedsync.StageBlockHashesCfg(db, dirs.Tmp, controlServer.ChainConfig),
stagedsync.StageSendersCfg(db, controlServer.ChainConfig, false, dirs.Tmp, cfg.Prune, blockRetire, controlServer.Hd),
zkStages.StageRpcRootsCfg(db, controlServer.ChainConfig, cfg.Zk),
stagedsync.StageExecuteBlocksCfg(
db,
cfg.Prune,
Expand Down
Loading