Skip to content

Commit

Permalink
Merge branch 'zkevm' into test/zkevm_api_unit_test
Browse files Browse the repository at this point in the history
  • Loading branch information
ARR552 authored Aug 30, 2024
2 parents d8530bf + 344e4bc commit e314d0a
Show file tree
Hide file tree
Showing 20 changed files with 1,143 additions and 229 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci_zkevm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
uses: actions/checkout@v4
with:
repository: 0xPolygon/kurtosis-cdk
ref: v0.2.4
ref: v0.2.7
path: kurtosis-cdk

- name: Install Kurtosis CDK tools
Expand Down Expand Up @@ -111,7 +111,7 @@ jobs:
- name: Monitor verified batches
working-directory: ./kurtosis-cdk
shell: bash
run: timeout 900s .github/actions/monitor-cdk-verified-batches/batch_verification_monitor.sh 20 900 cdk-erigon-node-001
run: timeout 900s .github/scripts/monitor-verified-batches.sh --rpc-url $(kurtosis port print cdk-v1 cdk-erigon-node-001 http-rpc) --target 20 --timeout 900

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
Expand Down
253 changes: 198 additions & 55 deletions cmd/rpcdaemon/commands/zkevm_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,35 @@ import (
libcommon "github.com/gateway-fm/cdk-erigon-lib/common"
"github.com/gateway-fm/cdk-erigon-lib/common/hexutility"
"github.com/gateway-fm/cdk-erigon-lib/kv"
"github.com/gateway-fm/cdk-erigon-lib/kv/memdb"
jsoniter "github.com/json-iterator/go"

"github.com/holiman/uint256"
"github.com/ledgerwatch/erigon/common/hexutil"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/state"
eritypes "github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/types/accounts"
"github.com/ledgerwatch/erigon/eth/ethconfig"
"github.com/ledgerwatch/erigon/eth/stagedsync"
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/eth/tracers"
"github.com/ledgerwatch/erigon/rpc"
smtDb "github.com/ledgerwatch/erigon/smt/pkg/db"
smt "github.com/ledgerwatch/erigon/smt/pkg/smt"
smtUtils "github.com/ledgerwatch/erigon/smt/pkg/utils"
"github.com/ledgerwatch/erigon/turbo/rpchelper"
"github.com/ledgerwatch/erigon/zk/constants"
"github.com/ledgerwatch/erigon/zk/hermez_db"
"github.com/ledgerwatch/erigon/zk/legacy_executor_verifier"
types "github.com/ledgerwatch/erigon/zk/rpcdaemon"
"github.com/ledgerwatch/erigon/zk/sequencer"
zkStages "github.com/ledgerwatch/erigon/zk/stages"
"github.com/ledgerwatch/erigon/zk/syncer"
zktx "github.com/ledgerwatch/erigon/zk/tx"
"github.com/ledgerwatch/erigon/zk/utils"
zkUtils "github.com/ledgerwatch/erigon/zk/utils"
"github.com/ledgerwatch/erigon/zk/witness"
"github.com/ledgerwatch/erigon/zkevm/hex"
"github.com/ledgerwatch/erigon/zkevm/jsonrpc/client"
Expand Down Expand Up @@ -294,6 +304,9 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers
if syncing != nil && syncing != false {
bn := syncing.(map[string]interface{})["currentBlock"]
highestBatchNo, err = hermezDb.GetBatchNoByL2Block(uint64(bn.(hexutil.Uint64)))
if err != nil {
return nil, err
}
}

bds := make([]*types.BatchDataSlim, 0, len(batchNumbers.Numbers))
Expand Down Expand Up @@ -337,7 +350,6 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers

// collect blocks in batch
var batchBlocks []*eritypes.Block
var batchTxs []eritypes.Transaction
// handle genesis - not in the hermez tables so requires special treament
if batchNumber == 0 {
blk, err := api.ethApi.BaseAPI.blockByNumberWithSenders(tx, 0)
Expand All @@ -353,9 +365,6 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers
return nil, err
}
batchBlocks = append(batchBlocks, blk)
for _, btx := range blk.Transactions() {
batchTxs = append(batchTxs, btx)
}
}

