diff --git a/rpc/rpc_server.go b/rpc/rpc_server.go index 4648d08..121a9d8 100644 --- a/rpc/rpc_server.go +++ b/rpc/rpc_server.go @@ -24,6 +24,8 @@ import ( var _ protobuff.ArchiveServiceServer = &Server{} +var emptyTd = &protobuff.TickData{} + type Server struct { protobuff.UnimplementedArchiveServiceServer listenAddrGRPC string @@ -52,6 +54,10 @@ func (s *Server) GetTickData(ctx context.Context, req *protobuff.GetTickDataRequ return nil, status.Errorf(codes.Internal, "getting tick data: %v", err) } + if tickData == emptyTd { + tickData = nil + } + return &protobuff.GetTickDataResponse{TickData: tickData}, nil } func (s *Server) GetTickTransactions(ctx context.Context, req *protobuff.GetTickTransactionsRequest) (*protobuff.GetTickTransactionsResponse, error) { diff --git a/rpc/rpc_server_test.go b/rpc/rpc_server_test.go new file mode 100644 index 0000000..2f55f70 --- /dev/null +++ b/rpc/rpc_server_test.go @@ -0,0 +1,7 @@ +package rpc + +import "testing" + +func Test_Server_GetTickData(t *testing.T) { + +} diff --git a/store/store.go b/store/store.go index e10d68c..c1c1cd4 100644 --- a/store/store.go +++ b/store/store.go @@ -38,7 +38,7 @@ func (s *PebbleStore) GetTickData(ctx context.Context, tickNumber uint64) (*prot defer closer.Close() var td protobuff.TickData - if err := proto.Unmarshal(value, &td); err != nil { + if err := protojson.Unmarshal(value, &td); err != nil { return nil, errors.Wrap(err, "unmarshalling tick data to protobuff type") } @@ -47,7 +47,7 @@ func (s *PebbleStore) GetTickData(ctx context.Context, tickNumber uint64) (*prot func (s *PebbleStore) SetTickData(ctx context.Context, tickNumber uint64, td *protobuff.TickData) error { key := tickDataKey(tickNumber) - serialized, err := proto.Marshal(td) + serialized, err := protojson.Marshal(td) if err != nil { return errors.Wrap(err, "serializing td proto") } diff --git a/store/store_test.go b/store/store_test.go index 6026ed0..45f0926 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -5,7 +5,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" "os" "path/filepath" "testing" @@ -30,49 +29,93 @@ func TestPebbleStore_TickData(t *testing.T) { logger, _ := zap.NewDevelopment() store := NewPebbleStore(db, logger) - // Create multiple TickData records - tickDatas := []*pb.TickData{ + tcs := []struct { + name string + td *pb.TickData + exp *pb.TickData + tickNumber uint64 + }{ { - ComputorIndex: 1, - Epoch: 1, - TickNumber: 101, - Timestamp: 1596240001, - SignatureHex: "signature1", + name: "TestTickData_1", + tickNumber: 101, + td: &pb.TickData{ + ComputorIndex: 1, + Epoch: 1, + TickNumber: 101, + Timestamp: 1596240001, + SignatureHex: "signature1", + }, + exp: &pb.TickData{ + ComputorIndex: 1, + Epoch: 1, + TickNumber: 101, + Timestamp: 1596240001, + SignatureHex: "signature1", + }, }, { - ComputorIndex: 2, - Epoch: 2, - TickNumber: 102, - Timestamp: 1596240002, - SignatureHex: "signature2", + name: "TestTickData_2", + tickNumber: 102, + td: &pb.TickData{ + ComputorIndex: 2, + Epoch: 2, + TickNumber: 102, + Timestamp: 1596240002, + SignatureHex: "signature2", + }, + exp: &pb.TickData{ + ComputorIndex: 2, + Epoch: 2, + TickNumber: 102, + Timestamp: 1596240002, + SignatureHex: "signature2", + }, }, { - ComputorIndex: 3, - Epoch: 3, - TickNumber: 103, - Timestamp: 1596240003, - SignatureHex: "signature3", + name: "TestTickData_3", + tickNumber: 103, + td: &pb.TickData{ + ComputorIndex: 3, + Epoch: 3, + TickNumber: 103, + Timestamp: 1596240003, + SignatureHex: "signature3", + }, + exp: &pb.TickData{ + ComputorIndex: 3, + Epoch: 3, + TickNumber: 103, + Timestamp: 1596240003, + SignatureHex: "signature3", + }, + }, + { + name: "TestTickData_nil", + tickNumber: 104, + td: nil, + exp: &pb.TickData{}, }, } - // Insert TickData records - for _, td := range tickDatas { - err = store.SetTickData(ctx, uint64(td.TickNumber), td) - require.NoError(t, err, "Failed to store TickData") - } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + err := store.SetTickData(ctx, tc.tickNumber, tc.td) + require.NoError(t, err) - // Retrieve and verify each TickData record - for _, tdOriginal := range tickDatas { - retrievedTickData, err := store.GetTickData(ctx, uint64(tdOriginal.TickNumber)) - require.NoError(t, err, "Failed to retrieve TickData") - ok := proto.Equal(tdOriginal, retrievedTickData) - require.Equal(t, true, ok, "Retrieved TickData does not match original") + retrievedTickData, err := store.GetTickData(ctx, tc.tickNumber) + require.NoError(t, err) + + if diff := cmp.Diff(tc.exp, retrievedTickData, cmpopts.IgnoreUnexported(pb.TickData{})); diff != "" { + t.Fatalf("Unexpected result: %v", diff) + } + }) } // Test error handling for non-existent TickData _, err = store.GetTickData(ctx, 999) // Assuming 999 is a tick number that wasn't stored require.Error(t, err, "Expected an error for non-existent TickData") require.Equal(t, ErrNotFound, err, "Expected ErrNotFound for non-existent TickData") + } func TestPebbleStore_QuorumTickData(t *testing.T) { diff --git a/validator/qchain/models.go b/validator/qchain/models.go index 3245c42..da01e66 100644 --- a/validator/qchain/models.go +++ b/validator/qchain/models.go @@ -6,6 +6,7 @@ import ( ) type QChain struct { + _ uint16 //padding Epoch uint16 Tick uint32 Millisecond uint16 @@ -25,7 +26,7 @@ type QChain struct { } func (q *QChain) Digest() ([32]byte, error) { - b, err := utils.BinarySerialize(q) + b, err := q.MarshallBinary() if err != nil { return [32]byte{}, errors.Wrap(err, "serializing vote") } @@ -37,3 +38,12 @@ func (q *QChain) Digest() ([32]byte, error) { return digest, nil } + +func (q *QChain) MarshallBinary() ([]byte, error) { + b, err := utils.BinarySerialize(q) + if err != nil { + return nil, errors.Wrap(err, "serializing vote") + } + + return b, nil +} diff --git a/validator/qchain/qchain_test.go b/validator/qchain/qchain_test.go index fed9056..e473e63 100644 --- a/validator/qchain/qchain_test.go +++ b/validator/qchain/qchain_test.go @@ -25,3 +25,25 @@ func TestQChain_Digest(t *testing.T) { _, err := qChain.Digest() require.NoError(t, err) } + +func TestQChain_MarshallBinary(t *testing.T) { + qChain := QChain{ + Epoch: 20, + Tick: 30, + Millisecond: 40, + Second: 50, + Minute: 60, + Hour: 70, + Day: 80, + Month: 90, + Year: 10, + PreviousResourceTestingDigest: 13423432, + PreviousSpectrumDigest: [32]byte{}, + PreviousUniverseDigest: [32]byte{}, + PreviousComputerDigest: [32]byte{}, + TxDigest: [32]byte{}, + } + b, err := qChain.MarshallBinary() + require.NoError(t, err) + require.Equal(t, len(b), 184) +} diff --git a/validator/tick/models.go b/validator/tick/models.go index 2f43b6e..d936713 100644 --- a/validator/tick/models.go +++ b/validator/tick/models.go @@ -9,6 +9,10 @@ import ( ) func qubicToProto(tickData types.TickData) (*protobuff.TickData, error) { + if tickData.IsEmpty() { + return nil, nil + } + date := time.Date(2000+int(tickData.Year), time.Month(tickData.Month), int(tickData.Day), int(tickData.Hour), int(tickData.Minute), int(tickData.Second), 0, time.UTC) timestamp := date.UnixMilli() + int64(tickData.Millisecond) transactionIds, err := digestsToIdentities(tickData.TransactionDigests) diff --git a/validator/tick/models_test.go b/validator/tick/models_test.go index bc0c566..0e386a8 100644 --- a/validator/tick/models_test.go +++ b/validator/tick/models_test.go @@ -95,6 +95,14 @@ func TestQubicToProto(t *testing.T) { if diff := cmp.Diff(got, &expectedProtoTickData, cmpopts.IgnoreUnexported(protobuff.TickData{})); diff != "" { t.Fatalf("qubicToProto() mismatch (-got +want):\n%s", diff) } + + got, err = qubicToProto(types.TickData{}) + if err != nil { + t.Fatalf("qubicToProto() unexpected error: %v", err) + } + if got != nil { + t.Fatalf("should have get a nil proto model for an empty tick data") + } } func fillStringTo(nrChars int, value string) string { diff --git a/validator/tick/validator.go b/validator/tick/validator.go index 71e90d1..86fceb7 100644 --- a/validator/tick/validator.go +++ b/validator/tick/validator.go @@ -77,11 +77,6 @@ func getFullDigestFromTickData(data types.TickData) ([32]byte, error) { } func Store(ctx context.Context, store *store.PebbleStore, tickNumber uint64, tickData types.TickData) error { - // if tick data is empty, don't store it - if tickData.IsEmpty() { - return nil - } - protoTickData, err := qubicToProto(tickData) if err != nil { return errors.Wrap(err, "converting qubic tick data to proto")