diff --git a/adapters/p2p2core/felt.go b/adapters/p2p2core/felt.go index 62c5f64cd7..103e57b399 100644 --- a/adapters/p2p2core/felt.go +++ b/adapters/p2p2core/felt.go @@ -4,6 +4,7 @@ import ( "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/p2p/starknet/spec" "github.com/ethereum/go-ethereum/common" + "reflect" ) func AdaptHash(h *spec.Hash) *felt.Felt { @@ -23,10 +24,9 @@ func AdaptFelt(f *spec.Felt252) *felt.Felt { } func adapt(v interface{ GetElements() []byte }) *felt.Felt { - if v == nil { + if v == nil || reflect.ValueOf(v).IsNil() { return nil } - return new(felt.Felt).SetBytes(v.GetElements()) } diff --git a/p2p/snap_server.go b/p2p/snap_server.go index 08bf0b3def..435c885161 100644 --- a/p2p/snap_server.go +++ b/p2p/snap_server.go @@ -97,7 +97,7 @@ func (b *snapServer) GetClassRange(request *spec.ClassRangeRequest) (iter.Seq[pr stateRoot := p2p2core.AdaptHash(request.Root) startAddr := p2p2core.AdaptHash(request.Start) - b.log.Debugw("GetClassRange", "root", stateRoot, "start", startAddr, "chunks", request.ChunksPerProof) + b.log.Debugw("GetClassRange", "start", startAddr, "chunks", request.ChunksPerProof) return func(yield yieldFunc) { s, err := b.blockchain.GetStateForStateRoot(stateRoot) @@ -164,7 +164,9 @@ func (b *snapServer) GetClassRange(request *spec.ClassRangeRequest) (iter.Seq[pr RangeProof: Core2P2pProof(proofs), } - b.log.Infow("sending class range response", "len(classes)", len(classkeys)) + first := classkeys[0] + last := classkeys[len(classkeys)-1] + b.log.Infow("sending class range response", "len(classes)", len(classkeys), "first", first, "last", last) if !yield(clsMsg) { // we should not send `FinMsg` when the client explicitly asks to stop return @@ -176,7 +178,7 @@ func (b *snapServer) GetClassRange(request *spec.ClassRangeRequest) (iter.Seq[pr } yield(finMsg) - b.log.Infow("class range iteration completed") + b.log.Infow("GetClassRange iteration completed") }, nil } @@ -261,7 +263,9 @@ func (b *snapServer) GetContractRange(request *spec.ContractRangeRequest) (iter. }, } - b.log.Infow("sending contract range response", "len(states)", len(states)) + first := p2p2core.AdaptAddress(states[0].Address) + last := p2p2core.AdaptAddress(states[len(states)-1].Address) + b.log.Infow("sending contract range response", "len(states)", len(states), "first", first, "last", last) if !yield(cntrMsg) { // we should not send `FinMsg` when the client explicitly asks to stop return @@ -269,6 +273,8 @@ func (b *snapServer) GetContractRange(request *spec.ContractRangeRequest) (iter. if finished { break } + + states = states[:0] } yield(finMsg) @@ -302,7 +308,8 @@ func (b *snapServer) GetStorageRange(request *spec.ContractStorageRequest) (iter strie, err := s.StorageTrieForAddr(p2p2core.AdaptAddress(query.Address)) if err != nil { - log.Error("error getting storage trie for address", "addr", query.Address.String(), "err", err) + addr := p2p2core.AdaptAddress(query.Address) + log.Error("error getting storage trie for address", "addr", addr, "err", err) return } @@ -445,12 +452,11 @@ func iterateWithLimit( pathes := make([]*felt.Felt, 0) hashes := make([]*felt.Felt, 0) - logger.Infow("entering IterateAndGenerateProof", "startAddr", startAddr, "endAddr", limitAddr, "maxNodes", maxNodes) count := uint32(0) proof, finished, err := srcTrie.IterateAndGenerateProof(startAddr, func(key *felt.Felt, value *felt.Felt) (bool, error) { // Need at least one. - if limitAddr != nil && key.Cmp(limitAddr) > 1 && count > 0 { - return false, nil + if limitAddr != nil && key.Cmp(limitAddr) >= 0 && count > 0 { + return true, nil } pathes = append(pathes, key) @@ -474,7 +480,6 @@ func iterateWithLimit( return nil, finished, err } - logger.Infow("exiting IterateAndGenerateProof", "len(proof)", len(proof), "finished", finished, "err", err) return proof, finished, err } diff --git a/p2p/snap_server_test.go b/p2p/snap_server_test.go index 227b1b65c1..3f3b8f3d23 100644 --- a/p2p/snap_server_test.go +++ b/p2p/snap_server_test.go @@ -205,6 +205,16 @@ func TestContractStorageRange(t *testing.T) { storageRoot *felt.Felt expectedLeaves int }{ + { + address: feltFromString("0x5eb8d1bc5aaf2f323f2a807d429686ac012ca16f90740071d2f3a160dc231"), + storageRoot: feltFromString("0x0"), + expectedLeaves: 0, + }, + { + address: feltFromString("0x614a5e0519963324acb5640321240827c0cd6a9f7cf5f17a80c1596e607d0"), + storageRoot: feltFromString("0x55ee7fd57d0aa3da8b89ea2feda16f9435186988a8b00b6f22f5ba39f3cf172"), + expectedLeaves: 1, + }, { address: feltFromString("0x3deecdb26a60e4c062d5bd98ab37f72ea2acc37f28dae6923359627ebde9"), storageRoot: feltFromString("0x276edbc91a945d11645ba0b8298c7d657e554d06ab2bb765cbc44d61fa01fd5"), @@ -333,6 +343,101 @@ func TestGetClassesByHash(t *testing.T) { assert.True(t, finMsgReceived) } +func TestGetContractStorageRoot(t *testing.T) { + var d db.DB + //t.Skip("DB snapshot is needed for this test") + d, _ = pebble.NewWithOptions("/Users/pnowosie/juno/snapshots/juno-sepolia", 128000000, 128, false) + defer func() { _ = d.Close() }() + bc := blockchain.New(d, &utils.Sepolia) // Needed because class loader need encoder to be registered + + b, err := bc.Head() + assert.NoError(t, err) + + fmt.Printf("headblock %d\n", b.Number) + + stateRoot := b.GlobalStateRoot + + logger, _ := utils.NewZapLogger(utils.DEBUG, false) + server := &snapServer{ + log: logger, + blockchain: bc, + } + + tests := []struct { + address *felt.Felt + storageRoot *felt.Felt + }{ + { + address: feltFromString("0x5eb8d1bc5aaf2f323f2a807d429686ac012ca16f90740071d2f3a160dc231"), + storageRoot: feltFromString("0x0"), + }, + { + address: feltFromString("0x5ec87443bcb74e1e58762be15c3c513926a91a5d5b4a204e9e7b5ca884fb7"), + storageRoot: feltFromString("0x36fc3942926334a24b739065f26ffe547044af7466a6f8d391e0750603ffa8c"), + }, + { + address: feltFromString("0x614a5e0519963324acb5640321240827c0cd6a9f7cf5f17a80c1596e607d0"), + storageRoot: feltFromString("0x55ee7fd57d0aa3da8b89ea2feda16f9435186988a8b00b6f22f5ba39f3cf172"), + }, + { + address: feltFromString("0x6b7d60ec8176d8a1c77afdca05191dad1e1a20fef2e5e3aceccee0b3cbd6a"), + storageRoot: feltFromString("0x726d42240f103a32ce1b6acc7498f52fdf83e308cf70e0a6394591cee1886c8"), + }, + { + address: feltFromString("0x3deecdb26a60e4c062d5bd98ab37f72ea2acc37f28dae6923359627ebde9"), + storageRoot: feltFromString("0x276edbc91a945d11645ba0b8298c7d657e554d06ab2bb765cbc44d61fa01fd5"), + }, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("%.7s...", test.address), func(t *testing.T) { + request := &spec.ContractRangeRequest{ + ChunksPerProof: 5, + Start: core2p2p.AdaptAddress(test.address), + End: nil, //core2p2p.AdaptAddress(test.address), + StateRoot: core2p2p.AdaptHash(stateRoot), + } + + iter, err := server.GetContractRange(request) + assert.NoError(t, err) + + finMsgReceived := false + for res := range iter { + assert.NotNil(t, res) + resT, ok := res.(*spec.ContractRangeResponse) + assert.True(t, ok) + assert.NotNil(t, resT) + + i := 0 + switch v := resT.GetResponses().(type) { + case *spec.ContractRangeResponse_Range: + assert.False(t, finMsgReceived) + assert.Len(t, v.Range.State, 1) + contract := v.Range.State[0] + fmt.Println("Contract:", p2p2core.AdaptAddress(contract.Address), "StorageRoot:", p2p2core.AdaptHash(contract.Storage)) + assert.Equal(t, test.address, p2p2core.AdaptAddress(contract.Address)) + assert.Equal(t, test.storageRoot, p2p2core.AdaptHash(contract.Storage)) + i++ + if i > 20 { + t.Fatal("Too many contracts received") + } + case *spec.ContractRangeResponse_Fin: + finMsgReceived = true + default: + // we expect no any other message only just one range because we break the iteration + t.Fatal("received unexpected message", "type", v) + } + } + }) + } +} + +func TestAdaptNilReturnsNil(t *testing.T) { + assert.Nil(t, p2p2core.AdaptAddress(nil)) + assert.Nil(t, p2p2core.AdaptHash(nil)) + assert.Nil(t, p2p2core.AdaptFelt(nil)) +} + func feltFromString(str string) *felt.Felt { f, err := (&felt.Felt{}).SetString(str) if err != nil { diff --git a/p2p/snap_syncer.go b/p2p/snap_syncer.go index 141961ec01..7998b3c360 100644 --- a/p2p/snap_syncer.go +++ b/p2p/snap_syncer.go @@ -116,8 +116,8 @@ var ( // For some reason, the trie throughput is higher if the batch size is small. classRangeChunksPerProof = 500 - contractRangeChunkPerProof = 500 - storageRangeChunkPerProof = 500 + contractRangeChunkPerProof = 501 + storageRangeChunkPerProof = 502 maxStorageBatchSize = 500 maxMaxPerStorageSize = 500