// batch l2 data - must build on the fly
Expand All @@ -364,7 +373,7 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers
return nil, err
}

batchL2Data, err := generateBatchData(tx, hermezDb, batchBlocks, forkId)
batchL2Data, err := utils.GenerateBatchData(tx, hermezDb, batchBlocks, forkId)
if err != nil {
return nil, err
}
Expand All @@ -376,54 +385,6 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers
return populateBatchDataSlimDetails(bds)
}

func generateBatchData(
tx kv.Tx,
hermezDb *hermez_db.HermezDbReader,
batchBlocks []*eritypes.Block,
forkId uint64,
) (batchL2Data []byte, err error) {

lastBlockNoInPreviousBatch := uint64(0)
if batchBlocks[0].NumberU64() != 0 {
lastBlockNoInPreviousBatch = batchBlocks[0].NumberU64() - 1
}

lastBlockInPreviousBatch, err := rawdb.ReadBlockByNumber(tx, lastBlockNoInPreviousBatch)
if err != nil {
return nil, err
}

batchL2Data = []byte{}
for i := 0; i < len(batchBlocks); i++ {
var dTs uint32
if i == 0 {
dTs = uint32(batchBlocks[i].Time() - lastBlockInPreviousBatch.Time())
} else {
dTs = uint32(batchBlocks[i].Time() - batchBlocks[i-1].Time())
}
iti, err := hermezDb.GetBlockL1InfoTreeIndex(batchBlocks[i].NumberU64())
if err != nil {
return nil, err
}
egTx := make(map[common.Hash]uint8)
for _, txn := range batchBlocks[i].Transactions() {
eg, err := hermezDb.GetEffectiveGasPricePercentage(txn.Hash())
if err != nil {
return nil, err
}
egTx[txn.Hash()] = eg
}

bl2d, err := zktx.GenerateBlockBatchL2Data(uint16(forkId), dTs, uint32(iti), batchBlocks[i].Transactions(), egTx)
if err != nil {
return nil, err
}
batchL2Data = append(batchL2Data, bl2d...)
}

return batchL2Data, err
}

// GetBatchByNumber returns a batch from the current canonical chain. If number is nil, the
// latest known batch is returned.
func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.BlockNumber, fullTx *bool) (json.RawMessage, error) {
Expand Down Expand Up @@ -665,7 +626,7 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
return nil, err
}

