diff --git a/blockchain/serviceMetadata.go b/blockchain/serviceMetadata.go index 165066b1..9656a0c2 100644 --- a/blockchain/serviceMetadata.go +++ b/blockchain/serviceMetadata.go @@ -4,8 +4,10 @@ import ( "context" "encoding/json" "fmt" + "github.com/singnet/snet-daemon/v5/errs" "math/big" "os" + "slices" "strings" "github.com/bufbuild/protocompile" @@ -253,15 +255,15 @@ func ServiceMetaData() *ServiceMetadata { var metadata *ServiceMetadata var err error if config.GetBool(config.BlockchainEnabledKey) { - ipfsHash := string(getServiceMetaDataUrifromRegistry()) + ipfsHash := string(getServiceMetaDataURIfromRegistry()) metadata, err = GetServiceMetaDataFromIPFS(ipfsHash) if err != nil { - zap.L().Panic("error on determining service metadata from file", zap.Error(err)) + zap.L().Panic("error on determining service metadata from file"+errs.ErrDescURL(errs.InvalidMetadata), zap.Error(err)) } } else { metadata = &ServiceMetadata{Encoding: "proto", ServiceType: "grpc"} } - zap.L().Debug("service_type: " + metadata.GetServiceType()) + zap.L().Debug("service type: " + metadata.GetServiceType()) return metadata } @@ -300,7 +302,7 @@ func GetRegistryFilterer(ethWsClient *ethclient.Client) *RegistryFilterer { return reg } -func getServiceMetaDataUrifromRegistry() []byte { +func getServiceMetaDataURIfromRegistry() []byte { reg := getRegistryCaller() orgId := StringToBytes32(config.GetString(config.OrganizationId)) @@ -408,7 +410,7 @@ func setFreeCallData(metaData *ServiceMetadata) error { metaData.freeCallsAllowed = metaData.defaultGroup.FreeCalls //If the signer address is not a valid address, then return back an error if !common.IsHexAddress(metaData.defaultGroup.FreeCallSigner) { - return fmt.Errorf("MetaData does not have 'free_call_signer_address defined correctly") + return fmt.Errorf("MetaData does not have 'free_call_signer_address defined correctly" + errs.ErrDescURL(errs.InvalidMetadata)) } metaData.freeCallSignerAddress = common.HexToAddress(ToChecksumAddress(metaData.defaultGroup.FreeCallSigner)) } @@ -453,10 +455,10 @@ func (metaData *ServiceMetadata) GetLicenses() Licenses { // methodFullName , ex "/example_service.Calculator/add" func (metaData *ServiceMetadata) GetDynamicPricingMethodAssociated(methodFullName string) (pricingMethod string, isDynamicPricingEligible bool) { - //Check if Method Level Options are defined , for the given Service and method, - //If Defined check if its in the format supported , then return the full method Name + // Check if Method Level Options are defined, for the given Service and method, + // If Defined check if it's in the format supported, then return the full method Name // i.e /package.service/method format , this will be directly fed in to the grpc called to made to - //determine dynamic pricing + // determine dynamic pricing if !config.GetBool(config.EnableDynamicPricing) { return } @@ -469,23 +471,12 @@ func (metaData *ServiceMetadata) GetDynamicPricingMethodAssociated(methodFullNam return } -// methodFullName , ex "/example_service.Calculator/add" +// IsModelTraining methodFullName , ex "/example_service.Calculator/add" func (metaData *ServiceMetadata) IsModelTraining(methodFullName string) (useModelTrainingEndPoint bool) { - if !config.GetBool(config.ModelTrainingEnabled) { return false } - useModelTrainingEndPoint = isElementInArray(methodFullName, metaData.TrainingMethods) - return -} - -func isElementInArray(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false + return slices.Contains(metaData.TrainingMethods, methodFullName) } func setServiceProto(metaData *ServiceMetadata) (err error) { @@ -594,8 +585,8 @@ func getFileDescriptor(protoContent string) protoreflect.FileDescriptor { SourceInfoMode: protocompile.SourceInfoStandard, } fds, err := compiler.Compile(context.Background(), serviceProto) - if err != nil { - zap.L().Error(err.Error()) + if err != nil || fds == nil { + zap.L().Fatal("failed to analyze protofile"+errs.ErrDescURL(errs.InvalidProto), zap.Error(err)) } return fds.FindFileByPath(serviceProto) } diff --git a/blockchain/serviceMetadata_test.go b/blockchain/serviceMetadata_test.go index 8d2357ee..44dd0496 100644 --- a/blockchain/serviceMetadata_test.go +++ b/blockchain/serviceMetadata_test.go @@ -3,6 +3,7 @@ package blockchain import ( "fmt" "math/big" + "slices" "strings" "testing" @@ -58,6 +59,7 @@ func TestTiers(t *testing.T) { assert.Equal(t, metaData.GetLicenses().Tiers[0].Range[0].DiscountInPercentage, 1.0) } + func TestInitServiceMetaDataFromJson(t *testing.T) { //Parse Bad JSON _, err := InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "{", "", 1))) @@ -68,7 +70,7 @@ func TestInitServiceMetaDataFromJson(t *testing.T) { //Parse Bad JSON _, err = InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "0x7DF35C98f41F3Af0df1dc4c7F7D4C19a71Dd059F", "", 1))) if err != nil { - assert.Equal(t, err.Error(), "MetaData does not have 'free_call_signer_address defined correctly") + assert.Contains(t, err.Error(), "MetaData does not have 'free_call_signer_address defined correctly") } _, err = InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "default_pricing", "dummy", 1))) if err != nil { @@ -84,11 +86,10 @@ func TestReadServiceMetaDataFromLocalFile(t *testing.T) { } func Test_getServiceMetaDataUrifromRegistry(t *testing.T) { - assert.Panics(t, func() { getServiceMetaDataUrifromRegistry() }) + assert.Panics(t, func() { getServiceMetaDataURIfromRegistry() }) config.Vip().Set(config.BlockChainNetworkSelected, "sepolia") config.Validate() - assert.Panics(t, func() { getServiceMetaDataUrifromRegistry() }) - + assert.Panics(t, func() { getServiceMetaDataURIfromRegistry() }) } func Test_setDefaultPricing(t *testing.T) { @@ -112,7 +113,7 @@ func TestServiceMetadata_parseServiceProto(t *testing.T) { assert.NotNil(t, priceMethodMap) assert.NotNil(t, trainingMethods) dynamicPriceMethod, ok := priceMethodMap["/example_service.Calculator/add"] - isTrainingMethod := isElementInArray("/example_service.Calculator/train_add", trainingMethods) + isTrainingMethod := slices.Contains(trainingMethods, "/example_service.Calculator/train_add") assert.Equal(t, dynamicPriceMethod, "/example_service.Calculator/dynamic_pricing_add") assert.True(t, ok, "true") assert.True(t, isTrainingMethod) diff --git a/config/config.go b/config/config.go index 9953d5b0..a48bb489 100644 --- a/config/config.go +++ b/config/config.go @@ -200,6 +200,7 @@ func Validate() error { switch dType := vip.GetString(DaemonTypeKey); dType { case "grpc": case "http": + zap.L().Warn("daemon type http is not for production mode, be careful") default: return fmt.Errorf("unrecognized DAEMON_TYPE '%+v'", dType) } diff --git a/contract_event_listener/listen_organization_metadata_changing.go b/contract_event_listener/listen_organization_metadata_changing.go index 86effc10..81c10d30 100644 --- a/contract_event_listener/listen_organization_metadata_changing.go +++ b/contract_event_listener/listen_organization_metadata_changing.go @@ -13,7 +13,7 @@ import ( ) func (l *ContractEventListener) ListenOrganizationMetadataChanging() { - zap.L().Info("Starting contract event listener for organization metadata changing") + zap.L().Debug("Starting contract event listener for organization metadata changing") watchOpts := &bind.WatchOpts{ Start: nil, @@ -29,7 +29,7 @@ func (l *ContractEventListener) ListenOrganizationMetadataChanging() { sub, err := registryFilterer.WatchOrganizationModified(watchOpts, eventContractChannel, orgIdFilter) if err != nil { - zap.L().Fatal("Failed to subscribe to logs", zap.Error(err)) + zap.L().Error("Failed to subscribe to logs", zap.Error(err)) } for { diff --git a/errs/errs.go b/errs/errs.go new file mode 100644 index 00000000..91906da5 --- /dev/null +++ b/errs/errs.go @@ -0,0 +1,22 @@ +package errs + +import ( + "fmt" +) + +const devPortalURL = "https://dev.singularitynet.io/docs/products/DecentralizedAIPlatform/Daemon/error-codes/#_" + +const ( + _ = iota + ServiceUnavailable + InvalidMetadata + InvalidProto + HTTPRequestBuildError + InvalidServiceCredentials + InvalidConfig + ReceiveMsgError +) + +func ErrDescURL(code int) string { + return fmt.Sprintf("\nAbout error & possible fixes: %s%d", devPortalURL, code) +} diff --git a/escrow/free_call_storage.go b/escrow/free_call_storage.go index 6ea51c00..aed3a5dc 100644 --- a/escrow/free_call_storage.go +++ b/escrow/free_call_storage.go @@ -35,6 +35,7 @@ func serializeFreeCallKey(key any) (serialized string, err error) { myKey := key.(*FreeCallUserKey) return myKey.String(), nil } + func (storage *FreeCallUserStorage) Get(key *FreeCallUserKey) (state *FreeCallUserData, ok bool, err error) { value, ok, err := storage.delegate.Get(key) if err != nil || !ok { diff --git a/handler/grpc.go b/handler/grpc.go index 57e65e1a..d6a5fa34 100644 --- a/handler/grpc.go +++ b/handler/grpc.go @@ -4,6 +4,9 @@ import ( "bytes" "context" "encoding/json" + "errors" + "fmt" + "github.com/singnet/snet-daemon/v5/errs" "io" "net/http" "net/url" @@ -39,7 +42,7 @@ type grpcHandler struct { modelTrainingEndpoint string executable string serviceMetaData *blockchain.ServiceMetadata - serviceCredentials []serviceCredential + serviceCredentials serviceCredentials } func (g grpcHandler) GrpcConn(isModelTraining bool) *grpc.ClientConn { @@ -78,10 +81,14 @@ func NewGrpcHandler(serviceMetadata *blockchain.ServiceMetadata) grpc.StreamHand case "jsonrpc": return h.grpcToJSONRPC case "http": - h.serviceCredentials = []serviceCredential{} + h.serviceCredentials = serviceCredentials{} err := config.Vip().UnmarshalKey(config.ServiceCredentialsKey, &h.serviceCredentials) if err != nil { - zap.L().Panic("invalid config", zap.Error(err)) + zap.L().Fatal("invalid config", zap.Error(fmt.Errorf("%v%v", err, errs.ErrDescURL(errs.InvalidServiceCredentials)))) + } + err = h.serviceCredentials.validate() + if err != nil { + zap.L().Fatal("invalid config", zap.Error(fmt.Errorf("%v%v", err, errs.ErrDescURL(errs.InvalidServiceCredentials)))) } return h.grpcToHTTP case "process": @@ -90,10 +97,24 @@ func NewGrpcHandler(serviceMetadata *blockchain.ServiceMetadata) grpc.StreamHand return nil } +func (srvCreds serviceCredentials) validate() error { + if len(srvCreds) > 0 { + for _, v := range srvCreds { + if v.Location != body && v.Location != header && v.Location != query { + return fmt.Errorf("invalid service_credentials: location should be body, header or query") + } + if v.Key == "" { + return fmt.Errorf("invalid service_credentials: key can't be empty") + } + } + } + return nil +} + func (g grpcHandler) getConnection(endpoint string) (conn *grpc.ClientConn) { passthroughURL, err := url.Parse(endpoint) if err != nil { - zap.L().Panic("error parsing passthrough endpoint", zap.Error(err)) + zap.L().Fatal(fmt.Sprintf("can't parse endpoint %v", errs.ErrDescURL(errs.InvalidConfig)), zap.String("endpoint", endpoint)) } if strings.Compare(passthroughURL.Scheme, "https") == 0 { conn, err = grpc.NewClient(passthroughURL.Host, @@ -101,13 +122,13 @@ func (g grpcHandler) getConnection(endpoint string) (conn *grpc.ClientConn) { if err != nil { zap.L().Panic("error dialing service", zap.Error(err)) } - } else { - conn, err = grpc.NewClient(passthroughURL.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), g.options) - if err != nil { - zap.L().Panic("error dialing service", zap.Error(err)) - } + return conn } - return + conn, err = grpc.NewClient(passthroughURL.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), g.options) + if err != nil { + zap.L().Panic("error dialing service", zap.Error(err)) + } + return conn } /* @@ -117,14 +138,12 @@ Modifications Copyright 2018 SingularityNET Foundation. All Rights Reserved. See */ func (g grpcHandler) grpcToGRPC(srv any, inStream grpc.ServerStream) error { method, ok := grpc.MethodFromServerStream(inStream) - if !ok { return status.Errorf(codes.Internal, "could not determine method from server stream") } inCtx := inStream.Context() md, ok := metadata.FromIncomingContext(inCtx) - if !ok { return status.Errorf(codes.Internal, "could not get metadata from incoming context") } @@ -135,7 +154,7 @@ func (g grpcHandler) grpcToGRPC(srv any, inStream grpc.ServerStream) error { isModelTraining := g.serviceMetaData.IsModelTraining(method) outStream, err := g.GrpcConn(isModelTraining).NewStream(outCtx, grpcDesc, method, grpc.CallContentSubtype(g.enc)) if err != nil { - return err + return status.Errorf(codes.Internal, "can't connect to service %v%v", err, errs.ErrDescURL(errs.ServiceUnavailable)) } s2cErrChan := forwardServerToClient(inStream, outStream) @@ -147,14 +166,17 @@ func (g grpcHandler) grpcToGRPC(srv any, inStream grpc.ServerStream) error { if s2cErr == io.EOF { // this is the happy case where the sender has encountered io.EOF, and won't be sending anymore./ // the clientStream>inStream may continue pumping though. - outStream.CloseSend() + errCloseSend := outStream.CloseSend() + if errCloseSend != nil { + zap.L().Debug("failed close outStream", zap.Error(err)) + } break } else { // however, we may have gotten a receive error (stream disconnected, a read error etc) in which case we need // to cancel the clientStream to the backend, let all of its goroutines be freed up by the CancelFunc and // exit with an error to the stack outCancel() - return status.Errorf(codes.Internal, "failed proxying s2c: %v", s2cErr) + return status.Errorf(codes.Internal, "failed proxying s2c: %v%s", s2cErr, errs.ErrDescURL(errs.ServiceUnavailable)) } case c2sErr := <-c2sErrChan: // This happens when the clientStream has nothing else to offer (io.EOF), returned a gRPC error. In those two @@ -256,9 +278,10 @@ type serviceCredential struct { Location httpLocation `json:"location"` } +type serviceCredentials []serviceCredential + func (g grpcHandler) grpcToHTTP(srv any, inStream grpc.ServerStream) error { method, ok := grpc.MethodFromServerStream(inStream) - if !ok { return status.Errorf(codes.Internal, "could not determine method from server stream") } @@ -270,18 +293,22 @@ func (g grpcHandler) grpcToHTTP(srv any, inStream grpc.ServerStream) error { f := &codec.GrpcFrame{} if err := inStream.RecvMsg(f); err != nil { - zap.L().Error(err.Error()) - return status.Errorf(codes.Internal, "error receiving request; error: %+cred", err) + zap.L().Error(fmt.Sprintf("error receiving grpc msg: %v%v", err, errs.ErrDescURL(errs.ReceiveMsgError))) + return status.Errorf(codes.Internal, "error receiving grpc msg: %v%v", err, errs.ErrDescURL(errs.ReceiveMsgError)) } // convert proto msg to json - jsonBody := protoToJson(g.serviceMetaData.ProtoFile, f.Data, method) + jsonBody, err := protoToJson(g.serviceMetaData.ProtoFile, f.Data, method) + if err != nil { + return status.Errorf(codes.Internal, "protoToJson error: %+v", errs.ErrDescURL(errs.InvalidProto)) + } - zap.L().Debug("Proto to json", zap.String("json", string(jsonBody))) + zap.L().Debug("Proto to json result", zap.String("json", string(jsonBody))) base, err := url.Parse(g.passthroughEndpoint) if err != nil { zap.L().Error("can't parse passthroughEndpoint", zap.Error(err)) + return status.Errorf(codes.Internal, "can't parse passthrough_endpoint %v%v", err, errs.ErrDescURL(errs.InvalidConfig)) } base.Path += method // method from proto should be the same as http handler path @@ -329,102 +356,105 @@ func (g grpcHandler) grpcToHTTP(srv any, inStream grpc.ServerStream) error { httpReq, err := http.NewRequest("POST", base.String(), bytes.NewBuffer(jsonBody)) httpReq.Header = headers if err != nil { - return status.Errorf(codes.Internal, "error creating http request; error: %+cred", err) + return status.Errorf(codes.Internal, "error creating http request: %+v%v", err, errs.ErrDescURL(errs.HTTPRequestBuildError)) } httpReq.Header.Set("content-type", "application/json") httpResp, err := http.DefaultClient.Do(httpReq) - if err != nil { - return status.Errorf(codes.Internal, "error executing http call; error: %+cred", err) + return status.Errorf(codes.Internal, "error executing HTTP service: %+v%v", err, errs.ErrDescURL(errs.ServiceUnavailable)) } - resp, err := io.ReadAll(httpResp.Body) if err != nil { - return status.Errorf(codes.Internal, "error reading response; error: %+cred", err) + return status.Errorf(codes.Internal, "error reading response from HTTP service: %+v%v", err, errs.ErrDescURL(errs.ServiceUnavailable)) + } + zap.L().Debug("Response from HTTP service", zap.String("response", string(resp))) + + protoMessage, errMarshal := jsonToProto(g.serviceMetaData.ProtoFile, resp, method) + if errMarshal != nil { + return status.Errorf(codes.Internal, "jsonToProto error: %+v%v", errMarshal, errs.ErrDescURL(errs.InvalidProto)) } - zap.L().Debug("Getting response", zap.String("response", string(resp))) - protoMessage := jsonToProto(g.serviceMetaData.ProtoFile, resp, method) if err = inStream.SendMsg(protoMessage); err != nil { - return status.Errorf(codes.Internal, "error sending response; error: %+cred", err) + return status.Errorf(codes.Internal, "error sending response from HTTP service: %+v", err) } return nil } -func jsonToProto(protoFile protoreflect.FileDescriptor, json []byte, methodName string) (proto proto.Message) { +func jsonToProto(protoFile protoreflect.FileDescriptor, json []byte, methodName string) (proto proto.Message, err error) { zap.L().Debug("Processing file", zap.String("fileName", string(protoFile.Name()))) - zap.L().Debug("Count services: ", zap.Int("value", protoFile.Services().Len())) + zap.L().Debug("Count services in proto: ", zap.Int("value", protoFile.Services().Len())) if protoFile.Services().Len() == 0 { zap.L().Warn("service in proto not found") - return proto + return proto, errors.New("services in proto not found") } service := protoFile.Services().Get(0) if service == nil { zap.L().Warn("service in proto not found") - return proto + return proto, errors.New("services in proto not found") } method := service.Methods().ByName(protoreflect.Name(methodName)) if method == nil { zap.L().Warn("method not found in proto") - return proto + return proto, fmt.Errorf("method %v in proto not found", methodName) } + output := method.Output() - zap.L().Debug("output msg descriptor", zap.Any("fullname", output.FullName())) + zap.L().Debug("output msg descriptor", zap.String("fullname", string(output.FullName()))) proto = dynamicpb.NewMessage(output) - err := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}.Unmarshal(json, proto) + err = protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}.Unmarshal(json, proto) if err != nil { - zap.L().Error("Can't unmarshal jsonToProto", zap.Error(err)) + zap.L().Error("can't unmarshal json to proto", zap.Error(err)) + return proto, fmt.Errorf("invalid proto, can't convert json to proto msg: %+v", err) } - return proto + return proto, nil } -func protoToJson(protoFile protoreflect.FileDescriptor, in []byte, methodName string) (json []byte) { +func protoToJson(protoFile protoreflect.FileDescriptor, in []byte, methodName string) (json []byte, err error) { if protoFile.Services().Len() == 0 { zap.L().Warn("service in proto not found") - return []byte("error, invalid proto file") + return []byte("error, invalid proto file"), errors.New("services in proto not found") } service := protoFile.Services().Get(0) if service == nil { zap.L().Warn("service in proto not found") - return []byte("error, invalid proto file") + return []byte("error, invalid proto file"), errors.New("services in proto not found") } method := service.Methods().ByName(protoreflect.Name(methodName)) if method == nil { zap.L().Warn("method not found in proto") - return []byte("error, invalid proto file or input request") + return []byte("error, method in proto not found"), errors.New("method in proto not found") } input := method.Input() zap.L().Debug("Input fullname method", zap.Any("value", input.FullName())) msg := dynamicpb.NewMessage(input) - err := proto.Unmarshal(in, msg) + err = proto.Unmarshal(in, msg) if err != nil { zap.L().Error("Error in unmarshalling", zap.Error(err)) - return []byte("error, invalid proto file or input request") + return []byte("error, invalid proto file or input request"), fmt.Errorf("error in unmarshaling proto to json: %+v", err) } json, err = protojson.MarshalOptions{UseProtoNames: true}.Marshal(msg) if err != nil { zap.L().Error("Error in marshaling", zap.Error(err)) - return []byte("error, invalid proto file or input request") + return []byte("error, invalid proto file or input request"), fmt.Errorf("error in marshaling proto to json: %+v", err) } - zap.L().Debug("Getting json", zap.String("json", string(json))) + zap.L().Debug("ProtoToJson result:", zap.String("json", string(json))) - return json + return json, nil } func (g grpcHandler) grpcToJSONRPC(srv any, inStream grpc.ServerStream) error { method, ok := grpc.MethodFromServerStream(inStream) - if !ok { return status.Errorf(codes.Internal, "could not determine method from server stream") } @@ -432,10 +462,6 @@ func (g grpcHandler) grpcToJSONRPC(srv any, inStream grpc.ServerStream) error { methodSegs := strings.Split(method, "/") method = methodSegs[len(methodSegs)-1] - if !ok { - return status.Errorf(codes.Internal, "could not get metadata from incoming context") - } - f := &codec.GrpcFrame{} if err := inStream.RecvMsg(f); err != nil { return status.Errorf(codes.Internal, "error receiving request; error: %+v", err) @@ -454,7 +480,6 @@ func (g grpcHandler) grpcToJSONRPC(srv any, inStream grpc.ServerStream) error { } httpReq, err := http.NewRequest("POST", g.passthroughEndpoint, bytes.NewBuffer(jsonRPCReq)) - if err != nil { return status.Errorf(codes.Internal, "error creating http request; error: %+v", err) } diff --git a/handler/grpc_test.go b/handler/grpc_test.go index c7ffca0d..097352b1 100644 --- a/handler/grpc_test.go +++ b/handler/grpc_test.go @@ -94,3 +94,44 @@ func (suite *GrpcTestSuite) TestPassThroughEndPoint() { passthroughURL, err = url.Parse("http://somedomain") assert.Equal(suite.T(), passthroughURL.Scheme, "http") } + +func TestHttpCredentials(t *testing.T) { + var creds = []serviceCredentials{ + {serviceCredential{ + Key: "api-key", + Value: "123abc", + Location: "query", + }}, + {serviceCredential{ + Key: "X-Api-Key", + Value: "123abc", + Location: "header", + }}, + } + + for _, v := range creds { + assert.Nil(t, v.validate()) + } + + var invalidCreds = []serviceCredentials{ + {serviceCredential{ + Key: "api-key", + Value: "123abc", + Location: "from", + }}, + {serviceCredential{ + Key: "X-Api-Key", + Value: "123abc", + Location: "", + }}, + {serviceCredential{ + Key: "", + Value: "123abc", + Location: "header", + }}, + } + + for _, v := range invalidCreds { + assert.NotNil(t, v.validate()) + } +} diff --git a/handler/interceptors.go b/handler/interceptors.go index 7de47be7..fe9cd8a9 100644 --- a/handler/interceptors.go +++ b/handler/interceptors.go @@ -27,11 +27,11 @@ const ( // Supported types are: "escrow". // Note: "job" Payment type is deprecated PaymentTypeHeader = "snet-payment-type" - //Client that calls the Daemon ( example can be "snet-cli","snet-dapp","snet-sdk") + // Client that calls the Daemon ( example can be "snet-cli","snet-dapp","snet-sdk") ClientTypeHeader = "snet-client-type" - //Value is a user address , example "0x94d04332C4f5273feF69c4a52D24f42a3aF1F207" + // Value is a user address , example "0x94d04332C4f5273feF69c4a52D24f42a3aF1F207" UserInfoHeader = "snet-user-info" - //User Agent details set in on the server stream info + // User Agent details set in on the server stream info UserAgentHeader = "user-agent" // PaymentChannelIDHeader is a MultiPartyEscrow contract payment channel // id. Value is a string containing a decimal number. @@ -281,7 +281,7 @@ func (interceptor *paymentValidationInterceptor) intercept(srv any, ss grpc.Serv defer func() { if r := recover(); r != nil { zap.L().Warn("Service handler called panic(panicValue)", zap.Any("panicValue", r)) - paymentHandler.CompleteAfterError(payment, fmt.Errorf("Service handler called panic(%v)", r)) + paymentHandler.CompleteAfterError(payment, fmt.Errorf("service handler called panic(%v)", r)) panic("re-panic after payment handler error handling") } else if e == nil { err = paymentHandler.Complete(payment) diff --git a/ipfsutils/ipfsutils.go b/ipfsutils/ipfsutils.go index aadb95d5..0319e842 100644 --- a/ipfsutils/ipfsutils.go +++ b/ipfsutils/ipfsutils.go @@ -52,8 +52,6 @@ func GetIpfsFile(hash string) (content []byte, err error) { return nil, err } - // log.WithField("hash", hash).WithField("blob", string(fileContent)).Debug("Blob of IPFS file with hash") - // Create a cid manually to check cid _, c, err := cid.CidFromBytes(append(cID.Bytes(), fileContent...)) if err != nil { diff --git a/metrics/heartbeat_test.go b/metrics/heartbeat_test.go index 96cca508..a72b281b 100644 --- a/metrics/heartbeat_test.go +++ b/metrics/heartbeat_test.go @@ -98,7 +98,7 @@ func (suite *HeartBeatTestSuite) TestHeartbeatHandler() { // Creating a ResponseRecorder to record the response. response := httptest.NewRecorder() handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { - HeartbeatHandler(writer, true) + HeartbeatHandler(writer, true, nil, nil) }) // Since it is basic http handler, we can call ServeHTTP method directly and pass request and response. @@ -131,7 +131,7 @@ func (suite *HeartBeatTestSuite) Test_GetHeartbeat() { serviceType := "http" serviveID := "SERVICE001" - dHeartbeat, _ := GetHeartbeat(serviceURL, serviceType, serviveID, false) + dHeartbeat, _ := GetHeartbeat(serviceURL, serviceType, serviveID, false, nil, nil) assert.NotNil(suite.T(), dHeartbeat, "heartbeat must not be nil") assert.Equal(suite.T(), dHeartbeat.Status, Online.String(), "Invalid State") @@ -152,11 +152,12 @@ func (suite *HeartBeatTestSuite) Test_GetHeartbeat() { // check with some timeout URL serviceURL = "http://localhost:1234" SetNoHeartbeatURLState(false) - dHeartbeat2, _ := GetHeartbeat(serviceURL, serviceType, serviveID, false) + dHeartbeat2, _ := GetHeartbeat(serviceURL, serviceType, serviveID, true, nil, nil) assert.NotNil(suite.T(), dHeartbeat2, "heartbeat must not be nil") assert.Equal(suite.T(), dHeartbeat2.Status, Warning.String(), "Invalid State") assert.NotEqual(suite.T(), dHeartbeat2.Status, Online.String(), "Invalid State") + assert.True(suite.T(), dHeartbeat2.TrainingInProto) assert.NotEqual(suite.T(), dHeartbeat2.ServiceHeartbeat, `{}`, "Service Heartbeat must not be empty.") assert.Equal(suite.T(), dHeartbeat2.ServiceHeartbeat, `{"serviceID":"SERVICE001","status":"NOT_SERVING"}`, diff --git a/snetd/cmd/components.go b/snetd/cmd/components.go index a8b9ff29..30033dab 100644 --- a/snetd/cmd/components.go +++ b/snetd/cmd/components.go @@ -12,6 +12,7 @@ import ( "github.com/singnet/snet-daemon/v5/blockchain" "github.com/singnet/snet-daemon/v5/config" "github.com/singnet/snet-daemon/v5/configuration_service" + "github.com/singnet/snet-daemon/v5/errs" "github.com/singnet/snet-daemon/v5/escrow" "github.com/singnet/snet-daemon/v5/etcddb" "github.com/singnet/snet-daemon/v5/handler" @@ -87,7 +88,7 @@ func loadConfigFileFromCommandLine(configFlag *pflag.Flag) { if configFlag.Changed || isFileExist(configFile) { err := config.LoadConfig(configFile) if err != nil { - panic(fmt.Errorf("[CONFIG] Error reading configuration file: %v", err)) + panic(fmt.Sprintf("[CONFIG] Error reading configuration file: %v%s", err, errs.ErrDescURL(errs.InvalidConfig))) } fmt.Println("[CONFIG] Using custom configuration file") } else { @@ -200,7 +201,7 @@ func (components *Components) LockerStorage() *storage.PrefixedAtomicStorage { } /* -create new PrefixedStorage using / as a prefix, use this storage as base for other storages +AtomicStorage - create new PrefixedStorage using / as a prefix, use this storage as base for other storages (i.e. return it from GetAtomicStorage of components.go); this guarantees that storages for different networks never intersect */ diff --git a/snetd/cmd/serve.go b/snetd/cmd/serve.go index 5fa99293..e349a47b 100644 --- a/snetd/cmd/serve.go +++ b/snetd/cmd/serve.go @@ -3,6 +3,7 @@ package cmd import ( "crypto/tls" "fmt" + "github.com/singnet/snet-daemon/v5/errs" "net" "net/http" "os" @@ -60,7 +61,7 @@ var ServeCmd = &cobra.Command{ var d daemon d, err = newDaemon(components) if err != nil { - zap.L().Fatal("Unable to initialize daemon", zap.Error(err)) + zap.L().Fatal("Unable to initialize daemon"+errs.ErrDescURL(errs.InvalidConfig), zap.Error(err)) } d.start()