diff --git a/mocks/mock_host.go b/mocks/mock_host.go new file mode 100644 index 0000000000..9957143892 --- /dev/null +++ b/mocks/mock_host.go @@ -0,0 +1,230 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/libp2p/go-libp2p/core/host (interfaces: Host) +// +// Generated by this command: +// +// mockgen -destination=../../mocks/mock_host.go -package=mocks github.com/libp2p/go-libp2p/core/host Host +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + connmgr "github.com/libp2p/go-libp2p/core/connmgr" + event "github.com/libp2p/go-libp2p/core/event" + network "github.com/libp2p/go-libp2p/core/network" + peer "github.com/libp2p/go-libp2p/core/peer" + peerstore "github.com/libp2p/go-libp2p/core/peerstore" + protocol "github.com/libp2p/go-libp2p/core/protocol" + multiaddr "github.com/multiformats/go-multiaddr" + gomock "go.uber.org/mock/gomock" +) + +// MockHost is a mock of Host interface. +type MockHost struct { + ctrl *gomock.Controller + recorder *MockHostMockRecorder + isgomock struct{} +} + +// MockHostMockRecorder is the mock recorder for MockHost. +type MockHostMockRecorder struct { + mock *MockHost +} + +// NewMockHost creates a new mock instance. +func NewMockHost(ctrl *gomock.Controller) *MockHost { + mock := &MockHost{ctrl: ctrl} + mock.recorder = &MockHostMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHost) EXPECT() *MockHostMockRecorder { + return m.recorder +} + +// Addrs mocks base method. +func (m *MockHost) Addrs() []multiaddr.Multiaddr { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Addrs") + ret0, _ := ret[0].([]multiaddr.Multiaddr) + return ret0 +} + +// Addrs indicates an expected call of Addrs. +func (mr *MockHostMockRecorder) Addrs() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Addrs", reflect.TypeOf((*MockHost)(nil).Addrs)) +} + +// Close mocks base method. +func (m *MockHost) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockHostMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockHost)(nil).Close)) +} + +// ConnManager mocks base method. +func (m *MockHost) ConnManager() connmgr.ConnManager { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConnManager") + ret0, _ := ret[0].(connmgr.ConnManager) + return ret0 +} + +// ConnManager indicates an expected call of ConnManager. +func (mr *MockHostMockRecorder) ConnManager() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConnManager", reflect.TypeOf((*MockHost)(nil).ConnManager)) +} + +// Connect mocks base method. +func (m *MockHost) Connect(ctx context.Context, pi peer.AddrInfo) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Connect", ctx, pi) + ret0, _ := ret[0].(error) + return ret0 +} + +// Connect indicates an expected call of Connect. +func (mr *MockHostMockRecorder) Connect(ctx, pi any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockHost)(nil).Connect), ctx, pi) +} + +// EventBus mocks base method. +func (m *MockHost) EventBus() event.Bus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EventBus") + ret0, _ := ret[0].(event.Bus) + return ret0 +} + +// EventBus indicates an expected call of EventBus. +func (mr *MockHostMockRecorder) EventBus() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EventBus", reflect.TypeOf((*MockHost)(nil).EventBus)) +} + +// ID mocks base method. +func (m *MockHost) ID() peer.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(peer.ID) + return ret0 +} + +// ID indicates an expected call of ID. +func (mr *MockHostMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockHost)(nil).ID)) +} + +// Mux mocks base method. +func (m *MockHost) Mux() protocol.Switch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Mux") + ret0, _ := ret[0].(protocol.Switch) + return ret0 +} + +// Mux indicates an expected call of Mux. +func (mr *MockHostMockRecorder) Mux() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Mux", reflect.TypeOf((*MockHost)(nil).Mux)) +} + +// Network mocks base method. +func (m *MockHost) Network() network.Network { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Network") + ret0, _ := ret[0].(network.Network) + return ret0 +} + +// Network indicates an expected call of Network. +func (mr *MockHostMockRecorder) Network() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Network", reflect.TypeOf((*MockHost)(nil).Network)) +} + +// NewStream mocks base method. +func (m *MockHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (network.Stream, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, p} + for _, a := range pids { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "NewStream", varargs...) + ret0, _ := ret[0].(network.Stream) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NewStream indicates an expected call of NewStream. +func (mr *MockHostMockRecorder) NewStream(ctx, p any, pids ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, p}, pids...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewStream", reflect.TypeOf((*MockHost)(nil).NewStream), varargs...) +} + +// Peerstore mocks base method. +func (m *MockHost) Peerstore() peerstore.Peerstore { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Peerstore") + ret0, _ := ret[0].(peerstore.Peerstore) + return ret0 +} + +// Peerstore indicates an expected call of Peerstore. +func (mr *MockHostMockRecorder) Peerstore() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Peerstore", reflect.TypeOf((*MockHost)(nil).Peerstore)) +} + +// RemoveStreamHandler mocks base method. +func (m *MockHost) RemoveStreamHandler(pid protocol.ID) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RemoveStreamHandler", pid) +} + +// RemoveStreamHandler indicates an expected call of RemoveStreamHandler. +func (mr *MockHostMockRecorder) RemoveStreamHandler(pid any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveStreamHandler", reflect.TypeOf((*MockHost)(nil).RemoveStreamHandler), pid) +} + +// SetStreamHandler mocks base method. +func (m *MockHost) SetStreamHandler(pid protocol.ID, handler network.StreamHandler) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetStreamHandler", pid, handler) +} + +// SetStreamHandler indicates an expected call of SetStreamHandler. +func (mr *MockHostMockRecorder) SetStreamHandler(pid, handler any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStreamHandler", reflect.TypeOf((*MockHost)(nil).SetStreamHandler), pid, handler) +} + +// SetStreamHandlerMatch mocks base method. +func (m *MockHost) SetStreamHandlerMatch(arg0 protocol.ID, arg1 func(protocol.ID) bool, arg2 network.StreamHandler) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetStreamHandlerMatch", arg0, arg1, arg2) +} + +// SetStreamHandlerMatch indicates an expected call of SetStreamHandlerMatch. +func (mr *MockHostMockRecorder) SetStreamHandlerMatch(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStreamHandlerMatch", reflect.TypeOf((*MockHost)(nil).SetStreamHandlerMatch), arg0, arg1, arg2) +} diff --git a/mocks/mock_p2p_client.go b/mocks/mock_p2p_client.go new file mode 100644 index 0000000000..d6f8cf36c2 --- /dev/null +++ b/mocks/mock_p2p_client.go @@ -0,0 +1,122 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/NethermindEth/juno/p2p/sync (interfaces: Client) +// +// Generated by this command: +// +// mockgen -destination=../../mocks/mock_p2p_client.go -package=mocks github.com/NethermindEth/juno/p2p/sync Client +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + iter "iter" + reflect "reflect" + + class "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/class" + event "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/event" + header "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/header" + state "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/state" + transaction "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/transaction" + gomock "go.uber.org/mock/gomock" +) + +// MockClient is a mock of Client interface. +type MockClient struct { + ctrl *gomock.Controller + recorder *MockClientMockRecorder + isgomock struct{} +} + +// MockClientMockRecorder is the mock recorder for MockClient. +type MockClientMockRecorder struct { + mock *MockClient +} + +// NewMockClient creates a new mock instance. +func NewMockClient(ctrl *gomock.Controller) *MockClient { + mock := &MockClient{ctrl: ctrl} + mock.recorder = &MockClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockClient) EXPECT() *MockClientMockRecorder { + return m.recorder +} + +// RequestBlockHeaders mocks base method. +func (m *MockClient) RequestBlockHeaders(ctx context.Context, req *header.BlockHeadersRequest) (iter.Seq[*header.BlockHeadersResponse], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestBlockHeaders", ctx, req) + ret0, _ := ret[0].(iter.Seq[*header.BlockHeadersResponse]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RequestBlockHeaders indicates an expected call of RequestBlockHeaders. +func (mr *MockClientMockRecorder) RequestBlockHeaders(ctx, req any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestBlockHeaders", reflect.TypeOf((*MockClient)(nil).RequestBlockHeaders), ctx, req) +} + +// RequestClasses mocks base method. +func (m *MockClient) RequestClasses(ctx context.Context, req *class.ClassesRequest) (iter.Seq[*class.ClassesResponse], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestClasses", ctx, req) + ret0, _ := ret[0].(iter.Seq[*class.ClassesResponse]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RequestClasses indicates an expected call of RequestClasses. +func (mr *MockClientMockRecorder) RequestClasses(ctx, req any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestClasses", reflect.TypeOf((*MockClient)(nil).RequestClasses), ctx, req) +} + +// RequestEvents mocks base method. +func (m *MockClient) RequestEvents(ctx context.Context, req *event.EventsRequest) (iter.Seq[*event.EventsResponse], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestEvents", ctx, req) + ret0, _ := ret[0].(iter.Seq[*event.EventsResponse]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RequestEvents indicates an expected call of RequestEvents. +func (mr *MockClientMockRecorder) RequestEvents(ctx, req any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestEvents", reflect.TypeOf((*MockClient)(nil).RequestEvents), ctx, req) +} + +// RequestStateDiffs mocks base method. +func (m *MockClient) RequestStateDiffs(ctx context.Context, req *state.StateDiffsRequest) (iter.Seq[*state.StateDiffsResponse], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestStateDiffs", ctx, req) + ret0, _ := ret[0].(iter.Seq[*state.StateDiffsResponse]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RequestStateDiffs indicates an expected call of RequestStateDiffs. +func (mr *MockClientMockRecorder) RequestStateDiffs(ctx, req any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestStateDiffs", reflect.TypeOf((*MockClient)(nil).RequestStateDiffs), ctx, req) +} + +// RequestTransactions mocks base method. +func (m *MockClient) RequestTransactions(ctx context.Context, req *transaction.TransactionsRequest) (iter.Seq[*transaction.TransactionsResponse], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestTransactions", ctx, req) + ret0, _ := ret[0].(iter.Seq[*transaction.TransactionsResponse]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RequestTransactions indicates an expected call of RequestTransactions. +func (mr *MockClientMockRecorder) RequestTransactions(ctx, req any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestTransactions", reflect.TypeOf((*MockClient)(nil).RequestTransactions), ctx, req) +} diff --git a/p2p/sync/client.go b/p2p/sync/client.go index d0dde4182d..38cbe4cbee 100644 --- a/p2p/sync/client.go +++ b/p2p/sync/client.go @@ -26,14 +26,23 @@ const ( type NewStreamFunc func(ctx context.Context, pids ...protocol.ID) (network.Stream, error) -type Client struct { +//go:generate mockgen -destination=../../mocks/mock_p2p_client.go -package=mocks github.com/NethermindEth/juno/p2p/sync Client +type Client interface { + RequestBlockHeaders(ctx context.Context, req *header.BlockHeadersRequest) (iter.Seq[*header.BlockHeadersResponse], error) + RequestTransactions(ctx context.Context, req *synctransaction.TransactionsRequest) (iter.Seq[*synctransaction.TransactionsResponse], error) + RequestEvents(ctx context.Context, req *event.EventsRequest) (iter.Seq[*event.EventsResponse], error) + RequestClasses(ctx context.Context, req *syncclass.ClassesRequest) (iter.Seq[*syncclass.ClassesResponse], error) + RequestStateDiffs(ctx context.Context, req *state.StateDiffsRequest) (iter.Seq[*state.StateDiffsResponse], error) +} + +type client struct { newStream NewStreamFunc network *utils.Network log utils.SimpleLogger } -func NewClient(newStream NewStreamFunc, snNetwork *utils.Network, log utils.SimpleLogger) *Client { - return &Client{ +func NewClient(newStream NewStreamFunc, snNetwork *utils.Network, log utils.SimpleLogger) Client { + return &client{ newStream: newStream, network: snNetwork, log: log, @@ -106,26 +115,26 @@ func requestAndReceiveStream[ReqT proto.Message, ResT proto.Message](ctx context }, nil } -func (c *Client) RequestBlockHeaders( +func (c *client) RequestBlockHeaders( ctx context.Context, req *header.BlockHeadersRequest, ) (iter.Seq[*header.BlockHeadersResponse], error) { return requestAndReceiveStream[*header.BlockHeadersRequest, *header.BlockHeadersResponse]( ctx, c.newStream, HeadersPID(), req, c.log) } -func (c *Client) RequestEvents(ctx context.Context, req *event.EventsRequest) (iter.Seq[*event.EventsResponse], error) { +func (c *client) RequestEvents(ctx context.Context, req *event.EventsRequest) (iter.Seq[*event.EventsResponse], error) { return requestAndReceiveStream[*event.EventsRequest, *event.EventsResponse](ctx, c.newStream, EventsPID(), req, c.log) } -func (c *Client) RequestClasses(ctx context.Context, req *syncclass.ClassesRequest) (iter.Seq[*syncclass.ClassesResponse], error) { +func (c *client) RequestClasses(ctx context.Context, req *syncclass.ClassesRequest) (iter.Seq[*syncclass.ClassesResponse], error) { return requestAndReceiveStream[*syncclass.ClassesRequest, *syncclass.ClassesResponse](ctx, c.newStream, ClassesPID(), req, c.log) } -func (c *Client) RequestStateDiffs(ctx context.Context, req *state.StateDiffsRequest) (iter.Seq[*state.StateDiffsResponse], error) { +func (c *client) RequestStateDiffs(ctx context.Context, req *state.StateDiffsRequest) (iter.Seq[*state.StateDiffsResponse], error) { return requestAndReceiveStream[*state.StateDiffsRequest, *state.StateDiffsResponse](ctx, c.newStream, StateDiffPID(), req, c.log) } -func (c *Client) RequestTransactions( +func (c *client) RequestTransactions( ctx context.Context, req *synctransaction.TransactionsRequest, ) (iter.Seq[*synctransaction.TransactionsResponse], error) { diff --git a/p2p/sync/sync.go b/p2p/sync/sync.go index 7de1aaba06..b957984997 100644 --- a/p2p/sync/sync.go +++ b/p2p/sync/sync.go @@ -32,10 +32,12 @@ import ( "go.uber.org/zap" ) +//go:generate mockgen -destination=../../mocks/mock_host.go -package=mocks github.com/libp2p/go-libp2p/core/host Host + type Service struct { host host.Host network *utils.Network - client *Client // todo: merge all the functionality of Client with p2p SyncService + client Client // todo: merge all the functionality of Client with p2p SyncService blockchain *blockchain.Blockchain listener junoSync.EventListener @@ -43,25 +45,32 @@ type Service struct { } func New(bc *blockchain.Blockchain, h host.Host, n *utils.Network, log utils.SimpleLogger) *Service { - return &Service{ + service := Service{ host: h, network: n, blockchain: bc, log: log, listener: &junoSync.SelectiveListener{}, } + + service.client = NewClient(service.randomPeerStream, n, log) + return &service +} + +// Useful for tests +func (s *Service) WithClient(client Client) { + s.client = client } func (s *Service) Run(ctx context.Context) { ctx, cancel := context.WithCancel(ctx) defer cancel() - s.client = NewClient(s.randomPeerStream, s.network, s.log) - for i := 0; ; i++ { if err := ctx.Err(); err != nil { break } + s.log.Debugw("Continuous iteration", "i", i) iterCtx, cancelIteration := context.WithCancel(ctx) @@ -129,7 +138,6 @@ func (s *Service) processBlock(ctx context.Context, blockNumber uint64) error { pipeline.Stage(ctx, txsCh, specBlockPartsFunc[specTxWithReceipts]), pipeline.Stage(ctx, eventsCh, specBlockPartsFunc[specEvents]), ))) - for b := range blocksCh { if b.err != nil { return fmt.Errorf("failed to process block: %w", b.err) diff --git a/p2p/sync/sync_test.go b/p2p/sync/sync_test.go new file mode 100644 index 0000000000..b39cbef42e --- /dev/null +++ b/p2p/sync/sync_test.go @@ -0,0 +1,188 @@ +package sync + +import ( + "context" + "errors" + "iter" + "testing" + "time" + + "github.com/NethermindEth/juno/blockchain" + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/db/memory" + "github.com/NethermindEth/juno/mocks" + "github.com/NethermindEth/juno/utils" + common "github.com/starknet-io/starknet-p2pspecs/p2p/proto/common" + syncclass "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/class" + synccommon "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/common" + "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/event" + "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/header" + "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/state" + synctransaction "github.com/starknet-io/starknet-p2pspecs/p2p/proto/sync/transaction" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +func TestSyncEmptyBlock(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + testDB := memory.New() + network := &utils.Mainnet + bc := blockchain.New(testDB, network) + host := mocks.NewMockHost(mockCtrl) + sync := New(bc, host, &utils.Sepolia, utils.NewNopZapLogger()) + client := mocks.NewMockClient(mockCtrl) + sync.WithClient(client) + + iter := &synccommon.Iteration{ + Start: &synccommon.Iteration_BlockNumber{BlockNumber: 0}, + Direction: synccommon.Iteration_Forward, + Limit: 1, + Step: 1, + } + + blockHeaderIter := NewBlockHeadersResponseSeq(t) + errNoBlock := errors.New("peer doesn't have this block") + client.EXPECT().RequestBlockHeaders(gomock.Any(), &header.BlockHeadersRequest{Iteration: iter}).Return(blockHeaderIter, nil) + client.EXPECT().RequestBlockHeaders(gomock.Any(), gomock.Any()).AnyTimes().Return(nil, errNoBlock) + + txIter := NewTransactionsResponseSeq() + client.EXPECT().RequestTransactions(gomock.Any(), &synctransaction.TransactionsRequest{Iteration: iter}).Return(txIter, nil) + + classesIter := NewClassesResponseSeq() + client.EXPECT().RequestClasses(gomock.Any(), &syncclass.ClassesRequest{Iteration: iter}).Return(classesIter, nil) + + eventsIter := NewEventsResponseSeq() + client.EXPECT().RequestEvents(gomock.Any(), &event.EventsRequest{Iteration: iter}).Return(eventsIter, nil) + + stateDiffsIter := NewStateDiffsResponseSeq() + client.EXPECT().RequestStateDiffs(gomock.Any(), &state.StateDiffsRequest{Iteration: iter}).Return(stateDiffsIter, nil) + + ctx, cancel := context.WithCancel(t.Context()) + go func() { + time.Sleep(10 * time.Millisecond) + cancel() + }() + sync.Run(ctx) + + height, err := bc.Height() + require.NoError(t, err) + require.Equal(t, height, uint64(0)) +} + +// NewBlockHeadersResponseSeq returns an iter.Seq emitting one Header message followed by a Fin message. +func NewBlockHeadersResponseSeq(t *testing.T) iter.Seq[*header.BlockHeadersResponse] { + hdr := &header.SignedBlockHeader{ + BlockHash: toHash(utils.HexToFelt(t, "0x40a15319f25a679938dedd6c1e2815bcf5a4f8282cb5210add954f65438fec2")), + ParentHash: toHash(utils.HexToFelt(t, "0x0")), + Number: 0, + Time: 1_650_000_000, + SequencerAddress: toAddress(utils.HexToFelt(t, "0x046a89ae102987331d369645031b49c27738ed096f2789c24449966da4c6de6b")), + StateRoot: toHash(utils.HexToFelt(t, "0x0")), + StateDiffCommitment: &synccommon.StateDiffCommitment{ + StateDiffLength: 0, + Root: toHash(utils.HexToFelt(t, "0x0")), + }, + Transactions: &common.Patricia{ + NLeaves: 0, + Root: toHash(utils.HexToFelt(t, "0x0")), + }, + Events: &common.Patricia{ + NLeaves: 0, + Root: toHash(utils.HexToFelt(t, "0x0")), + }, + Receipts: toHash(utils.HexToFelt(t, "0x0")), + ProtocolVersion: "0.13.4", + L1GasPriceFri: toUint128(utils.HexToFelt(t, "0x3")), + L1GasPriceWei: toUint128(utils.HexToFelt(t, "0x3")), + L1DataGasPriceFri: toUint128(utils.HexToFelt(t, "0x3")), + L1DataGasPriceWei: toUint128(utils.HexToFelt(t, "0x3")), + L2GasPriceFri: toUint128(utils.HexToFelt(t, "0x3")), + L2GasPriceWei: toUint128(utils.HexToFelt(t, "0x3")), + L1DataAvailabilityMode: common.L1DataAvailabilityMode(0), + Signatures: nil, // Todo + } + + return func(yield func(*header.BlockHeadersResponse) bool) { + // send the header + headerMsg := &header.BlockHeadersResponse{ + HeaderMessage: &header.BlockHeadersResponse_Header{Header: hdr}, + } + if !yield(headerMsg) { + return + } + // send the Fin frame + finMsg := &header.BlockHeadersResponse{ + HeaderMessage: &header.BlockHeadersResponse_Fin{}, + } + yield(finMsg) + } +} + +// NewTransactionsResponseSeq returns an iter.Seq emitting one TransactionWithReceipt message followed by a Fin message. +func NewTransactionsResponseSeq() iter.Seq[*synctransaction.TransactionsResponse] { + // Empty block - no txns + return func(yield func(*synctransaction.TransactionsResponse) bool) { + // send the Fin frame + fin := &synctransaction.TransactionsResponse{ + TransactionMessage: &synctransaction.TransactionsResponse_Fin{}, + } + yield(fin) + } +} + +// NewEventsResponseSeq returns an iter.Seq emitting one Event message followed by a Fin message. +func NewEventsResponseSeq() iter.Seq[*event.EventsResponse] { + // Empty block - no events + return func(yield func(*event.EventsResponse) bool) { + // send the Fin frame + fin := &event.EventsResponse{ + EventMessage: &event.EventsResponse_Fin{}, + } + yield(fin) + } +} + +// NewClassesResponseSeq returns an iter.Seq emitting one Class message followed by a Fin message. +func NewClassesResponseSeq() iter.Seq[*syncclass.ClassesResponse] { + // Empty block - no classes + return func(yield func(*syncclass.ClassesResponse) bool) { + // send the Fin frame + fin := &syncclass.ClassesResponse{ + ClassMessage: &syncclass.ClassesResponse_Fin{}, + } + yield(fin) + } +} + +// NewStateDiffsResponseSeq returns an iter.Seq emitting one StateDiff message followed by a Fin message. +func NewStateDiffsResponseSeq() iter.Seq[*state.StateDiffsResponse] { + // Empty block - no contract or class was altered + return func(yield func(*state.StateDiffsResponse) bool) { + // send the Fin frame + fin := &state.StateDiffsResponse{ + StateDiffMessage: &state.StateDiffsResponse_Fin{}, + } + yield(fin) + } +} + +func toHash(felt *felt.Felt) *common.Hash { + feltBytes := felt.Bytes() + return &common.Hash{Elements: feltBytes[:]} +} + +func toAddress(felt *felt.Felt) *common.Address { + feltBytes := felt.Bytes() + return &common.Address{Elements: feltBytes[:]} +} + +func toUint128(f *felt.Felt) *common.Uint128 { + // bits represents value in little endian byte order + // i.e. first is least significant byte + bits := f.Bits() + return &common.Uint128{ + Low: bits[0], + High: bits[1], + } +} diff --git a/vm/rust/src/execution.rs b/vm/rust/src/execution.rs index 80bfe24ace..03b5860021 100644 --- a/vm/rust/src/execution.rs +++ b/vm/rust/src/execution.rs @@ -181,7 +181,7 @@ where { let initial_resource_bounds = extract_resource_bounds(transaction)?; let initial_gas_limit = initial_resource_bounds.l2_gas.max_amount; - + // Use balance-dependent limit only when charge_fee is enabled, // otherwise use blockifier's default limit to avoid the account balance issue let max_l2_gas_limit = if get_execution_flags(transaction).charge_fee {