batchL2Data, err := generateBatchData(tx, hermezDb, batchBlocks, forkId)
batchL2Data, err := utils.GenerateBatchData(tx, hermezDb, batchBlocks, forkId)
if err != nil {
return nil, err
}
Expand All @@ -681,7 +642,7 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
// forkid exit roots logic
// if forkid < 12 then we should only set the exit roots if they have changed, otherwise 0x00..00
// if forkid >= 12 then we should always set the exit roots
if forkId < 12 {
if forkId < uint64(constants.ForkID12Banana) {
// get the previous batches exit roots
prevBatchNo := batchNo - 1
prevBatchHighestBlock, err := hermezDb.GetHighestBlockInBatch(prevBatchNo)
Expand Down Expand Up @@ -1448,3 +1409,185 @@ func populateBatchDataSlimDetails(batches []*types.BatchDataSlim) (json.RawMessa

return json.Marshal(jBatches)
}

// GetProof
func (zkapi *ZkEvmAPIImpl) GetProof(ctx context.Context, address common.Address, storageKeys []common.Hash, blockNrOrHash rpc.BlockNumberOrHash) (*accounts.SMTAccProofResult, error) {
api := zkapi.ethApi

tx, err := api.db.BeginRo(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback()
if api.historyV3(tx) {
return nil, fmt.Errorf("not supported by Erigon3")
}

blockNr, _, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters)
if err != nil {
return nil, err
}

latestBlock, err := rpchelper.GetLatestBlockNumber(tx)
if err != nil {
return nil, err
}

if latestBlock < blockNr {
// shouldn't happen, but check anyway
return nil, fmt.Errorf("block number is in the future latest=%d requested=%d", latestBlock, blockNr)
}

batch := memdb.NewMemoryBatch(tx, api.dirs.Tmp)
defer batch.Rollback()
if err = zkUtils.PopulateMemoryMutationTables(batch); err != nil {
return nil, err
}

if blockNr < latestBlock {
if latestBlock-blockNr > maxGetProofRewindBlockCount {
return nil, fmt.Errorf("requested block is too old, block must be within %d blocks of the head block number (currently %d)", maxGetProofRewindBlockCount, latestBlock)
}
unwindState := &stagedsync.UnwindState{UnwindPoint: blockNr}
stageState := &stagedsync.StageState{BlockNumber: latestBlock}

interHashStageCfg := zkStages.StageZkInterHashesCfg(nil, true, true, false, api.dirs.Tmp, api._blockReader, nil, api.historyV3(tx), api._agg, nil)

if err = zkStages.UnwindZkIntermediateHashesStage(unwindState, stageState, batch, interHashStageCfg, ctx, true); err != nil {
return nil, fmt.Errorf("unwind intermediate hashes: %w", err)
}

if err != nil {
return nil, err
}
tx = batch
}

reader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, 0, api.filters, api.stateCache, api.historyV3(tx), "")
if err != nil {
return nil, err
}

header, err := api._blockReader.HeaderByNumber(ctx, tx, blockNr)
if err != nil {
return nil, err
}

tds := state.NewTrieDbState(header.Root, tx, blockNr, nil)
tds.SetResolveReads(true)
tds.StartNewBuffer()
tds.SetStateReader(reader)

ibs := state.New(tds)

ibs.GetBalance(address)

for _, key := range storageKeys {
value := new(uint256.Int)
ibs.GetState(address, &key, value)
}

rl, err := tds.ResolveSMTRetainList()
if err != nil {
return nil, err
}

smtTrie := smt.NewRoSMT(smtDb.NewRoEriDb(tx))

proofs, err := smt.BuildProofs(smtTrie, rl, ctx)
if err != nil {
return nil, err
}

stateRootNode := smtUtils.ScalarToRoot(new(big.Int).SetBytes(header.Root.Bytes()))

if err != nil {
return nil, err
}

balanceKey, err := smtUtils.KeyEthAddrBalance(address.String())
if err != nil {
return nil, err
}

nonceKey, err := smtUtils.KeyEthAddrNonce(address.String())
if err != nil {
return nil, err
}

codeHashKey, err := smtUtils.KeyContractCode(address.String())
if err != nil {
return nil, err
}

codeLengthKey, err := smtUtils.KeyContractLength(address.String())
if err != nil {
return nil, err
}

balanceProofs := smt.FilterProofs(proofs, balanceKey)
balanceBytes, err := smt.VerifyAndGetVal(stateRootNode, balanceProofs, balanceKey)
if err != nil {
return nil, fmt.Errorf("balance proof verification failed: %w", err)
}

balance := new(big.Int).SetBytes(balanceBytes)

nonceProofs := smt.FilterProofs(proofs, nonceKey)
nonceBytes, err := smt.VerifyAndGetVal(stateRootNode, nonceProofs, nonceKey)
if err != nil {
return nil, fmt.Errorf("nonce proof verification failed: %w", err)
}
nonce := new(big.Int).SetBytes(nonceBytes).Uint64()

codeHashProofs := smt.FilterProofs(proofs, codeHashKey)
codeHashBytes, err := smt.VerifyAndGetVal(stateRootNode, codeHashProofs, codeHashKey)
if err != nil {
return nil, fmt.Errorf("code hash proof verification failed: %w", err)
}
codeHash := codeHashBytes

codeLengthProofs := smt.FilterProofs(proofs, codeLengthKey)
codeLengthBytes, err := smt.VerifyAndGetVal(stateRootNode, codeLengthProofs, codeLengthKey)
if err != nil {
return nil, fmt.Errorf("code length proof verification failed: %w", err)
}
codeLength := new(big.Int).SetBytes(codeLengthBytes).Uint64()

accProof := &accounts.SMTAccProofResult{
Address: address,
Balance: (*hexutil.Big)(balance),
CodeHash: libcommon.BytesToHash(codeHash),
CodeLength: hexutil.Uint64(codeLength),
Nonce: hexutil.Uint64(nonce),
BalanceProof: balanceProofs,
NonceProof: nonceProofs,
CodeHashProof: codeHashProofs,
CodeLengthProof: codeLengthProofs,
StorageProof: make([]accounts.SMTStorageProofResult, 0),
}

addressArrayBig := smtUtils.ScalarToArrayBig(smtUtils.ConvertHexToBigInt(address.String()))
for _, k := range storageKeys {
storageKey, err := smtUtils.KeyContractStorage(addressArrayBig, k.String())
if err != nil {
return nil, err
}
storageProofs := smt.FilterProofs(proofs, storageKey)

valueBytes, err := smt.VerifyAndGetVal(stateRootNode, storageProofs, storageKey)
if err != nil {
return nil, fmt.Errorf("storage proof verification failed: %w", err)
}

value := new(big.Int).SetBytes(valueBytes)

accProof.StorageProof = append(accProof.StorageProof, accounts.SMTStorageProofResult{
Key: k,
Value: (*hexutil.Big)(value),
Proof: storageProofs,
})
}

return accProof, nil
}
6 changes: 6 additions & 0 deletions core/state/intra_block_state_zkevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,19 @@ type ReadOnlyHermezDb interface {
GetIntermediateTxStateRoot(blockNum uint64, txhash libcommon.Hash) (libcommon.Hash, error)
GetReusedL1InfoTreeIndex(blockNum uint64) (bool, error)
GetSequenceByBatchNo(batchNo uint64) (*zktypes.L1BatchInfo, error)
GetSequenceByBatchNoOrHighest(batchNo uint64) (*zktypes.L1BatchInfo, error)
GetHighestBlockInBatch(batchNo uint64) (uint64, error)
GetLowestBlockInBatch(batchNo uint64) (uint64, bool, error)
GetL2BlockNosByBatch(batchNo uint64) ([]uint64, error)
GetBatchGlobalExitRoot(batchNum uint64) (*dstypes.GerUpdate, error)
GetVerificationByBatchNo(batchNo uint64) (*zktypes.L1BatchInfo, error)
GetVerificationByBatchNoOrHighest(batchNo uint64) (*zktypes.L1BatchInfo, error)
GetL1BatchData(batchNumber uint64) ([]byte, error)
GetL1InfoTreeUpdateByGer(ger libcommon.Hash) (*zktypes.L1InfoTreeUpdate, error)
GetBlockL1InfoTreeIndex(blockNumber uint64) (uint64, error)
GetBlockInfoRoot(blockNumber uint64) (libcommon.Hash, error)
GetLastBlockGlobalExitRoot(l2BlockNo uint64) (libcommon.Hash, uint64, error)
GetForkId(batchNo uint64) (uint64, error)
}

func (sdb *IntraBlockState) GetTxCount() (uint64, error) {
Expand Down
19 changes: 19 additions & 0 deletions core/types/accounts/account_proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,22 @@ type StorProofResult struct {
Value *hexutil.Big `json:"value"`
Proof []hexutility.Bytes `json:"proof"`
}

type SMTAccProofResult struct {
Address libcommon.Address `json:"address"`
Balance *hexutil.Big `json:"balance"`
CodeHash libcommon.Hash `json:"codeHash"`
CodeLength hexutil.Uint64 `json:"codeLength"`
Nonce hexutil.Uint64 `json:"nonce"`
BalanceProof []hexutility.Bytes `json:"balanceProof"`
NonceProof []hexutility.Bytes `json:"nonceProof"`
CodeHashProof []hexutility.Bytes `json:"codeHashProof"`
CodeLengthProof []hexutility.Bytes `json:"codeLengthProof"`
StorageProof []SMTStorageProofResult `json:"storageProof"`
}

type SMTStorageProofResult struct {
Key libcommon.Hash `json:"key"`
Value *hexutil.Big `json:"value"`
Proof []hexutility.Bytes `json:"proof"`
}
Loading

0 comments on commit e314d0a

Please sign in to comment.