diff --git a/README.md b/README.md index f134d5c4..d895dee9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -# snet-daemon +# SingularityNET Daemon [![Coverage Status](https://coveralls.io/repos/github/singnet/snet-daemon/badge.svg)](https://coveralls.io/github/singnet/snet-daemon) -SingularityNET Daemon +Users interested in deploying SingularityNET services should use this daemon + The daemon is the adapter with which an otherwise SingularityNET-unaware service implementation can be exposed to the SingularityNET platform. It is designed to be deployed as a sidecar proxy alongside the service on a given host. The daemon abstracts the blockchain components away from the clients. @@ -14,13 +15,13 @@ are then passed to the service after validation by the daemon. Gets the latest channel state of the Channel updated in ETCD by the daemons of the same group and then increments the nonce of the channel. -It then sends and ON-Chain transaction to claim funds.The daemons continue their work independently without any +It then sends and ON-Chain transaction to claim funds. The daemons continue their work independently without any confirmation from the treasurer on the blockchain. -## Usage (without compiling) +## Releases -Users interested in deploying SingularityNET services using SingularityNET -Daemon should install the appropriate [binary from releases](https://github.com/singnet/snet-daemon/releases). +**Usage without compiling:** +Precompiled binaries are published with each [release](https://github.com/singnet/snet-daemon/releases). ## Development @@ -28,8 +29,8 @@ These instructions are intended to facilitate the development and testing of Sin ### Prerequisites and dependencies -* [Go 1.21+](https://golang.org/dl/) -* [Protoc v25.0+](https://github.com/protocolbuffers/protobuf/releases) +* [Go 1.22+](https://golang.org/dl/) +* [Protoc 25.0+](https://github.com/protocolbuffers/protobuf/releases) **Protoc (libprotoc), golang and $GOPATH/bin should be in environment variables.** @@ -79,7 +80,7 @@ $ ./build/snetd-linux-amd64 init-full If you want to build snetd for several platforms, run `./scripts/build-all ` instead of `./scripts/build`. -You can edit the script to choose a specific platforms, but by default it will build for Linux, OSX, and Windows. +You can edit the script to choose the specific platforms, but by default it will build for Linux, OSX, and Windows. #### Run Daemon @@ -124,7 +125,7 @@ Available Commands: channel Manage operations on payment channels freecall Manage operations on free call users help Help about any command - init Write default configuration to file + init Write basic configuration to file init-full Write full default configuration to file list List channels, claims in progress, etc serve Is the default option which starts the Daemon. @@ -141,6 +142,10 @@ Use "snetd [command] --help" for more information about a command. ```bash $ ./scripts/test +``` +or +```bash +$ go test ./... ``` ### Configuration @@ -154,15 +159,19 @@ also supported via [Viper](https://github.com/spf13/viper). Use `snet init-full` command to save configuration file with default values. Following configuration properties can be set using configuration file. +#### Blockchain network config + +You can update the registry address or ethereum_json_rpc_endpoint in `resources/blockchain_network_config.json` before ./scripts/build. + #### Main properties These properties you should usually change before starting daemon for the first time. -* **blockchain_network_selected** (required) +* **blockchain_network_selected** (required) Name of the network to be used for Daemon possible values are one of (goerli, sepolia, main, local). Daemon will automatically read the Registry address associated with this network For local network ( you can also - specify the registry address manually),see the blockchain_network_config.json + specify the registry address manually), see the blockchain_network_config.json * **daemon_end_point** (required;) - Defines the ip and the port on which the daemon listens to. @@ -177,15 +186,10 @@ time. infura api key secret. -* **ipfs_end_point** (optional; default `"http://localhost:5002/"`) - - endpoint of IPFS instance to get [service configuration - metadata][service-configuration-metadata] - * **organization_id** (required) - Id of the organization to search for [service configuration metadata][service-configuration-metadata]. - * **service_id** (required) - Id of the service to search for [service configuration metadata][service-configuration-metadata]. @@ -202,10 +206,9 @@ time. * **executable_path** (required if `service_type` == `executable`) - path to executable to expose as a service. - -#### Blockchain network config - -You can update the registry address or ethereum_json_rpc_endpoint in `resources/blockchain_network_config.json` +* **ipfs_end_point** (optional; default `"http://ipfs.singularitynet.io:80"`) - + endpoint of IPFS instance to get [service configuration + metadata][service-configuration-metadata] #### Other properties @@ -214,16 +217,17 @@ This options are less frequently needed. * **service_credentials** (optional, for service_type http only): Array of credentials, example: -``` -"service_credentials": [ - {"key": "example_body_param", "value": 12345,"location": "body"}, - {"key": "X-API-Key", "value": "546bd7d4-d3e1-46ba-b752-bc45e4dc5b39", "location": "header"} - ], -``` + ``` + "service_credentials": [ + {"key": "example_body_param", "value": 12345,"location": "body"}, + {"key": "X-API-Key", "value": "546bd7d4-d3e1-46ba-b752-bc45e4dc5b39", "location": "header"} + ], + ``` + + Location can be: query, header or body. Query and header values must be string. -Location can be: query, header or body. Query and header values must be string. -* **allowed_users_flag** (optional;default:`false`) - You may need to protect the service provider 's service in test +* **allowed_user_flag** (optional;default:`false`) - You may need to protect the service provider 's service in test environment from being called by anyone, only Authorized users can make calls , when this flag is defined in the config, you can enforce this behaviour.You cannot set this flag to true in mainnet. @@ -231,11 +235,25 @@ Location can be: query, header or body. Query and header values must be string. In which case it becomes mandatory to define the configuration `allowed_users`, * **allowed_user_addresses** (optional;) - List of selected user addresses who can make requests to Daemon - Is Applicable only when you have `allowed_users_flag set` to true. + Is Applicable only when you have `allowed_user_flag` set to true. + +* **authentication_addresses** (required if `You need to update Daemon configurations remotely`) + Contains the Authentication addresses + that will be used to validate all requests to update Daemon configuration remotely + through a user interface (Operator UI) -* **authentication_address** (required if `You need to update Daemon configurations remotely`) - Contains the Authentication address that will be used to validate all requests to update Daemon configuration remotely - through a user interface ( Operator UI) +* **free_calls_users** + + You can set a separate number of allowed free calls for + certain users of the marketplace + + ```json + "free_calls_users": { + "johndoe@gmail.com": 500, + "snet@test.com": 100, + "me@email.com": 150 + }, + ``` * **auto_ssl_domain** (optional; default: `""`) - domain name for which the daemon should automatically acquire SSL certs @@ -250,9 +268,8 @@ Location can be: query, header or body. Query and header values must be string. * **burst_size** (optional; default: Infinite) - see [rate limiting configuration](./ratelimit/README.md) - -* **daemon_group_name** (optional ,default: `"default_group"`) - - This parameter defines the group the daemon belongs to . +* **daemon_group_name** (optional, default: `"default_group"`) - + This parameter defines the group the daemon belongs to. The group helps determine the recipient address for payments. [service configuration metadata][service-configuration-metadata]. @@ -261,9 +278,9 @@ Location can be: query, header or body. Query and header values must be string. see [logger configuration](./logger/README.md) * **max_message_size_in_mb** (optional; default: `4`) - - The default value set is to 4 (units are in MB ), this is used to configure the max size in MB of the message received + The default value set is to 4 (units are in MB), this is used to configure the max size in MB of the message received by the Daemon. - In case of Large messages , it is recommended to use streaming than setting a very high value on this configuration. + In case of Large messages, it is recommended to use streaming than setting a very high value on this configuration. It is not recommended to set the value more than 4GB `Please make sure your grpc version > 1.25` @@ -290,11 +307,11 @@ Location can be: query, header or body. Query and header values must be string. see [etcd server configuration](./etcddb#etcd-server-configuration) * **pvt_key_for_metering** (optional;only applies if `metering_enabled` is set to true) - This is used for authentication between daemon and the metering service in the context publishing stats , Even the - latest Channel Status is published , this way the offline channel state balance can also be tracked. - Daemon will send a signature signed by this private key , metering service will already have the public key + This is used for authentication between daemon and the metering service in the context publishing stats, Even the + latest Channel Status is published, this way the offline channel state balance can also be tracked. + Daemon will send a signature signed by this private key, metering service will already have the public key corresponding - to this Daemon ,metering service will ensure that the signer it receives matches the public key configured at its end. + to this Daemon, metering service will ensure that the signer it receives matches the public key configured at its end. This is mandatory only when metering is enabled. @@ -305,7 +322,7 @@ Location can be: query, header or body. Query and header values must be string. * **registry_address_key** (Optional) - Ethereum address of the Registry contract instance.This is auto determined if not specified based on the blockchain_network_selected - If a value is specified , it will be used and no attempt will be made to auto determine the registry address. + If a value is specified, it will be used and no attempt will be made to auto determine the registry address. * **alerts_email** (optional; default: `""`) - It must be a valid email. if it is empty, then it is considered as alerts @@ -326,7 +343,7 @@ Location can be: query, header or body. Query and header values must be string. * **is_curation_in_progress** (optional; default: `false`) - You may need to protect the service provider 's service in test environment from being called by anyone, only Authorized users can make calls , when this flag is set to true, - you can enforce this behaviour.Also see `curation_address_for_validation` + you can enforce this behaviour. Also see `curation_address_for_validation` * **token_expiry_in_minutes** (optional; default: `1440` minutes ~24hrs) - This is the default expiry time for a JWT token issued. @@ -351,10 +368,6 @@ Location can be: query, header or body. Query and header values must be string. [service-configuration-metadata]: https://github.com/singnet/wiki/blob/master/multiPartyEscrowContract/MPEServiceMetadata.md -## Release - -Precompiled binaries are published with each [release](https://github.com/singnet/snet-daemon/releases). - ## Versioning We use [SemVer](http://semver.org/) for versioning. For the versions available, see the diff --git a/authutils/auth_service.go b/authutils/auth_service.go index 972e0857..c794e344 100755 --- a/authutils/auth_service.go +++ b/authutils/auth_service.go @@ -8,11 +8,12 @@ import ( "encoding/hex" "errors" "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/singnet/snet-daemon/blockchain" - log "github.com/sirupsen/logrus" - "math/big" + "go.uber.org/zap" ) // TODO convert to separate authentication service. VERY MUCH REQUIRED FOR OPERATOR UI AUTHENTICATION @@ -25,33 +26,43 @@ const ( ) func GetSignerAddressFromMessage(message, signature []byte) (signer *common.Address, err error) { - log := log.WithFields(log.Fields{ - "message": blockchain.BytesToBase64(message), - "signature": blockchain.BytesToBase64(signature), - }) + messageFieldLog := zap.String("message", blockchain.BytesToBase64(message)) + signatureFieldLog := zap.String("signature", blockchain.BytesToBase64(signature)) messageHash := crypto.Keccak256( blockchain.HashPrefix32Bytes, crypto.Keccak256(message), ) - log = log.WithField("messageHash", hex.EncodeToString(messageHash)) + messageHashFieldLog := zap.String("messageHash", hex.EncodeToString(messageHash)) - v, _, _, e := blockchain.ParseSignature(signature) - if e != nil { - log.WithError(e).Warn("Error parsing signature") + v, _, _, err := blockchain.ParseSignature(signature) + if err != nil { + zap.L().Warn("Error parsing signature", zap.Error(err), messageFieldLog, signatureFieldLog, messageHashFieldLog) return nil, errors.New("incorrect signature length") } modifiedSignature := bytes.Join([][]byte{signature[0:64], {v % 27}}, nil) - publicKey, e := crypto.SigToPub(messageHash, modifiedSignature) - if e != nil { - log.WithError(e).WithField("modifiedSignature", modifiedSignature).Warn("Incorrect signature") + publicKey, err := crypto.SigToPub(messageHash, modifiedSignature) + modifiedSignatureFieldLog := zap.ByteString("modifiedSignature", modifiedSignature) + if err != nil { + zap.L().Warn("Incorrect signature", + zap.Error(err), + modifiedSignatureFieldLog, + messageFieldLog, + signatureFieldLog, + messageHashFieldLog) return nil, errors.New("incorrect signature data") } - log = log.WithField("publicKey", publicKey) + publicKeyFieldLog := zap.Any("publicKey", publicKey) keyOwnerAddress := crypto.PubkeyToAddress(*publicKey) - log.WithField("keyOwnerAddress", keyOwnerAddress).Debug("Message signature parsed") + keyOwnerAddressFieldLog := zap.Any("keyOwnerAddress", keyOwnerAddress) + zap.L().Debug("Message signature parsed", + messageFieldLog, + signatureFieldLog, + messageHashFieldLog, + publicKeyFieldLog, + keyOwnerAddressFieldLog) return &keyOwnerAddress, nil } @@ -61,7 +72,7 @@ func GetSignerAddressFromMessage(message, signature []byte) (signer *common.Addr func VerifySigner(message []byte, signature []byte, signer common.Address) error { signerFromMessage, err := GetSignerAddressFromMessage(message, signature) if err != nil { - log.Error(err) + zap.L().Error("Gering error from getSignerAddressFromMessage", zap.Error(err)) return err } if signerFromMessage.String() == signer.String() { @@ -104,7 +115,7 @@ func CurrentBlock() (*big.Int, error) { defer ethClient.RawClient.Close() var currentBlockHex string if err = ethClient.RawClient.CallContext(context.Background(), ¤tBlockHex, "eth_blockNumber"); err != nil { - log.WithError(err).Error("error determining current block") + zap.L().Error("error determining current block", zap.Error(err)) return nil, fmt.Errorf("error determining current block: %v", err) } return new(big.Int).SetBytes(common.FromHex(currentBlockHex)), nil diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index f04ea6d9..b336f0e8 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -5,14 +5,15 @@ import ( "context" "crypto/ecdsa" "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/pkg/errors" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" - "math/big" + "go.uber.org/zap" ) var ( @@ -98,7 +99,7 @@ func (processor *Processor) CurrentBlock() (currentBlock *big.Int, err error) { // unmarshaling the response currently. See https://github.com/ethereum/go-ethereum/issues/3230 var currentBlockHex string if err = processor.rawClient.CallContext(context.Background(), ¤tBlockHex, "eth_blockNumber"); err != nil { - log.WithError(err).Error("error determining current block") + zap.L().Error("error determining current block", zap.Error(err)) return nil, fmt.Errorf("error determining current block: %v", err) } diff --git a/blockchain/escrow.go b/blockchain/escrow.go index 1de4548c..5d1f9bfc 100644 --- a/blockchain/escrow.go +++ b/blockchain/escrow.go @@ -2,8 +2,10 @@ package blockchain import ( "github.com/ethereum/go-ethereum/common" - log "github.com/sirupsen/logrus" + "math/big" + + "go.uber.org/zap" ) type MultiPartyEscrowChannel struct { @@ -19,15 +21,15 @@ type MultiPartyEscrowChannel struct { var zeroAddress = common.Address{} func (processor *Processor) MultiPartyEscrowChannel(channelID *big.Int) (channel *MultiPartyEscrowChannel, ok bool, err error) { - log := log.WithField("channelID", channelID) + channelIdField := zap.Any("channelID", channelID) ch, err := processor.multiPartyEscrow.Channels(nil, channelID) if err != nil { - log.WithError(err).Warn("Error while looking up for channel id in blockchain") + zap.L().Warn("Error while looking up for channel id in blockchain", zap.Error(err), channelIdField) return nil, false, err } if ch.Sender == zeroAddress { - log.Warn("Unable to find channel id in blockchain") + zap.L().Warn("Unable to find channel id in blockchain", channelIdField) return nil, false, nil } @@ -41,8 +43,7 @@ func (processor *Processor) MultiPartyEscrowChannel(channelID *big.Int) (channel Signer: ch.Signer, } - log = log.WithField("channel", channel) - log.Debug("Channel found in blockchain") + zap.L().Debug("Channel found in blockchain", zap.Any("channel", channel)) return channel, true, nil } diff --git a/blockchain/orginzationMetadata.go b/blockchain/orginzationMetadata.go index aa417456..b8a54609 100644 --- a/blockchain/orginzationMetadata.go +++ b/blockchain/orginzationMetadata.go @@ -3,13 +3,15 @@ package blockchain import ( "encoding/json" "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/singnet/snet-daemon/config" - "github.com/singnet/snet-daemon/ipfsutils" - log "github.com/sirupsen/logrus" "math/big" "strings" "time" + + "github.com/singnet/snet-daemon/config" + "github.com/singnet/snet-daemon/ipfsutils" + + "github.com/ethereum/go-ethereum/common" + "go.uber.org/zap" ) /* @@ -81,7 +83,7 @@ type Payment struct { PaymentChannelStorageClient PaymentChannelStorageClient `json:"payment_channel_storage_client"` } -//Structure to hold the individual group details , an Organization can have multiple groups +// Structure to hold the individual group details , an Organization can have multiple groups type Group struct { GroupName string `json:"group_name"` GroupID string `json:"group_id"` @@ -89,29 +91,30 @@ type Group struct { LicenseEndpoints []string `json:"license_server_endpoints"` } -//Structure to hold the storage details of the payment +// Structure to hold the storage details of the payment type PaymentChannelStorageClient struct { ConnectionTimeout string `json:"connection_timeout" mapstructure:"connection_timeout"` RequestTimeout string `json:"request_timeout" mapstructure:"request_timeout"` Endpoints []string `json:"endpoints"` } -//Construct the Organization metadata from the JSON Passed +// Construct the Organization metadata from the JSON Passed func InitOrganizationMetaDataFromJson(jsonData string) (metaData *OrganizationMetaData, err error) { metaData = new(OrganizationMetaData) err = json.Unmarshal([]byte(jsonData), &metaData) if err != nil { - log.WithError(err).WithField("jsondata", jsonData) + zap.L().Error("Error in unmarshaling metadata json", zap.Error(err), zap.Any("jsondata", jsonData)) return nil, err } //Check for mandatory validations if err = setDerivedAttributes(metaData); err != nil { - log.WithError(err) + zap.L().Error("Error in setting derived atrributes", zap.Error(err)) return nil, err } if err = checkMandatoryFields(metaData); err != nil { + zap.L().Error("Error in check mdandatory fields", zap.Error(err)) return nil, err } @@ -141,7 +144,7 @@ func setDerivedAttributes(metaData *OrganizationMetaData) (err error) { return err } -//Determine the group this Daemon belongs to +// Determine the group this Daemon belongs to func getDaemonGroup(metaData OrganizationMetaData) (group *Group, err error) { groupName := config.GetString(config.DaemonGroupName) for _, group := range metaData.Groups { @@ -151,12 +154,12 @@ func getDaemonGroup(metaData OrganizationMetaData) (group *Group, err error) { } err = fmt.Errorf("group name %v in config is invalid, "+ "there was no group found with this name in the metadata", groupName) - log.WithError(err) + zap.L().Error("error in getting daemon group", zap.Error(err)) return nil, err } -//Will be used to load the Organization metadata when Daemon starts -//To be part of components +// Will be used to load the Organization metadata when Daemon starts +// To be part of components func GetOrganizationMetaData() *OrganizationMetaData { var metadata *OrganizationMetaData var err error @@ -167,8 +170,7 @@ func GetOrganizationMetaData() *OrganizationMetaData { metadata = &OrganizationMetaData{daemonGroup: &Group{}} } if err != nil { - log.WithError(err). - Panic("error on retrieving / parsing organization metadata from block chain") + zap.L().Panic("error on retrieving / parsing organization metadata from block chain", zap.Error(err)) } return metadata } @@ -185,13 +187,12 @@ func getMetaDataURI() []byte { organizationRegistered, err := reg.GetOrganizationById(nil, orgId) if err != nil || !organizationRegistered.Found { - log.WithError(err).WithField("OrganizationId", config.GetString(config.OrganizationId)). - Panic("Error Retrieving contract details for the Given Organization") + zap.L().Panic("Error Retrieving contract details for the Given Organization", zap.String("OrganizationId", config.GetString(config.OrganizationId))) } return organizationRegistered.OrgMetadataURI[:] } -//Get the Group ID the Daemon needs to associate itself to , requests belonging to a different group if will be rejected +// Get the Group ID the Daemon needs to associate itself to , requests belonging to a different group if will be rejected func (metaData OrganizationMetaData) GetGroupIdString() string { return metaData.daemonGroup.GroupID } @@ -205,35 +206,35 @@ func (metaData OrganizationMetaData) GetLicenseEndPoints() []string { return metaData.daemonGroup.LicenseEndpoints } -//Pass the group Name and retrieve the details of the payment address/ recipient address. +// Pass the group Name and retrieve the details of the payment address/ recipient address. func (metaData OrganizationMetaData) GetPaymentAddress() common.Address { return metaData.recipientPaymentAddress } -//Payment expiration threshold +// Payment expiration threshold func (metaData *OrganizationMetaData) GetPaymentExpirationThreshold() *big.Int { return metaData.daemonGroup.PaymentDetails.PaymentExpirationThreshold } -//Get the End points of the Payment Storage used to update the storage state +// Get the End points of the Payment Storage used to update the storage state func (metaData OrganizationMetaData) GetPaymentStorageEndPoints() []string { return metaData.daemonGroup.PaymentDetails.PaymentChannelStorageClient.Endpoints } -//Get the connection time out defined +// Get the connection time out defined func (metaData OrganizationMetaData) GetConnectionTimeOut() (connectionTimeOut time.Duration) { connectionTimeOut, err := time.ParseDuration(metaData.daemonGroup.PaymentDetails.PaymentChannelStorageClient.ConnectionTimeout) if err != nil { - log.Errorf(err.Error()) + zap.L().Error(err.Error()) } return connectionTimeOut } -//Get the Request time out defined +// Get the Request time out defined func (metaData OrganizationMetaData) GetRequestTimeOut() time.Duration { timeOut, err := time.ParseDuration(metaData.daemonGroup.PaymentDetails.PaymentChannelStorageClient.RequestTimeout) if err != nil { - log.Errorf(err.Error()) + zap.L().Error(err.Error()) } return timeOut } diff --git a/blockchain/serviceMetadata.go b/blockchain/serviceMetadata.go index df532570..31b5ab74 100644 --- a/blockchain/serviceMetadata.go +++ b/blockchain/serviceMetadata.go @@ -4,17 +4,18 @@ import ( "context" "encoding/json" "fmt" + "math/big" + "os" + "strings" + "github.com/bufbuild/protocompile" pproto "github.com/emicklei/proto" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/singnet/snet-daemon/config" "github.com/singnet/snet-daemon/ipfsutils" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" "google.golang.org/protobuf/reflect/protoreflect" - "math/big" - "os" - "strings" ) /* @@ -218,6 +219,7 @@ type OrganizationGroup struct { Licenses Licenses `json:"licenses,omitempty"` AddOns []AddOns `json:"addOns,omitempty"` } + type Pricing struct { PriceModel string `json:"price_model"` PriceInCogs *big.Int `json:"price_in_cogs,omitempty"` @@ -251,8 +253,8 @@ func ServiceMetaData() *ServiceMetadata { ipfsHash := string(getServiceMetaDataUrifromRegistry()) metadata, err = GetServiceMetaDataFromIPFS(FormatHash(ipfsHash)) if err != nil { - log.WithError(err). - Panic("error on determining service metadata from file") + + zap.L().Panic("error on determining service metadata from file", zap.Error(err)) } } else { metadata = &ServiceMetadata{Encoding: "proto", ServiceType: "grpc"} @@ -277,14 +279,13 @@ func ReadServiceMetaDataFromLocalFile(filename string) (*ServiceMetadata, error) func getRegistryCaller() (reg *RegistryCaller) { ethClient, err := GetEthereumClient() if err != nil { - log.WithError(err).Panic("Unable to get Blockchain client ") + zap.L().Panic("Unable to get Blockchain client ", zap.Error(err)) } defer ethClient.Close() registryContractAddress := getRegistryAddressKey() reg, err = NewRegistryCaller(registryContractAddress, ethClient.EthClient) if err != nil { - log.WithError(err).WithField("registryContractAddress", registryContractAddress). - Panic("Error instantiating Registry contract for the given Contract Address") + zap.L().Panic("Error instantiating Registry contract for the given Contract Address", zap.Error(err), zap.Any("registryContractAddress", registryContractAddress)) } return reg } @@ -297,9 +298,9 @@ func getServiceMetaDataUrifromRegistry() []byte { serviceRegistration, err := reg.GetServiceRegistrationById(nil, orgId, serviceId) if err != nil || !serviceRegistration.Found { - log.WithError(err).WithField("OrganizationId", config.GetString(config.OrganizationId)). - WithField("ServiceId", config.GetString(config.ServiceId)). - Panic("Error Retrieving contract details for the Given Organization and Service Ids ") + zap.L().Panic("Error Retrieving contract details for the Given Organization and Service Ids ", + zap.String("OrganizationId", config.GetString(config.OrganizationId)), + zap.String("ServiceId", config.GetString(config.ServiceId))) } return serviceRegistration.MetadataURI[:] @@ -314,7 +315,7 @@ func InitServiceMetaDataFromJson(jsonData string) (*ServiceMetadata, error) { metaData := new(ServiceMetadata) err := json.Unmarshal([]byte(jsonData), &metaData) if err != nil { - log.WithError(err).WithField("jsondata", jsonData) + zap.L().Error(err.Error(), zap.Any("jsondata", jsonData)) return nil, err } @@ -330,17 +331,16 @@ func InitServiceMetaDataFromJson(jsonData string) (*ServiceMetadata, error) { } dynamicPriceMethodMappingJson, err := json.Marshal(metaData.DynamicPriceMethodMapping) if err != nil { - log.Println(err) + zap.L().Error(err.Error()) } - log.Debugln("dynamicPriceMethodMappingJson: ", string(dynamicPriceMethodMappingJson)) - + zap.L().Debug("dynamic price method mapping", zap.String("json", string(dynamicPriceMethodMappingJson))) trainingMethodsJson, err := json.Marshal(metaData.TrainingMethods) if err != nil { - log.Println(err) + zap.L().Error(err.Error()) } - log.Debugln("trainingMethodsJson: ", string(trainingMethodsJson)) + zap.L().Debug("Traning method", zap.String("json", string(trainingMethodsJson))) return metaData, err } @@ -364,7 +364,7 @@ func setGroup(metaData *ServiceMetadata) (err error) { } err = fmt.Errorf("group name %v in config is invalid, "+ "there was no group found with this name in the metadata", groupName) - log.WithError(err) + zap.L().Error("Error in set group", zap.Error(err)) return err } @@ -379,7 +379,7 @@ func setDefaultPricing(metaData *ServiceMetadata) (err error) { } } err = fmt.Errorf("MetaData does not have the default pricing set ") - log.WithError(err) + zap.L().Warn("Error in set default pricing", zap.Error(err)) return err } @@ -485,11 +485,11 @@ func setServiceProto(metaData *ServiceMetadata) (err error) { } if metaData.ServiceType == "http" && len(protoFiles) > 1 { - log.Fatalln("Currently daemon support only one proto file for HTTP services!") + zap.L().Fatal("Currently daemon support only one proto file for HTTP services!") } for _, file := range protoFiles { - log.Debugln("Protofile: ", file) + zap.L().Debug("Protofile", zap.String("file", file)) //If Dynamic pricing is enabled ,there will be mandatory checks on the service proto //this is to ensure that the standards on how one defines the methods to invoke is followed @@ -568,7 +568,7 @@ func getFileDescriptor(protoContent string) protoreflect.FileDescriptor { } fds, err := compiler.Compile(context.Background(), serviceProto) if err != nil { - log.Println(err) + zap.L().Error(err.Error()) } return fds.FindFileByPath(serviceProto) } diff --git a/blockchain/utils.go b/blockchain/utils.go index 9fe7f1af..eba3974b 100644 --- a/blockchain/utils.go +++ b/blockchain/utils.go @@ -3,10 +3,11 @@ package blockchain import ( "encoding/base64" "fmt" - "github.com/ethereum/go-ethereum/common" - log "github.com/sirupsen/logrus" "regexp" "strings" + + "github.com/ethereum/go-ethereum/common" + "go.uber.org/zap" ) // ParseSignature parses Ethereum signature. @@ -53,10 +54,7 @@ func StringToBytes32(str string) [32]byte { } func RemoveSpecialCharactersfromHash(pString string) string { - reg, err := regexp.Compile("[^a-zA-Z0-9=]") - if err != nil { - log.Panic(err) - } + reg := regexp.MustCompile("[^a-zA-Z0-9=]") return reg.ReplaceAllString(pString, "") } @@ -64,7 +62,7 @@ func ConvertBase64Encoding(str string) ([32]byte, error) { var byte32 [32]byte data, err := base64.StdEncoding.DecodeString(str) if err != nil { - log.WithError(err).WithField("String Passed:", str) + zap.L().Error(err.Error(), zap.String("String Passed", str)) return byte32, err } copy(byte32[:], data[:]) @@ -72,10 +70,10 @@ func ConvertBase64Encoding(str string) ([32]byte, error) { } func FormatHash(ipfsHash string) string { - log.WithField("metadataHash", ipfsHash).Debug("Before Formatting") + zap.L().Debug("Before Formatting", zap.String("metadataHash", ipfsHash)) ipfsHash = strings.Replace(ipfsHash, IpfsPrefix, "", -1) ipfsHash = RemoveSpecialCharactersfromHash(ipfsHash) - log.WithField("metadataUri", ipfsHash).Debug("After Formatting") + zap.L().Debug("After Formatting", zap.String("metadataUri", ipfsHash)) return ipfsHash } diff --git a/blockchain/utils_test.go b/blockchain/utils_test.go index 4823ee10..e25b0bef 100644 --- a/blockchain/utils_test.go +++ b/blockchain/utils_test.go @@ -1,8 +1,9 @@ package blockchain import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestBytesToBase64(t *testing.T) { @@ -22,7 +23,7 @@ func TestFormatHash(t *testing.T) { } func TestConvertBase64Encoding(t *testing.T) { - if _, err := ConvertBase64Encoding("n@@###zNEetD1kzU3PZqR4nHPS8erDkrUK0hN4iCBQ4vH5U");err != nil { + if _, err := ConvertBase64Encoding("n@@###zNEetD1kzU3PZqR4nHPS8erDkrUK0hN4iCBQ4vH5U"); err != nil { assert.Equal(t, err.Error(), "illegal base64 data at input byte 1") } @@ -30,9 +31,29 @@ func TestConvertBase64Encoding(t *testing.T) { func TestToChecksumAddress(t *testing.T) { - assert.Equal(t,"0xE9D09A6C296ACDd4C01b21F407aC93FDfC63e78c", ToChecksumAddress("0xe9d09A6C296aCdd4c01b21f407ac93fdfC63E78C")) + assert.Equal(t, "0xE9D09A6C296ACDd4C01b21F407aC93FDfC63e78c", ToChecksumAddress("0xe9d09A6C296aCdd4c01b21f407ac93fdfC63E78C")) - assert.Equal(t,"0xE9D09A6C296ACDd4C01b21F407aC93FDfC63e78c", ToChecksumAddress("0xe9d09A6C296aCdd4c01b21f407ac93fdfC63E78C")) + assert.Equal(t, "0xE9D09A6C296ACDd4C01b21F407aC93FDfC63e78c", ToChecksumAddress("0xe9d09A6C296aCdd4c01b21f407ac93fdfC63E78C")) } +func TestRemoveSpecialCharactersfromHash(t *testing.T) { + testCases := []struct { + input string + expectedOutput string + }{ + {"abc123", "abc123"}, + {"abc123!@#", "abc123"}, + {"a1b2c3 ~`!@#$%^&*()_+-={}[]|\\:;\"'<>,.?/", "a1b2c3="}, + {"abc=123", "abc=123"}, + {"a1!b2@c3#=4", "a1b2c3=4"}, + } + for _, tc := range testCases { + t.Run(tc.input, func(t *testing.T) { + output := RemoveSpecialCharactersfromHash(tc.input) + if output != tc.expectedOutput { + t.Errorf("RemoveSpecialCharactersfromHash(%q) = %q; want %q", tc.input, output, tc.expectedOutput) + } + }) + } +} diff --git a/config/blockchain_network_config.go b/config/blockchain_network_config.go index a1926c00..cd2f37d7 100644 --- a/config/blockchain_network_config.go +++ b/config/blockchain_network_config.go @@ -3,10 +3,12 @@ package config import ( "encoding/json" "fmt" - "github.com/pkg/errors" - contracts "github.com/singnet/snet-ecosystem-contracts" - log "github.com/sirupsen/logrus" "os" + + contracts "github.com/singnet/snet-ecosystem-contracts" + + "github.com/pkg/errors" + "go.uber.org/zap" ) type NetworkSelected struct { @@ -27,7 +29,7 @@ var networkSelected = &NetworkSelected{} var networkIdNameMapping string func determineNetworkSelected(data []byte) (err error) { - dynamicBinding := map[string]interface{}{} + dynamicBinding := map[string]any{} networkName := GetString(BlockChainNetworkSelected) if err = json.Unmarshal(data, &dynamicBinding); err != nil { return err @@ -35,16 +37,16 @@ func determineNetworkSelected(data []byte) (err error) { //Get the Network Name selected in config ( snetd.config.json) , Based on this retrieve the Registry address , //Ethereum End point and Network ID mapped to networkSelected.NetworkName = networkName - networkSelected.RegistryAddressKey = getDetailsFromJsonOrConfig(dynamicBinding[networkName].(map[string]interface{})[RegistryAddressKey], RegistryAddressKey) - networkSelected.EthereumJSONRPCEndpoint = getDetailsFromJsonOrConfig(dynamicBinding[networkName].(map[string]interface{})[EthereumJsonRpcEndpointKey], EthereumJsonRpcEndpointKey) - networkSelected.NetworkId = fmt.Sprintf("%v", dynamicBinding[networkName].(map[string]interface{})[NetworkId]) + networkSelected.RegistryAddressKey = getDetailsFromJsonOrConfig(dynamicBinding[networkName].(map[string]any)[RegistryAddressKey], RegistryAddressKey) + networkSelected.EthereumJSONRPCEndpoint = getDetailsFromJsonOrConfig(dynamicBinding[networkName].(map[string]any)[EthereumJsonRpcEndpointKey], EthereumJsonRpcEndpointKey) + networkSelected.NetworkId = fmt.Sprintf("%v", dynamicBinding[networkName].(map[string]any)[NetworkId]) return err } // Check if the value set in the config file, if yes, then we use it as is // else we derive the value from the JSON parsed -func getDetailsFromJsonOrConfig(details interface{}, configName string) string { +func getDetailsFromJsonOrConfig(details any, configName string) string { if len(GetString(configName)) > 0 { return GetString(configName) } @@ -94,7 +96,7 @@ func setRegistryAddress() (err error) { } func deriveDatafromJSON(data []byte) (err error) { - m := map[string]interface{}{} + m := map[string]any{} err = json.Unmarshal(data, &m) if err != nil { return fmt.Errorf("cannot parse the registry JSON file for the network %v , the error is : %v", @@ -105,10 +107,12 @@ func deriveDatafromJSON(data []byte) (err error) { return errors.New("cannot find registry address from JSON for the selected network") } - networkSelected.RegistryAddressKey = fmt.Sprintf("%v", m[GetNetworkId()].(map[string]interface{})["address"]) + networkSelected.RegistryAddressKey = fmt.Sprintf("%v", m[GetNetworkId()].(map[string]any)["address"]) - log.Infof("The Network specified is :%v, and maps to the Network Id %v, the determined Registry address is %v and block chain end point is %v", - GetString(BlockChainNetworkSelected), GetNetworkId(), GetRegistryAddress(), GetBlockChainEndPoint()) + zap.L().Info("Derive data from JSON", zap.String("Network", GetString(BlockChainNetworkSelected)), + zap.String("NetwrokId", GetNetworkId()), + zap.String("RegistryAddress", GetRegistryAddress()), + zap.String("Blockchain endpoint", GetBlockChainEndPoint())) return nil } diff --git a/config/blockchain_network_config_test.go b/config/blockchain_network_config_test.go index 802e9379..9f6771c0 100644 --- a/config/blockchain_network_config_test.go +++ b/config/blockchain_network_config_test.go @@ -83,7 +83,7 @@ func Test_SetBlockChainNetworkDetails(t *testing.T) { func Test_GetDetailsFromJsonOrConfig(t *testing.T) { - dynamicBinding := map[string]interface{}{} + dynamicBinding := map[string]any{} data := []byte(defaultBlockChainNetworkConfig) json.Unmarshal(data, &dynamicBinding) @@ -97,7 +97,7 @@ func Test_GetDetailsFromJsonOrConfig(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := getDetailsFromJsonOrConfig(dynamicBinding[tt.network].(map[string]interface{})[tt.name], tt.name); got != tt.want { + if got := getDetailsFromJsonOrConfig(dynamicBinding[tt.network].(map[string]any)[tt.name], tt.name); got != tt.want { t.Errorf("getDetailsFromJsonOrConfig() = %v, want %v", got, tt.want) } }) diff --git a/config/config.go b/config/config.go index e16e81a5..c88942dc 100644 --- a/config/config.go +++ b/config/config.go @@ -1,9 +1,9 @@ package config import ( + "bytes" "errors" "fmt" - "github.com/ethereum/go-ethereum/common" "math/big" "net" "net/url" @@ -12,7 +12,9 @@ import ( "strings" "time" - log "github.com/sirupsen/logrus" + "github.com/ethereum/go-ethereum/common" + "go.uber.org/zap" + "github.com/spf13/cast" "github.com/spf13/viper" ) @@ -66,6 +68,7 @@ const ( TokenExpiryInMinutes = "token_expiry_in_minutes" TokenSecretKey = "token_secret_key" BlockchainProviderApiKey = "blockchain_provider_api_key" + FreeCallsUsers = "free_calls_users" //none|grpc|http //This defaultConfigJson will eventually be replaced by DefaultDaemonConfigurationSchema defaultConfigJson string = ` @@ -87,8 +90,6 @@ const ( "max_message_size_in_mb" : 4, "daemon_type": "grpc", "enable_dynamic_pricing":false, - "hdwallet_index": 0, - "hdwallet_mnemonic": "", "allowed_user_flag" :false, "auto_ssl_domain": "", "auto_ssl_cache_dir": ".certs", @@ -98,23 +99,22 @@ const ( "timezone": "UTC", "formatter": { "type": "text", - "timestamp_format": "2006-01-02T15:04:05.999999999Z07:00" + "timestamp_format": "2006-01-02T15:04:05.999Z07:00" }, "output": { - "type": "file", + "type": ["file", "stdout"], "file_pattern": "./snet-daemon.%Y%m%d.log", "current_link": "./snet-daemon.log", - "rotation_time_in_sec": 86400, - "max_age_in_sec": 604800, + "max_size_in_mb": 10, + "max_age_in_days": 7, "rotation_count": 0 }, "hooks": [] }, "payment_channel_storage_client": { - "connection_timeout": "5s", - "request_timeout": "3s", - "endpoints": ["http://127.0.0.1:2379"] - }, + "connection_timeout": "0s", + "request_timeout": "0s" + }, "payment_channel_storage_server": { "id": "storage-1", "scheme": "http", @@ -126,47 +126,29 @@ const ( "startup_timeout": "1m", "data_dir": "storage-data-dir-1.etcd", "log_level": "info", + "log_outputs": ["./etcd-server.log"], "enabled": false }, "alerts_email": "", "service_heartbeat_type": "http", "token_expiry_in_minutes": 1440, - "model_training_enabled":false + "model_training_enabled": false }` - MinimumConfigJson string = ` { + MinimumConfigJson string = `{ "blockchain_enabled": true, "blockchain_network_selected": "sepolia", + "passthrough_endpoint":"YOUR_SERVICE_ENDPOINT", + "service_id": "YOUR_SERVICE_ID", + "organization_id": "YOUR_ORG_ID", "daemon_end_point": "127.0.0.1:8080", "daemon_group_name":"default_group", "passthrough_enabled": true, - "passthrough_endpoint":"YOUR_SERVICE_ENDPOINT", - "service_id": "ExampleServiceId", - "organization_id": "ExampleOrganizationId", "payment_channel_storage_type": "etcd", "ipfs_end_point": "http://ipfs.singularitynet.io:80", - "enable_dynamic_pricing":false, - "model_training_enabled":false, - "log": { - "level": "info", - "timezone": "UTC", - "formatter": { - "type": "text", - "timestamp_format": "2006-01-02T15:04:05.999999999Z07:00" - }, + "log": { "output": { - "type": "file", - "file_pattern": "./snet-daemon.%Y%m%d.log", - "current_link": "./snet-daemon.log", - "rotation_time_in_sec": 86400, - "max_age_in_sec": 604800, - "rotation_count": 0 - }, - "hooks": [] - }, - "payment_channel_storage_client": { - "connection_timeout": "5s", - "request_timeout": "3s", - "endpoints": ["http://127.0.0.1:2379"] + "type": ["file", "stdout"] + } }}` ) @@ -189,6 +171,12 @@ func init() { vip.AddConfigPath(".") } +// SetVip allows setting a new Viper instance. +// This is useful for testing, where you may want to change the configuration. +func SetVip(newVip *viper.Viper) { + vip = newVip +} + // ReadConfigFromJsonString function reads settigs from json string to the // config instance. String should contain valid JSON config. func ReadConfigFromJsonString(config *viper.Viper, json string) error { @@ -231,15 +219,16 @@ func Validate() error { return err } - //Check if the Daemon is on the latest version or not + // Check if the Daemon is on the latest version or not if message, err := CheckVersionOfDaemon(); err != nil { - //In case of any error on version check , just log it - log.Warning(err) + // In case of any error on version check, just log it + zap.L().Warn(err.Error()) } else { - log.Info(message) + // Print current version of daemon + zap.L().Info(message) } - // the maximum that the server can receive to 2GB. + // Check the maximum message size (The maximum that the server can receive - 2GB). maxMessageSize := vip.GetInt(MaxMessageSizeInMB) if maxMessageSize <= 0 || maxMessageSize > 2048 { return errors.New(" max_message_size_in_mb cannot be more than 2GB (i.e 2048 MB) and has to be a positive number") @@ -247,6 +236,7 @@ func Validate() error { if err = allowedUserConfigurationChecks(); err != nil { return err } + return validateMeteringChecks() } @@ -265,6 +255,7 @@ func allowedUserConfigurationChecks() error { } return nil } + func validateMeteringChecks() (err error) { if GetBool(MeteringEnabled) && !IsValidUrl(GetString(MeteringEndPoint)) { return errors.New("to Support Metering you need to have a valid Metering End point") @@ -302,6 +293,24 @@ func GetBool(key string) bool { return vip.GetBool(key) } +func GetStringMap(key string) map[string]any { + return vip.GetStringMap(key) +} + +func GetFreeCallsCount(userID string) (countFreeCallsAllowed int) { + freeCallsUsers := GetStringMap(FreeCallsUsers) + if countFreeCalls, ok := freeCallsUsers[userID]; ok { + if count, countOk := countFreeCalls.(float64); countOk { + countFreeCallsAllowed = int(count) + } + } + return +} + +func GetStringSlice(key string) []string { + return vip.GetStringSlice(key) +} + func Get(key string) any { return vip.Get(key) } @@ -364,12 +373,12 @@ var DisplayKeys = map[string]bool{ } func LogConfig() { - log.Info("Final configuration:") + zap.L().Info("Final configuration: ") keys := vip.AllKeys() sort.Strings(keys) for _, key := range keys { if DisplayKeys[strings.ToUpper(key)] { - log.Infof("%v: %v", key, vip.Get(key)) + zap.L().Info(key, zap.Any("value", vip.Get(key))) } } } @@ -423,7 +432,7 @@ var userAddress []common.Address func IsAllowedUser(address *common.Address) bool { for _, user := range userAddress { - log.Println("userAddressFromConfig:" + user.Hex() + "<>" + address.Hex()) + zap.L().Info("user address from config", zap.String("value", user.Hex()+"<>"+address.Hex())) if user == *address { return true } @@ -448,3 +457,14 @@ func SetAllowedUsers() (err error) { } return nil } + +// NewJsonConfigFromString for tests +func NewJsonConfigFromString(config string) *viper.Viper { + v := viper.New() + v.SetConfigType("json") + err := v.ReadConfig(bytes.NewBufferString(config)) + if err != nil { + zap.L().Error("Error reading string config", zap.Error(err)) + } + return v +} diff --git a/config/config_test.go b/config/config_test.go index e17ac995..8fb9eb89 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -78,9 +78,9 @@ const jsonConfigString = ` }` func assertConfigIsEqualToJsonConfigString(t *testing.T, config *viper.Viper) { - assert.Equal(t, map[string]interface{}{"field": "value"}, config.Get("object")) + assert.Equal(t, map[string]any{"field": "value"}, config.Get("object")) assert.Equal(t, "value", config.Get("object.field")) - assert.Equal(t, []interface{}{"item-1", "item-2"}, config.Get("array")) + assert.Equal(t, []any{"item-1", "item-2"}, config.Get("array")) assert.Equal(t, "string-value", config.Get("string-key")) assert.Equal(t, 42, config.GetInt("int-key")) } diff --git a/config/configuration_schema.go b/config/configuration_schema.go index cbac244a..505dcf1c 100644 --- a/config/configuration_schema.go +++ b/config/configuration_schema.go @@ -93,7 +93,7 @@ func GetConfigurationSchema() ([]ConfigurationDetails, error) { } // ConvertStructToJSON converts the passed datastructure to a JSON -func ConvertStructToJSON(payLoad interface{}) ([]byte, error) { +func ConvertStructToJSON(payLoad any) ([]byte, error) { b, err := json.Marshal(&payLoad) if err != nil { return nil, err diff --git a/config/version.go b/config/version.go index fcb1cfb0..d76f6a02 100644 --- a/config/version.go +++ b/config/version.go @@ -2,70 +2,68 @@ package config import ( "encoding/json" + "errors" "fmt" - "io/ioutil" + "io" "net/http" "strings" ) -//Version configuration can be sent back easily on the response from Daemon +// Version configuration can be sent back easily on the response from Daemon var ( //latest Tag version versionTag string //sha1 revision used to build - sha1Revision string + sha1Revision string //Time when the binary was built - buildTime string - + buildTime string ) func GetVersionTag() string { return versionTag } - func GetSha1Revision() string { return sha1Revision } - func GetBuildTime() string { return buildTime } - -//This function is called to see if the current daemon is on the latest version , if it is not, indicate this to the user -//when the daemon starts. -func CheckVersionOfDaemon() (message string,err error) { - latestVersionFromGit,err := GetLatestDaemonVersion() - if len(versionTag) > 0 && err == nil { - if strings.Compare(latestVersionFromGit,versionTag) != 0 { - message = fmt.Sprintf("There is a newer version of the Daemon %v available. You are currently on %v, please consider upgrading.",latestVersionFromGit,versionTag) +// This function is called to see if the current daemon is on the latest version , if it is not, indicate this to the user +// when the daemon starts. +func CheckVersionOfDaemon() (message string, err error) { + var latestVersionFromGit string + message = "Daemon version is " + versionTag + latestVersionFromGit, err = GetLatestDaemonVersion() + if len(versionTag) > 0 && err == nil { + if strings.Compare(latestVersionFromGit, versionTag) != 0 { + err = errors.New(fmt.Sprintf("There is a newer version of the Daemon %v available. You are currently on %v, please consider upgrading.", latestVersionFromGit, versionTag)) } } - return message,err + return message, err } - -func GetLatestDaemonVersion() (version string,err error) { +func GetLatestDaemonVersion() (version string, err error) { resp, err := http.Get("https://api.github.com/repos/singnet/snet-daemon/releases/latest") if err != nil { - return "",err + return "", fmt.Errorf("error getting latest daemon version from github: %+v", err) } + defer resp.Body.Close() if resp.StatusCode == http.StatusOK { - if body, err := ioutil.ReadAll(resp.Body) ; err == nil { + if body, err := io.ReadAll(resp.Body); err == nil { var data GitTags if err = json.Unmarshal(body, &data); err == nil { - version = data.Tag_name + version = data.TagName } } } - defer resp.Body.Close() - return version,err + return version, err } type GitTags struct { - Tag_name string `json:"tag_name"` -} \ No newline at end of file + TagName string `json:"tag_name"` +} diff --git a/config/version_test.go b/config/version_test.go index 5724a5e9..19088051 100644 --- a/config/version_test.go +++ b/config/version_test.go @@ -54,9 +54,13 @@ func Test_getBuildTime(t *testing.T) { } func TestCheckVersionOfDaemon(t *testing.T) { - versionTag = "v0.1.9" - message ,err := CheckVersionOfDaemon() - assert.Nil(t, err) - assert.Contains(t,message,"There is a newer version of the Daemon") + versionTag = "v5.1.2" + message, err := CheckVersionOfDaemon() + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "There is a newer version of the Daemon") -} \ No newline at end of file + versionTag, _ = GetLatestDaemonVersion() + message, err = CheckVersionOfDaemon() + assert.Nil(t, err) + assert.Contains(t, message, "Daemon version is "+versionTag) +} diff --git a/configuration_service/configuration_service.go b/configuration_service/configuration_service.go index ba8f0417..daf8a247 100644 --- a/configuration_service/configuration_service.go +++ b/configuration_service/configuration_service.go @@ -4,15 +4,18 @@ package configuration_service import ( "bytes" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/singnet/snet-daemon/authutils" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" - "golang.org/x/net/context" + "go.uber.org/zap" + "math/big" "sort" "strings" + + "golang.org/x/net/context" ) type ConfigurationService struct { @@ -111,7 +114,7 @@ func (service ConfigurationService) authenticate(prefix string, auth *CallerAuth signerFromMessage, err := authutils.GetSignerAddressFromMessage(service.getMessageBytes(prefix, auth.CurrentBlock), auth.GetSignature()) if err != nil { - log.Error(err) + zap.L().Error(err.Error()) return err } //Check if the Signature is Valid and Signed accordingly diff --git a/configuration_service/configuration_service.proto b/configuration_service/configuration_service.proto index 258870fb..38e73831 100644 --- a/configuration_service/configuration_service.proto +++ b/configuration_service/configuration_service.proto @@ -60,7 +60,7 @@ message UpdateRequest { //Signature will compromise of the below // ("_UpdateRequest", "block_number",authentication_address) CallerAuthentication auth = 1; - //Indicates the updated configuration ( only the modified leaf and its changed value is passed ) Example (log.output.rotation_time_in_sec is a valid key ) + //Indicates the updated configuration ( only the modified leaf and its changed value is passed ) Example (log.output.max_size_in_mb is a valid key ) map updated_configuration = 2; diff --git a/configuration_service/configuration_service_test.go b/configuration_service/configuration_service_test.go index 6ef815cd..2b04e6e7 100644 --- a/configuration_service/configuration_service_test.go +++ b/configuration_service/configuration_service_test.go @@ -2,12 +2,13 @@ package configuration_service import ( "bytes" + "math/big" + "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/singnet/snet-daemon/authutils" - "math/big" - "testing" "github.com/singnet/snet-daemon/config" "github.com/stretchr/testify/assert" diff --git a/escrow/README.md b/escrow/README.md index b093894a..76283bfb 100644 --- a/escrow/README.md +++ b/escrow/README.md @@ -12,12 +12,12 @@
-| Type of Request | Check for State or Execute Service | Block chain Mode | allowed User Flag | Request | Signature expected | Method Called | Response sent | Comments | -|-----------------|------------------------------------------------------------------------------------------------|------------------|-------------------|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Paid Call | [Grpc State call](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto) | true | NA | [message ChannelStateRequest](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L20-L30) |"__get_channel_state"+MpeAddress+channelID+CurrentBlockNumber
[Bytes Constructed](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.go#L79-L84)| [rpc GetChannelState\(ChannelStateRequest\) returns \(ChannelStateReply\) \{\}](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L14-L17) | [message ChannelStateReply](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L36-L53) | Only channel signer/sender/receiver can get latest channel state . Current Block Number passed needs to be +-10 from the latest block number retrieved from the blockchain | -| Paid Call | [Grpc State call](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto) | false | NA | [message ChannelStateRequest](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L20-L30) | NA| [rpc GetChannelState\(ChannelStateRequest\) returns \(ChannelStateReply\) \{\}](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L14-L17) | [message ChannelStateReply](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L36-L53) | Same response is sent every time,Caller would not know if the block chain mode is enabled or disabled.The Signature sent is ignored. | -|Paid Call|Execute Service |true|true or false|Metadata Passed to Daemon should consist of the below header
"snet-payment-type"="escrow"
"snet-payment-channel-id" = "Channeld"
"snet-payment-channel-nonce"="Nonce"
"snet-payment-channel-amount" ="TotalAmount"
"snet-payment-channel-signature-bin"="Signature"|"__MPE_claim_message"+MpeContractAddress+ChannelID+ChannelNonce+SignedAmount
[Bytes Constructed](https://github.com/singnet/snet-daemon/blob/3fb726ac903888efd03de4443f06a5cd294ae9f9/escrow/validation.go#L173-L179)|Call to the method in Service |Response sent by Service | Only channel signer/sender can sign.
, Please note the Total Amount = Amount (retrieved from State call) + Price of the current call , latest nonce is also retrieved from the state call
if the allowed_user flag is true , then Make sure the Signer is also in the list of allowed users defined in the Daemon config.
Please note the [allowed user flag](https://github.com/singnet/snet-daemon/blob/master/README.md#allowed_users_flag) is applicable only in test networks like sepolia/goerli etc; but not in mainnet | -|Free Call|Execute Service |true|true or false|Metadata Passed to Daemon should consist of the below header
"snet-payment-type"="freecall"
""snet-free-call-user-id" = "user-id"
"snet-free-call-auth-token-bin"="Auth Token downloaded"
"snet-free-call-token-expiry-block" ="Token Expiry date"
"snet-current-block-number"="CurrentBlockNumber"
"snet-payment-channel-signature-bin"="Signture"| Signature = "__prefix_free_trial"+"user-id"+"organization_id"+"service_id"+BlockNumber+"AuthToken", now check if Auth-token = "user@mail"+"user-public-key"+ "token_issue_date"
from the first signature get the user-public-key, and use this to validate the AuthToken
[Bytes Constructed](https://github.com/singnet/snet-daemon/blob/3fb726ac903888efd03de4443f06a5cd294ae9f9/escrow/validation.go#L173-L179)|Call to the method in Service |Response sent by Service | Only channel signer/sender can sign.
, Please note the Total Amount = Amount (retrieved from State call) + Price of the current call , latest nonce is also retrieved from the state call
if the allowed_user flag is true , then Make sure the Signer is also in the list of allowed users defined in the Daemon config.
Please note the [allowed user flag](https://github.com/singnet/snet-daemon/blob/master/README.md#allowed_users_flag) is applicable only in test networks like sepolia/goerli etc; but not in mainnet | +| Type of Request | Check for State or Execute Service | Block chain Mode | allowed User Flag | Request | Signature expected | Method Called | Response sent | Comments | +|-----------------|------------------------------------------------------------------------------------------------|------------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Paid Call | [Grpc State call](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto) | true | NA | [message ChannelStateRequest](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L20-L30) |"__get_channel_state"+MpeAddress+channelID+CurrentBlockNumber
[Bytes Constructed](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.go#L79-L84)| [rpc GetChannelState\(ChannelStateRequest\) returns \(ChannelStateReply\) \{\}](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L14-L17) | [message ChannelStateReply](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L36-L53) | Only channel signer/sender/receiver can get latest channel state . Current Block Number passed needs to be +-10 from the latest block number retrieved from the blockchain | +| Paid Call | [Grpc State call](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto) | false | NA | [message ChannelStateRequest](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L20-L30) | NA| [rpc GetChannelState\(ChannelStateRequest\) returns \(ChannelStateReply\) \{\}](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L14-L17) | [message ChannelStateReply](https://github.com/singnet/snet-daemon/blob/master/escrow/state_service.proto#L36-L53) | Same response is sent every time,Caller would not know if the block chain mode is enabled or disabled.The Signature sent is ignored. | +|Paid Call|Execute Service |true|true or false| Metadata Passed to Daemon should consist of the below header
"snet-payment-type"="escrow"
"snet-payment-channel-id" = "Channeld"
"snet-payment-channel-nonce"="Nonce"
"snet-payment-channel-amount" ="TotalAmount"
"snet-payment-channel-signature-bin"="Signature" |"__MPE_claim_message"+MpeContractAddress+ChannelID+ChannelNonce+SignedAmount
[Bytes Constructed](https://github.com/singnet/snet-daemon/blob/3fb726ac903888efd03de4443f06a5cd294ae9f9/escrow/validation.go#L173-L179)|Call to the method in Service |Response sent by Service | Only channel signer/sender can sign.
, Please note the Total Amount = Amount (retrieved from State call) + Price of the current call , latest nonce is also retrieved from the state call
if the allowed_user flag is true , then Make sure the Signer is also in the list of allowed users defined in the Daemon config.
Please note the [allowed user flag](https://github.com/singnet/snet-daemon/blob/master/README.md#allowed_users_flag) is applicable only in test networks like sepolia/goerli etc; but not in mainnet | +|Free Call|Execute Service |true|true or false| Metadata Passed to Daemon should consist of the below header
"snet-payment-type"="free-call"
""snet-free-call-user-id" = "user-id"
"snet-free-call-auth-token-bin"="Auth Token downloaded"
"snet-free-call-token-expiry-block" ="Token Expiry date"
"snet-current-block-number"="CurrentBlockNumber"
"snet-payment-channel-signature-bin"="Signture" | Signature = "__prefix_free_trial"+"user-id"+"organization_id"+"service_id"+BlockNumber+"AuthToken", now check if Auth-token = "user@mail"+"user-public-key"+ "token_issue_date"
from the first signature get the user-public-key, and use this to validate the AuthToken
[Bytes Constructed](https://github.com/singnet/snet-daemon/blob/3fb726ac903888efd03de4443f06a5cd294ae9f9/escrow/validation.go#L173-L179)|Call to the method in Service |Response sent by Service | Only channel signer/sender can sign.
, Please note the Total Amount = Amount (retrieved from State call) + Price of the current call , latest nonce is also retrieved from the state call
if the allowed_user flag is true , then Make sure the Signer is also in the list of allowed users defined in the Daemon config.
Please note the [allowed user flag](https://github.com/singnet/snet-daemon/blob/master/README.md#allowed_users_flag) is applicable only in test networks like sepolia/goerli etc; but not in mainnet |
[Details on headers](https://github.com/singnet/snet-daemon/blob/master/handler/interceptors.go#L24-L43) diff --git a/escrow/control_service.go b/escrow/control_service.go index f3ebbf6e..333bf250 100644 --- a/escrow/control_service.go +++ b/escrow/control_service.go @@ -5,14 +5,16 @@ import ( "bytes" "errors" "fmt" + "math/big" + "sort" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/singnet/snet-daemon/authutils" "github.com/singnet/snet-daemon/blockchain" - log "github.com/sirupsen/logrus" + + "go.uber.org/zap" "golang.org/x/net/context" - "math/big" - "sort" ) type ProviderControlService struct { @@ -62,6 +64,8 @@ func NewProviderControlService(channelService PaymentChannelService, serMetaData } /* + GetListUnclaimed + Get list of unclaimed payments, we do this by getting the list of channels in progress which have some amount to be claimed. Verify that mpe_address is correct Verify that actual block_number is not very different (+-5 blocks) from the current_block_number from the signature @@ -108,7 +112,7 @@ func (service *ProviderControlService) StartClaimForMultipleChannels(ctx context } err = service.removeClaimedPayments() if err != nil { - log.Errorf("unable to remove payments from which are already claimed") + zap.L().Error("unable to remove payments from which are already claimed") return nil, err } return service.startClaims(request) @@ -198,7 +202,7 @@ func (service *ProviderControlService) GetListInProgress(ctx context.Context, re } err = service.removeClaimedPayments() if err != nil { - log.Errorf("unable to remove payments from which are already claimed") + zap.L().Error("unable to remove payments from which are already claimed") return nil, err } return service.listClaims() @@ -212,19 +216,19 @@ func (service *ProviderControlService) GetListInProgress(ctx context.Context, re // Check for any claims already done on block chain but have not been reflected in the storage yet, // update the storage status by calling the Finish() method on such claims func (service *ProviderControlService) StartClaim(ctx context.Context, startClaim *StartClaimRequest) (paymentReply *PaymentReply, err error) { - //Check if the mpe address matches to what is there in service metadata + // Check if the mpe address matches to what is there in service metadata if err := service.checkMpeAddress(startClaim.MpeAddress); err != nil { return nil, err } - //Verify signature , check if “payment_address” matches to what is there in metadata + // Verify signature, check if “payment_address” matches to what is there in metadata err = service.verifySignerForStartClaim(startClaim) if err != nil { return nil, err } - //Remove any payments already claimed on block chain + // Remove any payments already claimed on blockchain err = service.removeClaimedPayments() if err != nil { - log.Error("unable to remove payments from etcd storage which are already claimed in block chain") + zap.L().Error("unable to remove payments from etcd storage which are already claimed in block chain") return nil, err } return service.beginClaimOnChannel(bytesToBigInt(startClaim.GetChannelId())) @@ -232,7 +236,7 @@ func (service *ProviderControlService) StartClaim(ctx context.Context, startClai // get the list of channels in progress which have some amount to be claimed. func (service *ProviderControlService) listChannels() (*PaymentsListReply, error) { - //get the list of channels in progress which have some amount to be claimed. + // get the list of channels from storage in progress which have some amount to be claimed. channels, err := service.channelService.ListChannels() if err != nil { return nil, err @@ -274,7 +278,7 @@ func (service *ProviderControlService) getMessageBytes(prefixMessage string, req func (service *ProviderControlService) verifySigner(message []byte, signature []byte) error { signer, err := authutils.GetSignerAddressFromMessage(message, signature) if err != nil { - log.Error(err) + zap.L().Error(err.Error()) return err } if err = authutils.VerifyAddress(*signer, service.organizationMetaData.GetPaymentAddress()); err != nil { @@ -284,7 +288,7 @@ func (service *ProviderControlService) verifySigner(message []byte, signature [] } // Begin the claim process on the current channel and Increment the channel nonce and -// decrease the full amount to allow channel sender to continue working with remaining amount. +// decrease the full amount to allow channel sender to continue working with the remaining amount. func (service *ProviderControlService) beginClaimOnChannel(channelId *big.Int) (*PaymentReply, error) { latestChannel, ok, err := service.channelService.PaymentChannel(&PaymentChannelKey{ID: channelId}) if err != nil { @@ -314,7 +318,7 @@ func (service *ProviderControlService) beginClaimOnChannel(channelId *big.Int) ( return paymentReply, nil } -// Verify if the signer is same as the payment address in metadata +// Verify if the signer is the same as the payment address in metadata // __start_claim”, mpe_address, channel_id, channel_nonce func (service *ProviderControlService) verifySignerForStartClaim(startClaim *StartClaimRequest) error { channelId := bytesToBigInt(startClaim.GetChannelId()) @@ -336,21 +340,22 @@ func (service *ProviderControlService) listClaims() (*PaymentsListReply, error) //retrieve all the claims in progress claimsRetrieved, err := service.channelService.ListClaims() if err != nil { - log.Error("error in retrieving claims") + zap.L().Error("error in retrieving claims") return nil, err } output := make([]*PaymentReply, 0) for _, claimRetrieved := range claimsRetrieved { payment := claimRetrieved.Payment() - //To Get the Expiration of the Channel ( always get the latest state) + // To Get the Expiration of the Channel (always get the latest state) latestChannel, ok, err := service.channelService.PaymentChannel(&PaymentChannelKey{ID: payment.ChannelID}) if !ok || err != nil { - log.Errorf("Unable to retrieve the latest Channel State, ChannelID: %v, ChannelNonde: %v", payment.ChannelID, payment.ChannelNonce) + zap.L().Error("Unable to retrieve the latest Channel State", zap.Any("ChanelID", payment.ChannelID), zap.Any("ChannelNonce", payment.ChannelNonce)) continue } if payment.Signature == nil || payment.Amount.Int64() == 0 { - log.Errorf("The Signature or the Amount is not defined on the Payment with"+ - " Channel Id:%v , Nonce:%v", payment.ChannelID, payment.ChannelNonce) + zap.L().Error("The Signature or the Amount is not defined on the Payment with", + zap.Any("ChannelID", payment.ChannelID), + zap.Any("ChannelNonce", payment.ChannelNonce)) continue } paymentReply := &PaymentReply{ @@ -373,10 +378,10 @@ func (service *ProviderControlService) verifySignerForListInProgress(request *Ge return service.verifySigner(service.getMessageBytes("__list_in_progress", request), request.GetSignature()) } -// No write operation on block chains are done by Daemon (will be take care of by the snet client ) -// Finish on the claim should be called only after the payment is successfully claimed and block chain is updated accordingly. -// One way to determine this is by checking the nonce in the block chain with the nonce in the payment, -// for a given channel if the block chain nonce is greater than that of the nonce from etcd storage => that the claim is already done in block chain. +// No write operation on blockchain are done by Daemon (will be take care of by the snet client) +// Finish on the claim should be called only after the payment is successfully claimed and blockchain is updated accordingly. +// One way to determine this is by checking the nonce in the blockchain with the nonce in the payment, +// for a given channel if the blockchain nonce is greater than that of the nonce from etcd storage => that the claim is already done in blockchain. // and the Finish method is called on the claim. func (service *ProviderControlService) removeClaimedPayments() error { //Get the pending claims @@ -395,12 +400,13 @@ func (service *ProviderControlService) removeClaimedPayments() error { if blockChainChannel.Nonce.Cmp(payment.ChannelNonce) > 0 { //if the Nonce on this block chain is higher than that of the Payment, //means that the payment has been completed , hence update the etcd state with this - log.Debugf("for channel id: %v the nonce of channel from Block chain (%v) is "+ - "greater than nonce of channel from etcd storage (%v)", - payment.ChannelID, blockChainChannel.Nonce, payment.ChannelNonce) + zap.L().Debug("the nonce of channel from Blockchain is greater than nonce of channel from etcd storage", + zap.Any("ChannelID", payment.ChannelID), + zap.Any("BlockchainNonce", blockChainChannel.Nonce), + zap.Any("ChannelNonce", payment.ChannelNonce)) err = claimRetrieved.Finish() if err != nil { - log.Error(err) + zap.L().Error(err.Error()) return err } } diff --git a/escrow/escrow.go b/escrow/escrow.go index 3d6746ae..5e043ad4 100644 --- a/escrow/escrow.go +++ b/escrow/escrow.go @@ -2,7 +2,8 @@ package escrow import ( "fmt" - log "github.com/sirupsen/logrus" + + "go.uber.org/zap" ) // lockingPaymentChannelService implements PaymentChannelService interface @@ -49,7 +50,7 @@ func (h *lockingPaymentChannelService) PaymentChannel(key *PaymentChannelKey) (c blockchainChannel, blockchainOk, err := h.blockchainReader.GetChannelStateFromBlockchain(key) if !storageOk { - //Group ID check is only done for the first time , when the channel is added to storage from the block chain , + // Group ID check is only done for the first time , when the channel is added to storage from the block chain , //if the channel is already present in the storage the group ID check is skipped. if blockchainChannel != nil { blockChainGroupID, err := h.replicaGroupID() @@ -66,10 +67,10 @@ func (h *lockingPaymentChannelService) PaymentChannel(key *PaymentChannelKey) (c return MergeStorageAndBlockchainChannelState(storageChannel, blockchainChannel), true, nil } -//Check if the channel belongs to the same group Id +// Check if the channel belongs to the same group ID func (h *lockingPaymentChannelService) verifyGroupId(configGroupID [32]byte, blockChainGroupID [32]byte) error { if blockChainGroupID != configGroupID { - log.WithField("configGroupId", configGroupID).Warn("Channel received belongs to another group of replicas") + zap.L().Warn("Channel received belongs to another group of replicas", zap.Any("configGroupId", configGroupID)) return fmt.Errorf("Channel received belongs to another group of replicas, current group: %v, channel group: %v", configGroupID, blockChainGroupID) } return nil @@ -95,7 +96,7 @@ func (claim *claimImpl) Finish() (err error) { func (h *lockingPaymentChannelService) StartClaim(key *PaymentChannelKey, update ChannelUpdate) (claim Claim, err error) { lock, ok, err := h.locker.Lock(key.String()) if err != nil { - log.WithError(err).WithField("PaymentChannelKey", key).Error("StartClaim, unable to get lock!") + zap.L().Error("StartClaim, unable to get lock!", zap.Any("PaymentChannelKey", key)) return nil, fmt.Errorf("cannot get mutex for channel: %v because of %v", key, err) } if !ok { @@ -104,14 +105,15 @@ func (h *lockingPaymentChannelService) StartClaim(key *PaymentChannelKey, update defer func() { e := lock.Unlock() if e != nil { - log.WithError(e).WithField("key", key).WithField("err", err).Error("Transaction is cancelled because of err, but channel cannot be unlocked. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.") + zap.L().Error("Transaction is cancelled because of err, but channel cannot be unlocked. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.", + zap.Any("key", key), + zap.Error(err)) } }() channel, ok, err := h.storage.Get(key) if err != nil { - log.WithError(err).WithField("channelKey", key).Error("StartClaim, unable to get channel from Storage!") - + zap.L().Error("StartClaim, unable to get channel from Storage!", zap.Any("channelKey", key)) return } if !ok { @@ -130,8 +132,9 @@ func (h *lockingPaymentChannelService) StartClaim(key *PaymentChannelKey, update err = h.paymentStorage.Put(payment) if err != nil { - log.WithError(err) - log.WithField("payment", payment).Error("Cannot write payment into payment storage. Channel storage is already updated. Payment should be handled manually.") + zap.L().Error("Cannot write payment into payment storage. Channel storage is already updated. Payment should be handled manually.", + zap.Error(err), + zap.Any("payment", payment)) return } @@ -190,7 +193,7 @@ func (h *lockingPaymentChannelService) StartPaymentTransaction(payment *Payment) lock, ok, err := h.locker.Lock(channelKey.String()) if err != nil { - log.WithError(err).WithField("channelKey", channelKey).Error("StartPaymentTransaction, unable to get lock!") + zap.L().Error("StartPaymentTransaction, unable to get lock!", zap.Error(err), zap.Any("channelKey", channelKey)) return nil, NewPaymentError(Internal, "cannot get mutex for channel: %v", channelKey) } if !ok { @@ -200,18 +203,20 @@ func (h *lockingPaymentChannelService) StartPaymentTransaction(payment *Payment) if err != nil { e := lock.Unlock() if e != nil { - log.WithError(e).WithField("channelKey", channelKey).WithField("err", err).Error("Transaction is cancelled because of err, but channel cannot be unlocked. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.") + zap.L().Error("Transaction is cancelled because of err, but channel cannot be unlocked. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.", + zap.Error(err), + zap.Any("channelKey", channelKey)) } } }(lock) channel, ok, err := h.PaymentChannel(channelKey) if err != nil { - log.WithError(err).WithField("channelKey", channelKey).Error("StartPaymentTransaction, unable to get channel!") + zap.L().Error("StartPaymentTransaction, unable to get channel!", zap.Error(err), zap.Any("channelKey", channelKey)) return nil, NewPaymentError(Internal, "payment channel error:"+err.Error()) } if !ok { - log.Warn("Payment channel not found") + zap.L().Warn("Payment channel not found") return nil, NewPaymentError(Unauthenticated, "payment channel \"%v\" not found", channelKey) } @@ -232,13 +237,14 @@ func (payment *paymentTransaction) Commit() error { defer func(payment *paymentTransaction) { err := payment.lock.Unlock() if err != nil { - log.WithError(err).WithField("payment", payment).Error("Channel cannot be unlocked because of error. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.") + zap.L().Error("Channel cannot be unlocked because of error. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.", + zap.Error(err), zap.Any("payment", payment)) } else { - log.Debug("Channel unlocked") + zap.L().Debug("Channel unlocked") } }(payment) - e := payment.service.storage.Put( + err := payment.service.storage.Put( &PaymentChannelKey{ID: payment.payment.ChannelID}, &PaymentChannelData{ ChannelID: payment.channel.ChannelID, @@ -254,12 +260,12 @@ func (payment *paymentTransaction) Commit() error { GroupID: payment.channel.GroupID, }, ) - if e != nil { - log.WithError(e).Error("Unable to store new payment channel state") + if err != nil { + zap.L().Error("Unable to store new payment channel state", zap.Error(err)) return NewPaymentError(Internal, "unable to store new payment channel state") } - log.Debug("Payment completed") + zap.L().Debug("Payment completed") return nil } @@ -267,9 +273,11 @@ func (payment *paymentTransaction) Rollback() error { defer func(payment *paymentTransaction) { err := payment.lock.Unlock() if err != nil { - log.WithError(err).WithField("payment", payment).Error("Channel cannot be unlocked because of error. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.") + zap.L().Error("Channel cannot be unlocked because of error. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.", + zap.Error(err), + zap.Any("payment", payment)) } else { - log.Debug("Payment rolled back, channel unlocked") + zap.L().Debug("Payment rolled back, channel unlocked") } }(payment) return nil diff --git a/escrow/free_call.go b/escrow/free_call.go index a37d80b0..ecf101c4 100644 --- a/escrow/free_call.go +++ b/escrow/free_call.go @@ -2,8 +2,10 @@ package escrow import ( "fmt" + "github.com/singnet/snet-daemon/blockchain" - log "github.com/sirupsen/logrus" + "github.com/singnet/snet-daemon/config" + "go.uber.org/zap" ) type lockingFreeCallUserService struct { @@ -63,6 +65,7 @@ func (h *lockingFreeCallUserService) GetFreeCallUserKey(payment *FreeCallPayment return &FreeCallUserKey{UserId: payment.UserId, OrganizationId: payment.OrganizationId, ServiceId: payment.ServiceId, GroupID: blockchain.BytesToBase64(groupId[:])}, err } + func (h *lockingFreeCallUserService) StartFreeCallUserTransaction(payment *FreeCallPayment) (transaction FreeCallTransaction, err error) { userKey, err := h.GetFreeCallUserKey(payment) if err != nil { @@ -78,7 +81,7 @@ func (h *lockingFreeCallUserService) StartFreeCallUserTransaction(payment *FreeC return nil, NewPaymentError(Internal, "payment freeCallUserData error:"+err.Error()) } if !ok { - log.Warn("Payment freeCallUserData not found") + zap.L().Warn("Payment freeCallUserData not found") return nil, NewPaymentError(Unauthenticated, "payment freeCallUserData \"%v\" not found", userKey) } @@ -93,16 +96,23 @@ func (h *lockingFreeCallUserService) StartFreeCallUserTransaction(payment *FreeC if err != nil { e := lock.Unlock() if e != nil { - //todo send a notification to the devloper ( contact email is in service metadata) - log.WithError(e).WithField("userKey", userKey).WithField("err", err).Error("Transaction is cancelled because of err, but freeCallUserData cannot be unlocked. All other transactions on this freeCallUserData will be blocked until unlock. Please unlock freeCallUserData manually.") + //todo send a notification to the developer ( contact email is in service metadata) + zap.L().Error("Transaction is cancelled because of err, but freeCallUserData cannot be unlocked. All other transactions on this freeCallUserData will be blocked until unlock. Please unlock freeCallUserData manually.", + zap.Any("userKey", userKey), + zap.Error(err)) } } }(lock) - //Check if free calls are allowed or not on this user - if freeCallUserData.FreeCallsMade >= h.serviceMetadata.GetFreeCallsAllowed() { + var countFreeCallsAllowed int + if countFreeCallsAllowed = config.GetFreeCallsCount(freeCallUserData.UserId); countFreeCallsAllowed <= 0 { + countFreeCallsAllowed = h.serviceMetadata.GetFreeCallsAllowed() + } + + // Check if free calls are allowed or not on this user + if freeCallUserData.FreeCallsMade >= countFreeCallsAllowed { return nil, fmt.Errorf("free call limit has been exceeded, calls made "+ - "= %v,total free calls eligible = %v", freeCallUserData.FreeCallsMade, h.serviceMetadata.GetFreeCallsAllowed()) + "= %v,total free calls eligible = %v", freeCallUserData.FreeCallsMade, countFreeCallsAllowed) } return &freeCallTransaction{ payment: *payment, @@ -118,26 +128,25 @@ func (transaction *freeCallTransaction) Commit() error { err := payment.lock.Unlock() if err != nil { //todo send a notification to the developer defined in service metadata - log.WithError(err).WithField("transaction", payment). - Error("free call user cannot be unlocked because of error." + - " All other transactions on this channel will be blocked until unlock." + - " Please unlock user for free calls manually.") + zap.L().Error("free call user cannot be unlocked because of error."+ + " All other transactions on this channel will be blocked until unlock."+ + " Please unlock user for free calls manually.", zap.Any("transaction", payment), zap.Error(err)) } else { - log.Debug("free call user unlocked") + zap.L().Debug("free call user unlocked") } }(transaction) IncrementFreeCallCount(transaction.FreeCallUser()) - e := transaction.service.storage.Put( + err := transaction.service.storage.Put( transaction.freeCallUserKey, transaction.FreeCallUser(), ) - if e != nil { - log.WithError(e).Error("Unable to store new transaction free call user state") + if err != nil { + zap.L().Error("Unable to store new transaction free call user state") return NewPaymentError(Internal, "unable to store new transaction free call user state") } - log.Debug("Free Call Payment completed") + zap.L().Debug("Free Call Payment completed") return nil } @@ -145,9 +154,10 @@ func (payment *freeCallTransaction) Rollback() error { defer func(payment *freeCallTransaction) { err := payment.lock.Unlock() if err != nil { - log.WithError(err).WithField("payment", payment).Error("free call user cannot be unlocked because of error. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.") + zap.L().Error("free call user cannot be unlocked because of error. All other transactions on this channel will be blocked until unlock. Please unlock channel manually.", + zap.Error(err), zap.Any("payment", payment)) } else { - log.Debug("Free call Payment rolled back, free call user unlocked") + zap.L().Debug("Free call Payment rolled back, free call user unlocked") } }(payment) return nil diff --git a/escrow/free_call_api.go b/escrow/free_call_api.go index 247d67fa..a2f08759 100644 --- a/escrow/free_call_api.go +++ b/escrow/free_call_api.go @@ -7,21 +7,21 @@ import ( // To Support Free calls type FreeCallPayment struct { - //Has the Id of the user making the call + // Has the ID of the user making the call UserId string - //Service Id . + // Service ID ServiceId string - //Organization Id + // Organization Id OrganizationId string - //Current block number + // Current block number CurrentBlockNumber *big.Int // Signature passed Signature []byte - //Group ID + // Group ID GroupId string - //Auth Token Passed + // Auth Token Passed AuthToken []byte - //Token expiration date in blocks + // Token expiration date in blocks AuthTokenExpiryBlockNumber *big.Int } diff --git a/escrow/free_call_state_service.go b/escrow/free_call_state_service.go index 5330ee2a..c471f732 100644 --- a/escrow/free_call_state_service.go +++ b/escrow/free_call_state_service.go @@ -2,11 +2,13 @@ package escrow import ( "fmt" + "math/big" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" + "golang.org/x/net/context" - "math/big" ) type FreeCallStateService struct { @@ -37,7 +39,7 @@ func (service *BlockChainDisabledFreeCallStateService) mustEmbedUnimplementedFre func (service *FreeCallStateService) GetFreeCallsAvailable(context context.Context, request *FreeCallStateRequest) (reply *FreeCallStateReply, err error) { if err = service.verify(request); err != nil { - log.WithError(err).Errorf("Error in authorizing the request") + zap.L().Error("Error in authorizing the request", zap.Error(err)) return nil, err } availableCalls, err := service.checkForFreeCalls(service.getFreeCallPayment(request)) @@ -60,7 +62,7 @@ func (service *FreeCallStateService) verify(request *FreeCallStateRequest) (err } func (service *FreeCallStateService) checkForFreeCalls(payment *FreeCallPayment) (callsAvailable int, err error) { - //Now get the state from etcd for this user , if there are no records , then return the free calls + //Now get the state from etcd for this user, if there are no records, then return the free calls key, err := service.freeCallService.GetFreeCallUserKey(payment) if err != nil { return 0, err @@ -72,8 +74,10 @@ func (service *FreeCallStateService) checkForFreeCalls(payment *FreeCallPayment) if err != nil { return 0, err } - callsAvailable = service.serviceMetadata.GetFreeCallsAllowed() - data.FreeCallsMade - return callsAvailable, nil + if freeCallsAllowed := config.GetFreeCallsCount(key.UserId); freeCallsAllowed > 0 { + return freeCallsAllowed - data.FreeCallsMade, err + } + return service.serviceMetadata.GetFreeCallsAllowed() - data.FreeCallsMade, nil } func (service *FreeCallStateService) getFreeCallPayment(request *FreeCallStateRequest) *FreeCallPayment { diff --git a/escrow/free_call_storage.go b/escrow/free_call_storage.go index 1bc56207..3afe9181 100644 --- a/escrow/free_call_storage.go +++ b/escrow/free_call_storage.go @@ -31,7 +31,7 @@ func NewFreeCallUserStorage(atomicStorage storage.AtomicStorage) *FreeCallUserSt }*/ } -func serializeFreeCallKey(key interface{}) (serialized string, err error) { +func serializeFreeCallKey(key any) (serialized string, err error) { myKey := key.(*FreeCallUserKey) return myKey.String(), nil } diff --git a/escrow/income.go b/escrow/income.go index a8a7993e..18a40e39 100644 --- a/escrow/income.go +++ b/escrow/income.go @@ -41,9 +41,9 @@ func NewIncomeValidator(pricing *pricing.PricingStrategy) (validator IncomeValid } func (validator *incomeValidator) Validate(data *IncomeData) (err error) { -//TO DO, the user request information from IncomeData needs to be passed here !!!! - price,err := validator.priceStrategy.GetPrice(data.GrpcContext) - if err != nil { + //TO DO, the user request information from IncomeData needs to be passed here !!!! + price, err := validator.priceStrategy.GetPrice(data.GrpcContext) + if err != nil { return err } diff --git a/escrow/lock.go b/escrow/lock.go index 6956b630..f7eceefa 100644 --- a/escrow/lock.go +++ b/escrow/lock.go @@ -2,7 +2,7 @@ package escrow import ( "github.com/singnet/snet-daemon/storage" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" ) // Lock is an aquired lock. @@ -68,7 +68,7 @@ func (lock *lockType) Unlock() (err error) { return } if !ok { - log.WithField("lock.name", lock.name).Error("lock is unlocked already") + zap.L().Error("lock is unlocked already", zap.String("lock.name", lock.name)) } return } diff --git a/escrow/payment_channel_api.go b/escrow/payment_channel_api.go index cf83fde1..86640a0d 100644 --- a/escrow/payment_channel_api.go +++ b/escrow/payment_channel_api.go @@ -158,7 +158,7 @@ type PaymentError struct { // NewPaymentError constructs new PaymentError instance with given error code // and message. -func NewPaymentError(code PaymentErrorCode, format string, msg ...interface{}) *PaymentError { +func NewPaymentError(code PaymentErrorCode, format string, msg ...any) *PaymentError { return &PaymentError{Code: code, Message: fmt.Sprintf(format, msg...)} } diff --git a/escrow/payment_channel_storage.go b/escrow/payment_channel_storage.go index 2b9548d8..e402e9e2 100644 --- a/escrow/payment_channel_storage.go +++ b/escrow/payment_channel_storage.go @@ -4,12 +4,13 @@ import ( "bytes" "encoding/gob" "fmt" + "math/big" + "reflect" + "github.com/ethereum/go-ethereum/common" "github.com/singnet/snet-daemon/storage" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" - "math/big" - "reflect" + "go.uber.org/zap" "github.com/singnet/snet-daemon/blockchain" ) @@ -32,10 +33,10 @@ func NewPaymentChannelStorage(atomicStorage storage.AtomicStorage) *PaymentChann } -func serializeKey(key interface{}) (slice string, err error) { +func serializeKey(key any) (slice string, err error) { return fmt.Sprintf("%v", key), nil } -func serialize(value interface{}) (slice string, err error) { +func serialize(value any) (slice string, err error) { var b bytes.Buffer e := gob.NewEncoder(&b) err = e.Encode(value) @@ -47,7 +48,7 @@ func serialize(value interface{}) (slice string, err error) { return } -func deserialize(slice string, value interface{}) (err error) { +func deserialize(slice string, value any) (err error) { b := bytes.NewBuffer([]byte(slice)) d := gob.NewDecoder(b) err = d.Decode(value) @@ -111,16 +112,16 @@ func NewBlockchainChannelReader(processor *blockchain.Processor, cfg *viper.Vipe func (reader *BlockchainChannelReader) GetChannelStateFromBlockchain(key *PaymentChannelKey) (channel *PaymentChannelData, ok bool, err error) { ch, ok, err := reader.readChannelFromBlockchain(key.ID) if err != nil || !ok { - log.Debugln(err) + zap.L().Warn("Unsuccessful GetChannelStateFromBlockchain", zap.Error(err), zap.Bool("ok", ok)) return } recipientPaymentAddress := reader.recipientPaymentAddress() if recipientPaymentAddress != ch.Recipient { - log.WithField("recipientPaymentAddress", recipientPaymentAddress). - WithField("ch.Recipient", ch.Recipient). - Warn("Recipient Address from service metadata not Match on what was retrieved from Channel") + zap.L().Warn("Recipient Address from service metadata not Match on what was retrieved from Channel", + zap.Any("recipientPaymentAddress", recipientPaymentAddress), + zap.Any("ch.Recipient", ch.Recipient)) return nil, false, fmt.Errorf("recipient Address from service metadata does not Match on what was retrieved from Channel") } return &PaymentChannelData{ diff --git a/escrow/payment_handler.go b/escrow/payment_handler.go index beab619c..8b68d91b 100644 --- a/escrow/payment_handler.go +++ b/escrow/payment_handler.go @@ -1,16 +1,17 @@ package escrow import ( - "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "go.uber.org/zap" "google.golang.org/grpc/codes" "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" "github.com/singnet/snet-daemon/handler" "github.com/singnet/snet-daemon/metrics" - log "github.com/sirupsen/logrus" - "math/big" ) const ( @@ -102,11 +103,11 @@ func (h *paymentChannelPaymentHandler) Complete(payment handler.Payment) (err *h return err } -func PublishChannelStats(payment handler.Payment) (err *handler.GrpcError) { +func PublishChannelStats(payment handler.Payment) (grpcErr *handler.GrpcError) { if !config.GetBool(config.MeteringEnabled) { - err = handler.NewGrpcErrorf(codes.Internal, "Cannot post latest offline channel state as metering is disabled !!") - log.WithError(err.Err()).Error("Error in payment channel payment handler commit") - return err + grpcErr = handler.NewGrpcErrorf(codes.Internal, "Cannot post latest offline channel state as metering is disabled !!") + zap.L().Error("Error in payment channel payment handler commit", zap.Error(grpcErr.Err())) + return grpcErr } paymentTransaction := payment.(*paymentTransaction) channelStats := &metrics.ChannelStats{ChannelId: paymentTransaction.payment.ChannelID, @@ -119,13 +120,13 @@ func PublishChannelStats(payment handler.Payment) (err *handler.GrpcError) { channelStats.OrganizationID = config.GetString(config.OrganizationId) channelStats.ServiceID = config.GetString(config.ServiceId) - log.Debugf("Payment channel payment handler is publishing channel statistics: %v", channelStats) + zap.L().Debug("Payment channel payment handler is publishing channel statistics", zap.Any("ChannelStats", channelStats)) commonStats := &metrics.CommonStats{ GroupID: channelStats.GroupID, UserName: paymentTransaction.Channel().Sender.Hex()} status := metrics.Publish(channelStats, serviceURL, commonStats) if !status { - log.WithError(fmt.Errorf("Payment channel payment handler unable to post latest off-chain Channel state on contract API End point %s", serviceURL)) + log.Error("Payment channel payment handler unable to post latest off-chain Channel state on contract API Endpoint", zap.String("serciveURL", serviceURL)) return handler.NewGrpcErrorf(codes.Internal, "Unable to publish status error") } return nil diff --git a/escrow/prepaid_handler.go b/escrow/prepaid_handler.go index 96f52329..40df2439 100644 --- a/escrow/prepaid_handler.go +++ b/escrow/prepaid_handler.go @@ -6,7 +6,7 @@ import ( "github.com/singnet/snet-daemon/handler" "github.com/singnet/snet-daemon/pricing" "github.com/singnet/snet-daemon/token" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" ) const ( @@ -68,7 +68,7 @@ func (h *PrePaidPaymentHandler) Payment(context *handler.GrpcStreamContext) (tra if validateErr != nil { return nil, paymentErrorToGrpcError(validateErr) } - //Increment the used amount + // Increment the used amount if err := h.service.UpdateUsage(prePaidPayment.ChannelID, price, USED_AMOUNT); err != nil { return nil, paymentErrorToGrpcError(err) } @@ -98,13 +98,13 @@ func (h *PrePaidPaymentHandler) getPaymentFromContext(context *handler.GrpcStrea }, nil } -//Just logging , as we increase the usage before calling the service -//assuming the service call will be successful +// Just logging , as we increase the usage before calling the service +// assuming the service call will be successful func (h *PrePaidPaymentHandler) Complete(payment handler.Payment) (err *handler.GrpcError) { prePaidTransaction := payment.(PrePaidTransaction) - log.Debugf("usage %v successfully updated and channel id: %v state is consistent", - prePaidTransaction.Price(), - prePaidTransaction.ChannelId()) + zap.L().Debug("usage successfully updated and state of channel is consistent", + zap.Any("price", prePaidTransaction.Price()), + zap.Any("channelID", prePaidTransaction.ChannelId())) return nil } @@ -114,11 +114,12 @@ func (h *PrePaidPaymentHandler) CompleteAfterError(payment handler.Payment, resu prePaidTransaction := payment.(PrePaidTransaction) if err = paymentErrorToGrpcError(h.service.UpdateUsage(prePaidTransaction.ChannelId(), prePaidTransaction.Price(), REFUND_AMOUNT)); err != nil { - log.Error(err) - log.Errorf("usage INCONSISTENT state on Channel id:%v , usage wrongly increased by %v", - prePaidTransaction.ChannelId(), prePaidTransaction.Price()) + zap.L().Error(err.Err().Error()) + zap.L().Error("usage INCONSISTENT state on Channel, usage wrongly increased", zap.Any("usage", prePaidTransaction.Price()), + zap.Any("ChannelID", prePaidTransaction.ChannelId())) } - log.Debugf("usage:%v on channel id:%v was updated already, however the refund state has been"+ - "adjusted accordingly", prePaidTransaction.Price(), prePaidTransaction.ChannelId()) + + zap.L().Debug("usage on channel id was updated already, however the refund state has been adjusted accordingly", + zap.Any("usage", prePaidTransaction.Price()), zap.Any("channelID", prePaidTransaction.ChannelId())) return err } diff --git a/escrow/prepaid_service.go b/escrow/prepaid_service.go index 67c745fa..45722e3e 100644 --- a/escrow/prepaid_service.go +++ b/escrow/prepaid_service.go @@ -33,9 +33,9 @@ func (h *lockingPrepaidService) GetUsage(key PrePaidDataKey) (data *PrePaidData, } -//Defines the condition that needs to be met, it generates the respective typed Data when -//conditions are satisfied, you define your own validations in here -//It takes in the latest typed values read. +// Defines the condition that needs to be met, it generates the respective typed Data when +// conditions are satisfied, you define your own validations in here +// It takes in the latest typed values read. type ConditionFunc func(conditionValues []storage.TypedKeyValueData, revisedAmount *big.Int, channelId *big.Int) ([]storage.TypedKeyValueData, error) func (h *lockingPrepaidService) UpdateUsage(channelId *big.Int, revisedAmount *big.Int, updateUsageType string) (err error) { @@ -78,16 +78,16 @@ func (h *lockingPrepaidService) UpdateUsage(channelId *big.Int, revisedAmount *b } return nil } -func getAllKeys(channelId *big.Int) []interface{} { - keys := make([]interface{}, 3) +func getAllKeys(channelId *big.Int) []any { + keys := make([]any, 3) for i, usageType := range []string{REFUND_AMOUNT, PLANNED_AMOUNT, USED_AMOUNT} { keys[i] = PrePaidDataKey{ChannelID: channelId, UsageType: usageType} } return keys } -//this function will be used to read typed data ,convert it in to a business structure -//on which validations can be easily performed and return back the business structure. +// this function will be used to read typed data ,convert it in to a business structure +// on which validations can be easily performed and return back the business structure. func convertTypedDataToPrePaidUsage(data []storage.TypedKeyValueData) (new *PrePaidUsageData, err error) { usageData := &PrePaidUsageData{PlannedAmount: big.NewInt(0), UsedAmount: big.NewInt(0), RefundAmount: big.NewInt(0)} diff --git a/escrow/prepaid_storage.go b/escrow/prepaid_storage.go index f6a8609b..1fa530ba 100644 --- a/escrow/prepaid_storage.go +++ b/escrow/prepaid_storage.go @@ -15,13 +15,13 @@ type PrePaidPayment struct { AuthToken string } -//Used when the Request comes in +// Used when the Request comes in func (payment *PrePaidPayment) String() string { return fmt.Sprintf("{ID:%v/%v/%v}", payment.ChannelID, payment.OrganizationId, payment.GroupId) } -//Kept the bare minimum here , other details like group and sender address of this channel can -//always be retrieved from BlockChain +// Kept the bare minimum here , other details like group and sender address of this channel can +// always be retrieved from BlockChain type PrePaidData struct { Amount *big.Int } @@ -44,7 +44,7 @@ const ( REFUND_AMOUNT string = "R" ) -//This will ony be used for doing any business checks +// This will ony be used for doing any business checks type PrePaidUsageData struct { ChannelID *big.Int PlannedAmount *big.Int @@ -80,7 +80,7 @@ func (data PrePaidUsageData) Clone() *PrePaidUsageData { } } -func serializePrePaidKey(key interface{}) (serialized string, err error) { +func serializePrePaidKey(key any) (serialized string, err error) { myKey := key.(PrePaidDataKey) return myKey.String(), nil } diff --git a/escrow/state_service.go b/escrow/state_service.go index 80c87c64..0170da2c 100644 --- a/escrow/state_service.go +++ b/escrow/state_service.go @@ -6,13 +6,15 @@ import ( "bytes" "errors" "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" + "math/big" + "github.com/singnet/snet-daemon/authutils" "github.com/singnet/snet-daemon/blockchain" - log "github.com/sirupsen/logrus" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "go.uber.org/zap" "golang.org/x/net/context" - "math/big" ) // PaymentChannelStateService is an implementation of PaymentChannelStateServiceServer gRPC interface @@ -79,10 +81,9 @@ In this case, the server can only make us believe that we have more money in the That means that one possible attack via unspent_amount is to make us believe that we have less tokens than we truly have, and therefore reject future calls (or force us to call channelAddFunds).*/ func (service *PaymentChannelStateService) GetChannelState(context context.Context, request *ChannelStateRequest) (reply *ChannelStateReply, err error) { - log.WithFields(log.Fields{ - "context": context, - "request": request, - }).Debug("GetChannelState called") + zap.L().Debug("GetChannelState called", + zap.Any("context", context), + zap.Any("request", request)) channelID := bytesToBigInt(request.GetChannelId()) // signature verification @@ -117,7 +118,7 @@ func (service *PaymentChannelStateService) GetChannelState(context context.Conte // check if nonce matches with blockchain or not nonceEqual, err := service.StorageNonceMatchesWithBlockchainNonce(channel) if err != nil { - log.WithError(err).Infof("payment data not available in payment storage.") + zap.L().Info("payment data not available in payment storage.", zap.Error(err)) return nil, err } else if !nonceEqual { @@ -126,12 +127,12 @@ func (service *PaymentChannelStateService) GetChannelState(context context.Conte paymentID := PaymentID(channel.ChannelID, (&big.Int{}).Sub(channel.Nonce, big.NewInt(1))) payment, ok, err := service.paymentStorage.Get(paymentID) if err != nil { - log.WithError(err).Errorf("Error trying unable to extract old payment from storage") + zap.L().Error("Error trying unable to extract old payment from storage", zap.Error(err)) return nil, err } if !ok { - log.Errorf("old payment is not found in storage, nevertheless local channel nonce is not equal to the blockchain one, channel: %v", channelID) + zap.L().Error("old payment is not found in storage, nevertheless local channel nonce is not equal to the blockchain one", zap.Any("ChannelID", channelID)) return nil, errors.New("channel has different nonce in local storage and blockchain and old payment is not found in storage") } return &ChannelStateReply{ diff --git a/escrow/state_service_test.go b/escrow/state_service_test.go index 98a4563d..648dee57 100644 --- a/escrow/state_service_test.go +++ b/escrow/state_service_test.go @@ -5,14 +5,15 @@ import ( "crypto/ecdsa" "encoding/hex" "errors" + "math/big" + "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/storage" "github.com/stretchr/testify/assert" - "math/big" - "testing" ) type stateServiceTestType struct { diff --git a/escrow/validation.go b/escrow/validation.go index 748327bd..827f4ef6 100644 --- a/escrow/validation.go +++ b/escrow/validation.go @@ -3,13 +3,15 @@ package escrow import ( "bytes" "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/singnet/snet-daemon/authutils" "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + "github.com/spf13/viper" - "math/big" + "go.uber.org/zap" ) const ( @@ -44,7 +46,7 @@ func (validator *FreeCallPaymentValidator) Validate(payment *FreeCallPayment) (e newSignature := true //this will be removed once dapp makes the changes to move to new Signature signerAddress, err := validator.getSignerOfAuthTokenForFreeCall(payment) if err != nil || *signerAddress != validator.freeCallSigner { - //Make sure the current Dapp is backward compatible , this will be removed once Dapp + //Make sure the current Dapp is backward compatible, this will be removed once Dapp //Makes the latest signature change with Token for Free calls if signerAddress, err = validator.getSignerAddressForFreeCall(payment); err != nil { return NewPaymentError(Unauthenticated, "payment signature is not valid") @@ -87,10 +89,11 @@ func NewChannelPaymentValidator(processor *blockchain.Processor, cfg *viper.Vipe // Validate returns instance of PaymentError as error if validation fails, nil // otherwise. func (validator *ChannelPaymentValidator) Validate(payment *Payment, channel *PaymentChannelData) (err error) { - var log = log.WithField("payment", payment).WithField("channel", channel) + paymentFieldLog := zap.Any("payment", payment) + channelFieldLog := zap.Any("channel", channel) if payment.ChannelNonce.Cmp(channel.Nonce) != 0 { - log.Warn("Incorrect nonce is sent by client") + zap.L().Warn("Incorrect nonce is sent by client", paymentFieldLog, channelFieldLog) return NewPaymentError(IncorrectNonce, "incorrect payment channel nonce, latest: %v, sent: %v", channel.Nonce, payment.ChannelNonce) } @@ -99,9 +102,9 @@ func (validator *ChannelPaymentValidator) Validate(payment *Payment, channel *Pa return NewPaymentError(Unauthenticated, "payment signature is not valid") } - log = log.WithField("signerAddress", blockchain.AddressToHex(signerAddress)) + signerAddressFieldLog := zap.String("signerAddress", blockchain.AddressToHex(signerAddress)) if *signerAddress != channel.Signer && *signerAddress != channel.Sender { - log.WithField("signerAddress", blockchain.AddressToHex(signerAddress)).Warn("Channel signer is not equal to payment signer/sender") + zap.L().Warn("Channel signer is not equal to payment signer/sender", signerAddressFieldLog) return NewPaymentError(Unauthenticated, "payment is not signed by channel signer/sender") } currentBlock, e := validator.currentBlock() @@ -111,12 +114,12 @@ func (validator *ChannelPaymentValidator) Validate(payment *Payment, channel *Pa expirationThreshold := validator.paymentExpirationThreshold() currentBlockWithThreshold := new(big.Int).Add(currentBlock, expirationThreshold) if currentBlockWithThreshold.Cmp(channel.Expiration) >= 0 { - log.WithField("currentBlock", currentBlock).WithField("expirationThreshold", expirationThreshold).Warn("Channel expiration time is after expiration threshold") + zap.L().Warn("Channel expiration time is after expiration threshold", zap.Any("currentBlock", currentBlock), zap.Any("expirationThreshold", expirationThreshold)) return NewPaymentError(Unauthenticated, "payment channel is near to be expired, expiration time: %v, current block: %v, expiration threshold: %v", channel.Expiration, currentBlock, expirationThreshold) } if channel.FullAmount.Cmp(payment.Amount) < 0 { - log.Warn("Not enough tokens on payment channel") + zap.L().Warn("Not enough tokens on payment channel") return NewPaymentError(Unauthenticated, "not enough tokens on payment channel, channel amount: %v, payment amount: %v", channel.FullAmount, payment.Amount) } @@ -136,6 +139,7 @@ func (validator *FreeCallPaymentValidator) compareWithLatestBlockNumber(blockNum return nil } +// deprecated func (validator *FreeCallPaymentValidator) getSignerAddressForFreeCall(payment *FreeCallPayment) (signer *common.Address, err error) { message := bytes.Join([][]byte{ @@ -148,7 +152,7 @@ func (validator *FreeCallPaymentValidator) getSignerAddressForFreeCall(payment * signer, err = authutils.GetSignerAddressFromMessage(message, payment.Signature) if err != nil { - log.WithField("payment", payment).WithError(err).Error("Cannot get signer from payment") + zap.L().Error("Cannot get signer from payment", zap.Any("payment", payment), zap.Error(err)) return nil, err } return signer, err @@ -165,11 +169,11 @@ func getSignerAddressFromPayment(payment *Payment) (signer *common.Address, err signer, err = authutils.GetSignerAddressFromMessage(message, payment.Signature) if err != nil { - log.WithField("payment", payment).WithError(err).Error("Cannot get signer from payment") + zap.L().Error("Cannot get signer from payment", zap.Error(err), zap.Any("payment", payment)) return nil, err } if err = checkCurationValidations(signer); err != nil { - log.Error(err) + zap.L().Error(err.Error()) return nil, err } @@ -177,21 +181,23 @@ func getSignerAddressFromPayment(payment *Payment) (signer *common.Address, err } func (validator *FreeCallPaymentValidator) getSignerOfAuthTokenForFreeCall(payment *FreeCallPayment) (signer *common.Address, err error) { - //signer-token = (user@mail, user-public-key, token_issue_date), this is generated by Market place Dapp + //signer-token = (user@mail, user-public-key, token_issue_date), this is generated by Marketplace Dapp signer, err = getUserAddressFromSignatureOfFreeCalls(payment) if err != nil { return nil, err } + fmt.Println("signer of req - will be passed to token: ", signer.Hex()) + fmt.Println("AuthTokenExpiryBlockNumber: ", payment.AuthTokenExpiryBlockNumber.Int64()) message := bytes.Join([][]byte{ []byte(payment.UserId), - signer.Bytes(), + signer.Bytes(), // user address bigIntToBytes(payment.AuthTokenExpiryBlockNumber), }, nil) return authutils.GetSignerAddressFromMessage(message, payment.AuthToken) } -// user signs using his private key , the public adress of this user should be in the token issued by Dapp +// user signs using his private key, the public address of this user should be in the token issued by Dapp func getUserAddressFromSignatureOfFreeCalls(payment *FreeCallPayment) (signer *common.Address, err error) { message := bytes.Join([][]byte{ []byte(FreeCallPrefixSignature), @@ -205,11 +211,11 @@ func getUserAddressFromSignatureOfFreeCalls(payment *FreeCallPayment) (signer *c signer, err = authutils.GetSignerAddressFromMessage(message, payment.Signature) if err != nil { - log.WithField("payment", payment).WithError(err).Error("Cannot get signer from payment") + zap.L().Error("Cannot get signer from payment", zap.Error(err), zap.Any("payment", payment)) return nil, err } if err = checkCurationValidations(signer); err != nil { - log.Error(err) + zap.L().Error(err.Error()) return nil, err } return signer, err diff --git a/etcddb/README.md b/etcddb/README.md index 90e892ba..359ed22c 100644 --- a/etcddb/README.md +++ b/etcddb/README.md @@ -14,7 +14,7 @@ There are two payment channel storage types which are currently supported by sne *memory* storage type is used in configuration where only one service replica is used by snet-daemon or for testing purposes. -To run snet-daemon with several replicas set the payment_channel_storage_type is now initialized from Organizatio metadata: +To run snet-daemon with several replicas set the payment_channel_storage_type is now initialized from Organization metadata: ```json { "payment_channel_storage_type": "etcd" @@ -25,13 +25,15 @@ To run snet-daemon with several replicas set the payment_channel_storage_type is *payment_channel_storage_client* JSON map can be used to configure payment channel storage etcd client. -| Field name | Description |Default Value | -|--------------------|-----------------------------------------------|-------------------------| -| connection_timeout | timeout for failing to establish a connection |5 seconds | -| request_timeout | per request timeout |3 seconds | -| endpoints | list of etcd cluster endpoints (host:port) |["http://127.0.0.1:2379"]| +| Field name | Description | Default Value | +|--------------------|-----------------------------------------------|-----------------------------| +| connection_timeout | timeout for failing to establish a connection | from org metadata | +| request_timeout | per request timeout | from org metadata | +| endpoints | list of etcd cluster endpoints (host:port) | from org metadata | +**endpoints from the config are ignored and taken only from ipfs metadata** + Endpoints consist of a list of URLs which points to etcd cluster servers. @@ -61,20 +63,22 @@ cluster , please go over the documentation below To use embedded etcd server in snet-daemon the configuration file needs to contain the *payment_channel_storage_server* JSON map with fields: -| Field name | Description |Default Value | -|----------------|--------------------------------------------------------|-------------------------------| -| id | unique name of the etcd server node |storage-1 | -| schema | URL schema used to create client and peer and urls |http | -| host | host where the etcd server is executed |127.0.0.1 | -| client_port | port to listen clients requests |2379 | -| peer_port | port to listen etcd peers |2380 | -| token | unique initial cluster token |unique-token | -| cluster | initial cluster configuration for bootstrapping |storage-1=http://127.0.0.1:2380| -| startup_timeout| time to wait that etcd server is successfully started |1 minute | -| data_dir | directory where etcd server stores its data |storage-data-dir-1.etcd | -| log_level | etcd server logging level (error, warning, info, debug)|info | -| enabled | enable running embedded etcd server |true | - +| Field name | Description | Default Value | +|-----------------|---------------------------------------------------------|--------------------------------| +| id | unique name of the etcd server node | storage-1 | +| schema | URL schema used to create client and peer and urls | http | +| host | host where the etcd server is executed | 127.0.0.1 | +| client_port | port to listen clients requests | 2379 | +| peer_port | port to listen etcd peers | 2380 | +| token | unique initial cluster token | unique-token | +| cluster | initial cluster configuration for bootstrapping | storage-1=http://127.0.0.1:2380| +| startup_timeout | time to wait that etcd server is successfully started | 1 minute | +| data_dir | directory where etcd server stores its data | storage-data-dir-1.etcd | +| log_level | etcd server logging level (error, warning, info, debug) | info | +| log_outputs | file path to append server logs to or stderr/stdout | stderr | +| enabled | enable running embedded etcd server | true | + +**log_outputs can accept array** The cluster field is a comma-separated list of one or more etcd peer URLs in form of *id=host:peer_port*. @@ -102,6 +106,10 @@ want to set up a local cluster , then payment_channel_storage_server.enabled con "id": "storage-1", "host" : "127.0.0.1", "client_port": 2379, + "log_level": "info", + "log_outputs": [ + "./etcd-server.log" + ], "peer_port": 2380, "token": "unique-token", "cluster": "storage-1=http://127.0.0.1:2380", @@ -115,14 +123,18 @@ Config for snet-daemon that does not run embedded etcd node: * *enabled* field is set to _false_ ```json { - "payment_channel_storage_server": { - "id": "storage-2", - "host" : "127.0.0.2", - "client_port": 2379, - "peer_port": 2380, - "token": "unique-token", - "cluster": "storage-1=http://127.0.0.1:2380,storage-2=http://127.0.0.2:2380,storage-3=http://127.0.0.3:2380", - "enabled": false - } + "payment_channel_storage_server": { + "id": "storage-2", + "host": "127.0.0.2", + "client_port": 2379, + "peer_port": 2380, + "log_level": "info", + "log_outputs": [ + "./etcd-server.log" + ], + "token": "unique-token", + "cluster": "storage-1=http://127.0.0.1:2380,storage-2=http://127.0.0.2:2380,storage-3=http://127.0.0.3:2380", + "enabled": false + } } ``` diff --git a/etcddb/etcddb_client.go b/etcddb/etcddb_client.go index 43c3654f..529f9ea4 100644 --- a/etcddb/etcddb_client.go +++ b/etcddb/etcddb_client.go @@ -5,20 +5,19 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "github.com/golang-collections/collections/set" - "github.com/singnet/snet-daemon/blockchain" - "github.com/singnet/snet-daemon/storage" - "github.com/singnet/snet-daemon/utils" "os" "strings" "time" + "github.com/golang-collections/collections/set" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + "github.com/singnet/snet-daemon/storage" + "github.com/singnet/snet-daemon/utils" "github.com/spf13/viper" - - "go.etcd.io/etcd/client/v3" + clientv3 "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/client/v3/concurrency" + "go.uber.org/zap" ) // EtcdClientMutex mutex struct for etcd client @@ -57,7 +56,10 @@ func NewEtcdClientFromVip(vip *viper.Viper, metaData *blockchain.OrganizationMet return nil, err } - log.WithField("PaymentChannelStorageClient", fmt.Sprintf("%+v", conf)).Info() + zap.L().Info("Creating new payment storage client (etcdv3)", + zap.String("ConnectionTimeout", conf.ConnectionTimeout.String()), + zap.String("RequestTimeout", conf.RequestTimeout.String()), + zap.Strings("Endpoints", conf.Endpoints)) var etcdv3 *clientv3.Client @@ -83,9 +85,11 @@ func NewEtcdClientFromVip(vip *viper.Viper, metaData *blockchain.OrganizationMet } } - session, err := concurrency.NewSession(etcdv3) + ctx, cancel := context.WithTimeout(context.Background(), conf.RequestTimeout) + defer cancel() + session, err := concurrency.NewSession(etcdv3, concurrency.WithContext(ctx)) if err != nil { - return + return nil, fmt.Errorf("can't connect to etcddb: %v", err) } client = &EtcdClient{ @@ -95,9 +99,10 @@ func NewEtcdClientFromVip(vip *viper.Viper, metaData *blockchain.OrganizationMet } return } + func getTlsConfig() (*tls.Config, error) { - log.Debug("enabling SSL support via X509 keypair") + zap.L().Debug("enabling SSL support via X509 keypair") cert, err := tls.LoadX509KeyPair(config.GetString(config.PaymentChannelCertPath), config.GetString(config.PaymentChannelKeyPath)) if err != nil { @@ -120,15 +125,17 @@ func getTlsConfig() (*tls.Config, error) { // Get gets value from etcd by key func (client *EtcdClient) Get(key string) (value string, ok bool, err error) { - log := log.WithField("func", "Get").WithField("key", key).WithField("client", client) - ctx, cancel := context.WithTimeout(context.Background(), client.timeout) defer cancel() response, err := client.etcdv3.Get(ctx, key) if err != nil { - log.WithError(err).Error("Unable to get value by key") + zap.L().Error("Unable to get value by key", + zap.Error(err), + zap.String("func", "Get"), + zap.String("key", key), + zap.Any("client", client)) return } @@ -144,8 +151,6 @@ func (client *EtcdClient) Get(key string) (value string, ok bool, err error) { // GetByKeyPrefix gets all values which have the same key prefix func (client *EtcdClient) GetByKeyPrefix(key string) (values []string, err error) { - log := log.WithField("func", "GetByKeyPrefix").WithField("key", key).WithField("client", client) - ctx, cancel := context.WithTimeout(context.Background(), client.timeout) defer cancel() @@ -153,7 +158,11 @@ func (client *EtcdClient) GetByKeyPrefix(key string) (values []string, err error response, err := client.etcdv3.Get(ctx, key, clientv3.WithRange(keyEnd)) if err != nil { - log.WithError(err).Error("Unable to get value by key prefix") + zap.L().Error("Unable to get value by key prefix", + zap.Error(err), + zap.String("func", "Get"), + zap.String("key", key), + zap.Any("client", client)) return } @@ -167,7 +176,6 @@ func (client *EtcdClient) GetByKeyPrefix(key string) (values []string, err error // Put puts key and value to etcd func (client *EtcdClient) Put(key string, value string) (err error) { - log := log.WithField("func", "Put").WithField("key", key).WithField("client", client) etcdv3 := client.etcdv3 ctx, cancel := context.WithTimeout(context.Background(), client.timeout) @@ -175,7 +183,11 @@ func (client *EtcdClient) Put(key string, value string) (err error) { _, err = etcdv3.Put(ctx, key, value) if err != nil { - log.WithError(err).Error("Unable to put value by key") + zap.L().Error("Unable to put value by key", + zap.Error(err), + zap.String("func", "Put"), + zap.String("key", key), + zap.Any("client", client)) } return err @@ -183,7 +195,6 @@ func (client *EtcdClient) Put(key string, value string) (err error) { // Delete deletes the existing key and value from etcd func (client *EtcdClient) Delete(key string) error { - log := log.WithField("func", "Delete").WithField("key", key).WithField("client", client) etcdv3 := client.etcdv3 ctx, cancel := context.WithTimeout(context.Background(), client.timeout) @@ -191,7 +202,11 @@ func (client *EtcdClient) Delete(key string) error { _, err := etcdv3.Delete(ctx, key) if err != nil { - log.WithError(err).Error("Unable to delete value by key") + zap.L().Error("Unable to delete value by key", + zap.Error(err), + zap.String("func", "Delete"), + zap.String("key", key), + zap.Any("client", client)) } return err @@ -214,7 +229,7 @@ func (client *EtcdClient) CompareAndSwap(key string, prevValue string, newValue ConditionKeys: []string{key}, Update: func(oldValues []storage.KeyValueData) (update []storage.KeyValueData, ok bool, err error) { if oldValues[0].Present && strings.Compare(oldValues[0].Value, prevValue) == 0 { - return []storage.KeyValueData{storage.KeyValueData{ + return []storage.KeyValueData{{ Key: key, Value: newValue, }}, true, nil @@ -228,8 +243,6 @@ func (client *EtcdClient) CompareAndSwap(key string, prevValue string, newValue // Transaction uses CAS operation to compare and set multiple key values func (client *EtcdClient) Transaction(compare []EtcdKeyValue, swap []EtcdKeyValue) (ok bool, err error) { - log := log.WithField("func", "CompareAndSwap").WithField("client", client) - etcdv3 := client.etcdv3 ctx, cancel := context.WithTimeout(context.Background(), client.timeout) defer cancel() @@ -252,8 +265,11 @@ func (client *EtcdClient) Transaction(compare []EtcdKeyValue, swap []EtcdKeyValu for _, keyValue := range compare { keys = append(keys, keyValue.key) } - log = log.WithField("keys", strings.Join(keys, ", ")) - log.WithError(err).Error("Unable to compare and swap value by keys") + zap.L().Error("Unable to compare and swap value by keys", + zap.Error(err), + zap.String("keys", strings.Join(keys, ", ")), + zap.String("func", "CompareAndSwap"), + zap.Any("client", client)) return false, err } @@ -269,7 +285,7 @@ func (client *EtcdClient) PutIfAbsent(key string, value string) (ok bool, err er if oldValues[0].Present { return nil, false, nil } - return []storage.KeyValueData{storage.KeyValueData{ + return []storage.KeyValueData{{ Key: key, Value: value, }}, true, nil @@ -354,7 +370,7 @@ func (client *EtcdClient) CompleteTransaction(_transaction storage.Transaction, endtime := time.Now() - log.Debugf("etcd Transaction took %v", endtime.Sub(startime)) + zap.L().Debug("etcd transaction time", zap.Any("time", endtime.Sub(startime))) if err != nil { return false, err } @@ -391,7 +407,7 @@ func (client *EtcdClient) checkTxnResponse(keys []string, txnResp *clientv3.TxnR } latestStateArray = append(latestStateArray, latestValues...) } - keySet.Do(func(elem interface{}) { + keySet.Do(func(elem any) { latestStateArray = append(latestStateArray, keyValueVersion{ Key: elem.(string), Present: false, @@ -439,7 +455,7 @@ func (client *EtcdClient) StartTransaction(keys []string) (_transaction storage. txnResp, err := txn.Commit() if err != nil { - log.WithError(err).Error("error in getting values") + zap.L().Error("error in getting values", zap.Error(err)) return nil, err } if txnResp != nil { diff --git a/etcddb/etcddb_client_test.go b/etcddb/etcddb_client_test.go index d2929415..f84db835 100644 --- a/etcddb/etcddb_client_test.go +++ b/etcddb/etcddb_client_test.go @@ -1,9 +1,11 @@ package etcddb import ( + "testing" + "github.com/magiconair/properties/assert" + _ "github.com/singnet/snet-daemon/fix-proto" "github.com/singnet/snet-daemon/utils" - "testing" ) func Test_checkIfHttps(t *testing.T) { @@ -11,5 +13,4 @@ func Test_checkIfHttps(t *testing.T) { assert.Equal(t, utils.CheckIfHttps(endpoint), true) endpoint = []string{"http://snet-etcd.singularitynet.io:2379"} assert.Equal(t, utils.CheckIfHttps(endpoint), false) - } diff --git a/etcddb/etcddb_conf.go b/etcddb/etcddb_conf.go index 76c6100f..1414385a 100644 --- a/etcddb/etcddb_conf.go +++ b/etcddb/etcddb_conf.go @@ -1,13 +1,11 @@ package etcddb import ( - "github.com/singnet/snet-daemon/blockchain" "strings" "time" - "github.com/coreos/pkg/capnslog" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) @@ -33,6 +31,22 @@ func GetEtcdClientConf(vip *viper.Viper, metaData *blockchain.OrganizationMetaDa Endpoints: metaData.GetPaymentStorageEndPoints(), } + if vip == nil { + return + } + + confFromVip := &EtcdClientConf{} + subVip := config.SubWithDefault(vip, config.PaymentChannelStorageClientKey) + err = subVip.Unmarshal(confFromVip) + + if confFromVip.RequestTimeout != 0 { + conf.RequestTimeout = confFromVip.RequestTimeout + } + + if confFromVip.ConnectionTimeout != 0 { + conf.ConnectionTimeout = confFromVip.ConnectionTimeout + } + return } @@ -72,8 +86,9 @@ type EtcdServerConf struct { Cluster string StartupTimeout time.Duration `json:"startup_timeout" mapstructure:"startup_timeout"` Enabled bool - DataDir string `json:"data_dir" mapstructure:"DATA_DIR"` - LogLevel string `json:"log_level" mapstructure:"LOG_LEVEL"` + DataDir string `json:"data_dir" mapstructure:"DATA_DIR"` + LogLevel string `json:"log_level" mapstructure:"LOG_LEVEL"` + LogOutputs []string `json:"log_outputs" mapstructure:"LOG_OUTPUTS"` } // GetEtcdServerConf gets EtcdServerConf from viper @@ -102,54 +117,5 @@ func GetEtcdServerConf(vip *viper.Viper) (conf *EtcdServerConf, err error) { return } - err = initEtcdLogger(conf) - - return -} - -// capnslog to logrus formatter implementation -// with methods Format and Flush -type capnslogToLogrusLogFormatter struct { -} - -func (formatter *capnslogToLogrusLogFormatter) Format(pkg string, level capnslog.LogLevel, - depth int, entries ...interface{}) { - - l := log.WithField("pkg", pkg) - - switch level { - case capnslog.CRITICAL, capnslog.ERROR: - l.Error(entries...) - case capnslog.WARNING, capnslog.NOTICE: - l.Warning(entries...) - case capnslog.INFO: - l.Info(entries...) - case capnslog.DEBUG: - fallthrough - case capnslog.TRACE: - l.Debug(entries...) - default: - l.Warning("Unknown log level", level) - } -} - -func (formatter *capnslogToLogrusLogFormatter) Flush() { -} - -func initEtcdLogger(conf *EtcdServerConf) (err error) { - - //etcdLogger, err := capnslog.GetRepoLogger("github.com/coreos/etcd") - //if err != nil { - // return - //} - - //logLevel, err := capnslog.ParseLevel(strings.ToUpper(conf.LogLevel)) - //if err != nil { - // return - //} - - //etcdLogger.SetRepoLogLevel(logLevel) - capnslog.SetFormatter(&capnslogToLogrusLogFormatter{}) - return } diff --git a/etcddb/etcddb_conf_test.go b/etcddb/etcddb_conf_test.go index 30263d8f..e3868101 100644 --- a/etcddb/etcddb_conf_test.go +++ b/etcddb/etcddb_conf_test.go @@ -1,12 +1,13 @@ package etcddb import ( - "github.com/singnet/snet-daemon/blockchain" "os" "testing" "time" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" + "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) @@ -37,6 +38,7 @@ func TestCustomEtcdClientConf(t *testing.T) { assert.Equal(t, 5*time.Second, conf.RequestTimeout) assert.Equal(t, []string{"http://127.0.0.1:2479"}, conf.Endpoints) } + func TestCustomEtcdClientConfWithDefault(t *testing.T) { var testJsonOrgGroupData = "{ \"org_name\": \"organization_name\", \"org_id\": \"org_id1\", \"groups\": [ { \"group_name\": \"default_group2\", \"group_id\": \"99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=\", \"payment\": { \"payment_address\": \"0x671276c61943A35D5F230d076bDFd91B0c47bF09\", \"payment_expiration_threshold\": 40320, \"payment_channel_storage_type\": \"etcd\", \"payment_channel_storage_client\": { \"connection_timeout\": \"15s\", \"endpoints\": [ \"http://127.0.0.1:2479\" ] } } }, { \"group_name\": \"default_group\", \"group_id\": \"99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=\", \"payment\": { \"payment_address\": \"0x671276c61943A35D5F230d076bDFd91B0c47bF09\", \"payment_expiration_threshold\": 40320, \"payment_channel_storage_type\": \"etcd\", \"payment_channel_storage_client\": { \"connection_timeout\": \"5s\", \"request_timeout\": \"3s\" } } } ] }" metadata, err := blockchain.InitOrganizationMetaDataFromJson(testJsonOrgGroupData) @@ -72,6 +74,7 @@ func TestDefaultEtcdServerConf(t *testing.T) { assert.Equal(t, time.Minute, conf.StartupTimeout) assert.Equal(t, "storage-data-dir-1.etcd", conf.DataDir) assert.Equal(t, "info", conf.LogLevel) + assert.Equal(t, []string{"./etcd-server.log"}, conf.LogOutputs) assert.Equal(t, false, conf.Enabled) server, err := GetEtcdServer() @@ -113,7 +116,8 @@ func TestEnabledEtcdServerConf(t *testing.T) { "cluster": "storage-1=http://127.0.0.1:2380", "startup_timeout": "15s", "data_dir": "custom-storage-data-dir-1.etcd", - "log_level": "warning", + "log_level": "warn", + "log_outputs": ["stderr"], "enabled": true } }` @@ -137,7 +141,8 @@ func TestEnabledEtcdServerConf(t *testing.T) { assert.Equal(t, "unique-token", conf.Token) assert.Equal(t, 15*time.Second, conf.StartupTimeout) assert.Equal(t, "custom-storage-data-dir-1.etcd", conf.DataDir) - assert.Equal(t, "warning", conf.LogLevel) + assert.Equal(t, "warn", conf.LogLevel) + assert.Equal(t, []string{"stderr"}, conf.LogOutputs) assert.Equal(t, true, conf.Enabled) server, err := GetEtcdServerFromVip(vip) @@ -146,24 +151,21 @@ func TestEnabledEtcdServerConf(t *testing.T) { err = server.Start() assert.Nil(t, err) - defer server.Close() defer removeWorkDir(t, conf.DataDir) + defer server.Close() } func readConfig(t *testing.T, configJSON string) (vip *viper.Viper) { vip = viper.New() config.SetDefaultFromConfig(vip, config.Vip()) - err := config.ReadConfigFromJsonString(vip, configJSON) assert.Nil(t, err) return } func removeWorkDir(t *testing.T, workDir string) { - dir, err := os.Getwd() assert.Nil(t, err) - err = os.RemoveAll(dir + "/" + workDir) assert.Nil(t, err) } diff --git a/etcddb/etcddb_server.go b/etcddb/etcddb_server.go index f3b0f63c..3ceabe22 100644 --- a/etcddb/etcddb_server.go +++ b/etcddb/etcddb_server.go @@ -3,16 +3,15 @@ package etcddb import ( "errors" "fmt" - "net/url" - "time" - "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" "go.etcd.io/etcd/server/v3/embed" + "go.uber.org/zap" + "net/url" + "time" ) -// EtcdServer struct has some useful methods to wolrk with etcd server +// EtcdServer struct has some useful methods to work with etcd server type EtcdServer struct { conf *EtcdServerConf etcd *embed.Etcd @@ -52,7 +51,7 @@ func GetEtcdServerFromVip(vip *viper.Viper) (server *EtcdServer, err error) { conf, err := GetEtcdServerConf(vip) - log.WithField("PaymentChannelStorageServer", fmt.Sprintf("%+v", conf)).Info() + zap.L().Info("Getting payment channel storage sever", zap.Any("conf", conf)) if err != nil || conf == nil || !conf.Enabled { return @@ -113,9 +112,9 @@ func getEtcdConf(conf *EtcdServerConf) *embed.Config { Host: fmt.Sprintf("%s:%d", conf.Host, conf.PeerPort), } - log.WithField("PaymentChannelStorageServer", fmt.Sprintf("%+v", conf)).Info() - log.WithField("ClientURL", clientURL).Info() - log.WithField("PeerURL", peerURL).Info() + zap.L().Info("Getting etcd config", zap.Any("PaymentChannelStorageServer", fmt.Sprintf("%+v", conf)), + zap.Any("ClientURL", clientURL), + zap.Any("PeerURL", clientURL)) etcdConf := embed.NewConfig() etcdConf.Name = conf.ID @@ -142,5 +141,11 @@ func getEtcdConf(conf *EtcdServerConf) *embed.Config { // --initial-cluster-state etcdConf.ClusterState = embed.ClusterStateFlagNew + // --log-level + etcdConf.LogLevel = conf.LogLevel + + // --log-outputs + etcdConf.LogOutputs = conf.LogOutputs + return etcdConf } diff --git a/etcddb/etcddb_test.go b/etcddb/etcddb_test.go index 47df0f51..e6344616 100644 --- a/etcddb/etcddb_test.go +++ b/etcddb/etcddb_test.go @@ -3,13 +3,14 @@ package etcddb import ( "context" "fmt" - "github.com/singnet/snet-daemon/blockchain" - "github.com/singnet/snet-daemon/storage" "strconv" "sync" "testing" "time" + "github.com/singnet/snet-daemon/blockchain" + "github.com/singnet/snet-daemon/storage" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -305,7 +306,7 @@ func (suite *EtcdTestSuite) TestPutIfAbsentTransactionFailsAfterConcurrentPut() // then ok, err = client.CompleteTransaction(transaction, []storage.KeyValueData{ - storage.KeyValueData{ + { Key: key, Value: "transaction-value", Present: true, diff --git a/go.mod b/go.mod index 338c3cd9..ba1bfa1a 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,9 @@ go 1.22 require ( github.com/OneOfOne/go-utils v0.0.0-20180319162427-6019ff89a94e - github.com/bufbuild/protocompile v0.13.0 - github.com/coreos/pkg v0.0.0-20240122114842-bbd7aa9bf6fb + github.com/bufbuild/protocompile v0.14.0 github.com/emicklei/proto v1.13.2 - github.com/ethereum/go-ethereum v1.14.3 + github.com/ethereum/go-ethereum v1.14.7 github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/gorilla/handlers v1.5.2 @@ -15,70 +14,68 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/improbable-eng/grpc-web v0.15.0 github.com/ipfs/go-cid v0.4.1 - github.com/ipfs/kubo v0.28.0 - github.com/jonboulle/clockwork v0.4.0 - github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible + github.com/ipfs/kubo v0.29.0 github.com/magiconair/properties v1.8.7 github.com/pkg/errors v0.9.1 github.com/rs/cors v1.11.0 github.com/rs/xid v1.5.0 github.com/singnet/snet-ecosystem-contracts v0.1.1 - github.com/sirupsen/logrus v1.9.3 github.com/soheilhy/cmux v0.1.5 github.com/spf13/cast v1.6.0 - github.com/spf13/cobra v1.8.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.18.2 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - github.com/zbindenren/logrus_mail v0.0.0-20201006120535-9ec03a23b467 - go.etcd.io/etcd/client/v3 v3.5.13 - go.etcd.io/etcd/server/v3 v3.5.13 - golang.org/x/crypto v0.23.0 - golang.org/x/net v0.25.0 + go.etcd.io/etcd/client/v3 v3.5.14 + go.etcd.io/etcd/server/v3 v3.5.14 + go.uber.org/zap v1.27.0 + golang.org/x/crypto v0.25.0 + golang.org/x/net v0.27.0 golang.org/x/time v0.5.0 - google.golang.org/grpc v1.64.0 - google.golang.org/protobuf v1.34.1 + google.golang.org/grpc v1.65.0 + google.golang.org/protobuf v1.34.2 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( github.com/DataDog/zstd v1.4.5 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/StackExchange/wmi v1.2.1 // indirect - github.com/VictoriaMetrics/fastcache v1.12.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v1.1.0 // indirect + github.com/cockroachdb/pebble v1.1.1 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 // indirect - github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/deckarep/golang-set/v2 v2.1.0 // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ethereum/c-kzg-4844 v1.0.2 // indirect + github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 // indirect github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fjl/memsize v0.0.2 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect - github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect - github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -93,7 +90,7 @@ require ( github.com/gorilla/websocket v1.5.1 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-bexpr v0.1.10 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -102,17 +99,17 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.4 // indirect + github.com/holiman/uint256 v1.3.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.19.0 // indirect + github.com/ipfs/boxo v0.20.0 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-block-format v0.2.0 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect github.com/ipfs/go-ds-measure v0.2.0 // indirect github.com/ipfs/go-fs-lock v0.0.7 // indirect - github.com/ipfs/go-ipfs-cmds v0.10.0 // indirect + github.com/ipfs/go-ipfs-cmds v0.11.0 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect github.com/ipfs/go-ipld-cbor v0.1.0 // indirect github.com/ipfs/go-ipld-format v0.6.0 // indirect @@ -126,15 +123,15 @@ require ( github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/goprocess v0.1.4 // indirect + github.com/jonboulle/clockwork v0.2.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.6 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-libp2p v0.33.2 // indirect + github.com/libp2p/go-libp2p v0.34.1 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-libp2p-kad-dht v0.25.2 // indirect github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect @@ -156,7 +153,7 @@ require ( github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr v0.12.3 // indirect + github.com/multiformats/go-multiaddr v0.12.4 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect @@ -166,27 +163,28 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_golang v1.19.0 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.53.0 // indirect - github.com/prometheus/procfs v0.14.0 // indirect + github.com/prometheus/procfs v0.15.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/samber/lo v1.39.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/supranational/blst v0.3.11 // indirect + github.com/supranational/blst v0.3.12 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect @@ -199,39 +197,37 @@ require ( github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.etcd.io/bbolt v1.3.9 // indirect - go.etcd.io/etcd/api/v3 v3.5.13 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect - go.etcd.io/etcd/client/v2 v2.305.13 // indirect - go.etcd.io/etcd/pkg/v3 v3.5.13 // indirect - go.etcd.io/etcd/raft/v3 v3.5.13 // indirect + go.etcd.io/bbolt v1.3.10 // indirect + go.etcd.io/etcd/api/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/v2 v2.305.14 // indirect + go.etcd.io/etcd/pkg/v3 v3.5.14 // indirect + go.etcd.io/etcd/raft/v3 v3.5.14 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect - go.opentelemetry.io/otel v1.25.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.25.0 // indirect - go.opentelemetry.io/otel/sdk v1.25.0 // indirect - go.opentelemetry.io/otel/trace v1.25.0 // indirect - go.opentelemetry.io/proto/otlp v1.1.0 // indirect + go.opentelemetry.io/otel v1.26.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0 // indirect + go.opentelemetry.io/otel/metric v1.26.0 // indirect + go.opentelemetry.io/otel/sdk v1.26.0 // indirect + go.opentelemetry.io/otel/trace v1.26.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect - golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect + golang.org/x/mod v0.19.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.20.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.23.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect gonum.org/v1/gonum v0.15.0 // indirect google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.2.2 // indirect + lukechampine.com/blake3 v1.3.0 // indirect nhooyr.io/websocket v1.8.7 // indirect rsc.io/tmplfunc v0.0.3 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 096b5213..8c0bd83a 100644 --- a/go.sum +++ b/go.sum @@ -26,16 +26,16 @@ github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t github.com/Jorropo/jsync v1.0.1 h1:6HgRolFZnsdfzRUj+ImB9og1JYOxQoReSywkHOGSaUU= github.com/Jorropo/jsync v1.0.1/go.mod h1:jCOZj3vrBCri3bSU3ErUYvevKlnbssrXeCivybS5ABQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/go-utils v0.0.0-20180319162427-6019ff89a94e h1:Kzs/MKSycSiJUW63f+BddSnX+3C5r+7JbHBV0b2wp50= github.com/OneOfOne/go-utils v0.0.0-20180319162427-6019ff89a94e/go.mod h1:oB/bL1T7aOtIWE/pkfR+SRdXfwbUyVe/0GogdHQxync= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= -github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -71,19 +71,17 @@ github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJR github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/bufbuild/protocompile v0.13.0 h1:6cwUB0Y2tSvmNxsbunwzmIto3xOlJOV7ALALuVOs92M= -github.com/bufbuild/protocompile v0.13.0/go.mod h1:dr++fGGeMPWHv7jPeT06ZKukm45NJscd7rUxQVzEKRk= +github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU= +github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU= github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= @@ -104,12 +102,14 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= -github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= -github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= +github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= @@ -124,20 +124,17 @@ github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHq github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20240122114842-bbd7aa9bf6fb h1:GIzvVQ9UkUlOhSDlqmrQAAAUd6R3E+caIisNEyWXvNE= -github.com/coreos/pkg v0.0.0-20240122114842-bbd7aa9bf6fb/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 h1:ZFUue+PNxmHlu7pYv+IYMtqlaO/0VwaGEqKepZf9JpA= github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I= +github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -150,8 +147,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= -github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= @@ -181,14 +178,12 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v1.0.1 h1:pGixCbGizcVKSwoV70ge48+PrbB+iSKs2rjgfE4yJmQ= -github.com/ethereum/c-kzg-4844 v1.0.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844 v1.0.2 h1:8tV84BCEiPeOkiVgW9mpYBeBUir2bkCNVqxPwwVeO+s= github.com/ethereum/c-kzg-4844 v1.0.2/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.14.0 h1:xRWC5NlB6g1x7vNy4HDBLuqVNbtLrc7v8S6+Uxim1LU= -github.com/ethereum/go-ethereum v1.14.0/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= -github.com/ethereum/go-ethereum v1.14.3 h1:5zvnAqLtnCZrU9uod1JCvHWJbPMURzYFHfc2eHz4PHA= -github.com/ethereum/go-ethereum v1.14.3/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= +github.com/ethereum/go-ethereum v1.14.7 h1:EHpv3dE8evQmpVEQ/Ne2ahB06n2mQptdwqaMNhAT29g= +github.com/ethereum/go-ethereum v1.14.7/go.mod h1:Mq0biU2jbdmKSZoqOj29017ygFrMnB5/Rifwp980W4o= +github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= +github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -212,10 +207,8 @@ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uq github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= -github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= -github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -255,7 +248,8 @@ github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -334,8 +328,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 h1:velgFPYr1X9TDwLIfkV7fWqsFlf7TeP11M/7kPd/dVI= +github.com/google/pprof v0.0.0-20240509144519-723abb6459b7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -369,8 +363,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -407,8 +401,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= +github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= @@ -426,14 +420,14 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.19.0 h1:UbX9FBJQF19ACLqRZOgdEla6jR/sC4H1O+iGE0NToXA= -github.com/ipfs/boxo v0.19.0/go.mod h1:V5gJzbIMwKEXrg3IdvAxIdF7UPgU4RsXmNGS8MQ/0D4= +github.com/ipfs/boxo v0.20.0 h1:umUl7q1v5g5AX8FPLTnZBvvagLmT+V0Tt61EigP81ec= +github.com/ipfs/boxo v0.20.0/go.mod h1:mwttn53Eibgska2DhVIj7ln3UViq7MVHRxOMb+ehSDM= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= -github.com/ipfs/go-blockservice v0.5.0 h1:B2mwhhhVQl2ntW2EIpaWPwSCxSuqr5fFA93Ms4bYLEY= -github.com/ipfs/go-blockservice v0.5.0/go.mod h1:W6brZ5k20AehbmERplmERn8o2Ni3ZZubvAxaIUeaT6w= +github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8= +github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q= @@ -453,21 +447,21 @@ github.com/ipfs/go-ds-measure v0.2.0 h1:sG4goQe0KDTccHMyT45CY1XyUbxe5VwTKpg2LjAp github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9UvVh8V3JxE= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= -github.com/ipfs/go-ipfs-blockstore v1.3.0 h1:m2EXaWgwTzAfsmt5UdJ7Is6l4gJcaM/A12XwJyvYvMM= -github.com/ipfs/go-ipfs-blockstore v1.3.0/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= +github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ= +github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-cmds v0.10.0 h1:ZB4+RgYaH4UARfJY0uLKl5UXgApqnRjKbuCiJVcErYk= -github.com/ipfs/go-ipfs-cmds v0.10.0/go.mod h1:sX5d7jkCft9XLPnkgEfXY0z2UBOB5g6fh/obBS0enJE= +github.com/ipfs/go-ipfs-cmds v0.11.0 h1:6AsTKwbVxwzrOkq2x89e6jYMGxzYqjt/WbAam69HZQE= +github.com/ipfs/go-ipfs-cmds v0.11.0/go.mod h1:DHp7YfJlOK+2IS07nk+hFmbKHK52tc29W38CaAgWHpk= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= -github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= -github.com/ipfs/go-ipfs-exchange-interface v0.2.0 h1:8lMSJmKogZYNo2jjhUs0izT+dck05pqUw4mWNW9Pw6Y= -github.com/ipfs/go-ipfs-exchange-interface v0.2.0/go.mod h1:z6+RhJuDQbqKguVyslSOuVDhqF9JtTrO3eptSAiW2/Y= +github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw= +github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo= +github.com/ipfs/go-ipfs-exchange-interface v0.2.1 h1:jMzo2VhLKSHbVe+mHNzYgs95n0+t0Q69GQ5WhRDZV/s= +github.com/ipfs/go-ipfs-exchange-interface v0.2.1/go.mod h1:MUsYn6rKbG6CTtsDp+lKJPmVt3ZrCViNyH3rfPGsZ2E= github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA= github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s= github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE= @@ -501,10 +495,12 @@ github.com/ipfs/go-unixfs v0.4.5 h1:wj8JhxvV1G6CD7swACwSKYa+NgtdWC1RUit+gFnymDU= github.com/ipfs/go-unixfs v0.4.5/go.mod h1:BIznJNvt/gEx/ooRMI4Us9K8+qeGO7vx1ohnbk8gjFg= github.com/ipfs/go-unixfsnode v1.9.0 h1:ubEhQhr22sPAKO2DNsyVBW7YB/zA8Zkif25aBvz8rc8= github.com/ipfs/go-unixfsnode v1.9.0/go.mod h1:HxRu9HYHOjK6HUqFBAi++7DVoWAHn0o4v/nZ/VA+0g8= -github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs= -github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU= -github.com/ipfs/kubo v0.28.0 h1:JmIunSz43G7BSrZZbSWVA5pJZNR1No3pFA8DiY2UOEA= -github.com/ipfs/kubo v0.28.0/go.mod h1:QQ0V6ENy2GQ6zbX9ISUhAayojtb36TTw5e7iT06WPDA= +github.com/ipfs/go-verifcid v0.0.3 h1:gmRKccqhWDocCRkC+a59g5QW7uJw5bpX9HWBevXa0zs= +github.com/ipfs/go-verifcid v0.0.3/go.mod h1:gcCtGniVzelKrbk9ooUSX/pM3xlH73fZZJDzQJRvOUw= +github.com/ipfs/kubo v0.29.0 h1:J5G5le0/gYkx8qLN/zxDl0LcEXKbHZyMh4FCuQN1nVo= +github.com/ipfs/kubo v0.29.0/go.mod h1:mLhuve/44BxEX5ujEihviRXiaxdlrja3kjJgEs2WhK0= +github.com/ipld/go-car v0.6.2 h1:Hlnl3Awgnq8icK+ze3iRghk805lu8YNq3wlREDTF2qc= +github.com/ipld/go-car v0.6.2/go.mod h1:oEGXdwp6bmxJCZ+rARSkDliTeYnVzv3++eXajZ+Bmr8= github.com/ipld/go-car/v2 v2.13.1 h1:KnlrKvEPEzr5IZHKTXLAEub+tPrzeAFQVRlSQvuxBO4= github.com/ipld/go-car/v2 v2.13.1/go.mod h1:QkdjjFNGit2GIkpQ953KBwowuoukoM75nP/JI1iDJdo= github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc= @@ -522,8 +518,8 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= -github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -543,10 +539,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= -github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= @@ -567,12 +563,6 @@ github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2 github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= -github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= -github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= -github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= -github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= -github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= @@ -581,16 +571,16 @@ github.com/libp2p/go-doh-resolver v0.4.0 h1:gUBa1f1XsPwtpE1du0O+nnZCUqtG7oYi7Bb+ github.com/libp2p/go-doh-resolver v0.4.0/go.mod h1:v1/jwsFusgsWIGX/c6vCRrnJ60x7bhTiq/fs2qt0cAg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.33.2 h1:vCdwnFxoGOXMKmaGHlDSnL4bM3fQeW8pgIa9DECnb40= -github.com/libp2p/go-libp2p v0.33.2/go.mod h1:zTeppLuCvUIkT118pFVzA8xzP/p2dJYOMApCkFh0Yww= +github.com/libp2p/go-libp2p v0.34.1 h1:fxn9vyLo7vJcXQRNvdRbyPjbzuQgi2UiqC8hEbn8a18= +github.com/libp2p/go-libp2p v0.34.1/go.mod h1:snyJQix4ET6Tj+LeI0VPjjxTtdWpeOhYt5lEY0KirkQ= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-kad-dht v0.25.2 h1:FOIk9gHoe4YRWXTu8SY9Z1d0RILol0TrtApsMDPjAVQ= github.com/libp2p/go-libp2p-kad-dht v0.25.2/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= -github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= -github.com/libp2p/go-libp2p-pubsub v0.10.0/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw= +github.com/libp2p/go-libp2p-pubsub v0.11.0 h1:+JvS8Kty0OiyUiN0i8H5JbaCgjnJTRnTHe4rU88dLFc= +github.com/libp2p/go-libp2p-pubsub v0.11.0/go.mod h1:QEb+hEV9WL9wCiUAnpY29FZR6W3zK8qYlaml8R4q6gQ= github.com/libp2p/go-libp2p-pubsub-router v0.6.0 h1:D30iKdlqDt5ZmLEYhHELCMRj8b4sFAqrUcshIUvVP/s= github.com/libp2p/go-libp2p-pubsub-router v0.6.0/go.mod h1:FY/q0/RBTKsLA7l4vqC2cbRbOvyDotg8PJQ7j8FDudE= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= @@ -681,8 +671,8 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.12.3 h1:hVBXvPRcKG0w80VinQ23P5t7czWgg65BmIvQKjDydU8= -github.com/multiformats/go-multiaddr v0.12.3/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= +github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -712,8 +702,9 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -724,8 +715,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU= +github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= @@ -743,15 +734,15 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA= -github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY= +github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= +github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= -github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= @@ -759,38 +750,38 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= -github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0= -github.com/pion/dtls/v2 v2.2.8 h1:BUroldfiIbV9jSnC6cKOMnyiORRWrWWpV11JUyEu5OA= -github.com/pion/dtls/v2 v2.2.8/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= -github.com/pion/ice/v2 v2.3.11 h1:rZjVmUwyT55cmN8ySMpL7rsS8KYsJERsrxJLLxpKhdw= -github.com/pion/ice/v2 v2.3.11/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E= -github.com/pion/interceptor v0.1.25 h1:pwY9r7P6ToQ3+IF0bajN0xmk/fNw/suTgaTdlwTDmhc= -github.com/pion/interceptor v0.1.25/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y= +github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= +github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= +github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= +github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.9 h1:7Ue5KZsqq8EuqStnpPWV33vYYEH0+skdDN5L7EiEsI4= -github.com/pion/mdns v0.0.9/go.mod h1:2JA5exfxwzXiCihmxpTKgFUpiQws2MnipoPK09vecIc= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.13 h1:+EQijuisKwm/8VBs8nWllr0bIndR7Lf7cZG200mpbNo= -github.com/pion/rtcp v1.2.13/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.3 h1:VEHxqzSVQxCkKDSHro5/4IUUG1ea+MFdqR2R3xSpNU8= -github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.9 h1:TP5ZVxV5J7rz7uZmbyvnUvsn7EJ2x/5q9uhsTtXbI3g= -github.com/pion/sctp v1.8.9/go.mod h1:cMLT45jqw3+jiJCrtHVwfQLnfR0MGZ4rgOJwUOIqLkI= -github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw= -github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= +github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= +github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= -github.com/pion/transport/v2 v2.2.4 h1:41JJK6DZQYSeVLxILA2+F4ZkKb4Xd/tFJZRFZQ9QAlo= -github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/turn/v2 v2.1.4 h1:2xn8rduI5W6sCZQkEnIUDAkrBQNl2eYIBCHMZ3QMmP8= -github.com/pion/turn/v2 v2.1.4/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.23 h1:GbqEuxBbVLFhXk0GwxKAoaIJYiEa9TyoZPEZC+2HZxM= -github.com/pion/webrtc/v3 v3.2.23/go.mod h1:1CaT2fcZzZ6VZA+O1i9yK2DU4EOcXVvSbWG9pr5jefs= +github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= +github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= +github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -808,8 +799,8 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -831,14 +822,14 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s= -github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ= +github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek= +github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= -github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= -github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= -github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= +github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= +github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -860,8 +851,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= @@ -871,8 +862,6 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/singnet/snet-ecosystem-contracts v0.1.0 h1:vTWItKR/b5MJBsdZX4Dpbds/yoIIZEHQBGTPu8JH4Sg= -github.com/singnet/snet-ecosystem-contracts v0.1.0/go.mod h1:upRHFLALLPm2chI/tdYGuF/4Kh8RB6rjdVR8HnH27SI= github.com/singnet/snet-ecosystem-contracts v0.1.1 h1:d/xa8T6iFt9efLKATY9SNIu+/lL47Hn9NwszjIEKjnQ= github.com/singnet/snet-ecosystem-contracts v0.1.1/go.mod h1:upRHFLALLPm2chI/tdYGuF/4Kh8RB6rjdVR8HnH27SI= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -901,13 +890,13 @@ github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNo github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -930,8 +919,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= -github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.12 h1:Vfas2U2CFHhniv2QkUm2OVa1+pGTdqtpqm9NnhUUbZ8= +github.com/supranational/blst v0.3.12/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -980,26 +969,24 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zbindenren/logrus_mail v0.0.0-20201006120535-9ec03a23b467 h1:XDZPGSRSOhoMTouMFJUfOXijMQSh+elkG4Q39+UaLaw= -github.com/zbindenren/logrus_mail v0.0.0-20201006120535-9ec03a23b467/go.mod h1:cbf3evkvbZXZU3sunY1L3MmsZ/I6/oK5pksOGQGHO2g= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd/api/v3 v3.5.13 h1:8WXU2/NBge6AUF1K1gOexB6e07NgsN1hXK0rSTtgSp4= -go.etcd.io/etcd/api/v3 v3.5.13/go.mod h1:gBqlqkcMMZMVTMm4NDZloEVJzxQOQIls8splbqBDa0c= -go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg= -go.etcd.io/etcd/client/pkg/v3 v3.5.13/go.mod h1:XxHT4u1qU12E2+po+UVPrEeL94Um6zL58ppuJWXSAB8= -go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= -go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= -go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js= -go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI= -go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= -go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= -go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= -go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= -go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= -go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= +go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= +go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= +go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= +go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= +go.etcd.io/etcd/client/v2 v2.305.14 h1:v5ASLyFuMlVd/gKU6uf6Cod+vSWKa4Rsv9+eghl0Nwk= +go.etcd.io/etcd/client/v2 v2.305.14/go.mod h1:AWYT0lLEkBuqVaGw0UVMtA4rxCb3/oGE8PxZ8cUS4tI= +go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= +go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= +go.etcd.io/etcd/pkg/v3 v3.5.14 h1:keuxhJiDCPjTKpW77GxJnnVVD5n4IsfvkDaqiqUMNEQ= +go.etcd.io/etcd/pkg/v3 v3.5.14/go.mod h1:7o+DL6a7DYz9KSjWByX+NGmQPYinoH3D36VAu/B3JqA= +go.etcd.io/etcd/raft/v3 v3.5.14 h1:mHnpbljpBBftmK+YUfp+49ivaCc126aBPLAnwDw0DnE= +go.etcd.io/etcd/raft/v3 v3.5.14/go.mod h1:WnIK5blyJGRKsHA3efovdNoLv9QELTZHzpDOVIAuL2s= +go.etcd.io/etcd/server/v3 v3.5.14 h1:l/3gdiSSoGU6MyKAYiL+8WSOMq9ySG+NqQ04euLtZfY= +go.etcd.io/etcd/server/v3 v3.5.14/go.mod h1:SPh0rUtGNDgOZd/aTbkAUYZV+5FFHw5sdbGnO2/byw0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1008,32 +995,30 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30= -go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E= -go.opentelemetry.io/otel/exporters/zipkin v1.21.0 h1:D+Gv6lSfrFBWmQYyxKjDd0Zuld9SRXpIrEsKZvE4DO4= -go.opentelemetry.io/otel/exporters/zipkin v1.21.0/go.mod h1:83oMKR6DzmHisFOW3I+yIMGZUTjxiWaiBI8M8+TU5zE= -go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= -go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= -go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= +go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 h1:1u/AyyOqAWzy+SkPxDpahCNZParHV8Vid1RnI2clyDE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0/go.mod h1:z46paqbJ9l7c9fIPCXTqTGwhQZ5XoTIsfeFYWboizjs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0 h1:Waw9Wfpo/IXzOI8bCB7DIk+0JZcqqsyn1JFnAc+iam8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0/go.mod h1:wnJIG4fOqyynOnnQF/eQb4/16VlX2EJAHhHgqIqWfAo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 h1:1wp/gyxsuYtuE/JFxsQRtcCDtMrO2qMvlfXALU5wkzI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0/go.mod h1:gbTHmghkGgqxMomVQQMur1Nba4M0MQ8AYThXDUjsJ38= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0 h1:0W5o9SzoR15ocYHEQfvfipzcNog1lBxOLfnex91Hk6s= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0/go.mod h1:zVZ8nz+VSggWmnh6tTsJqXQ7rU4xLwRtna1M4x5jq58= +go.opentelemetry.io/otel/exporters/zipkin v1.26.0 h1:sBk6A62GgcQRwcxcBwRMPkqeuSizcpHkXyZNyP281Fw= +go.opentelemetry.io/otel/exporters/zipkin v1.26.0/go.mod h1:fLzYtPUxPFzu7rSqhYsCxYheT2dNoPjtKovCLzLm07w= +go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= +go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= +go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= +go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= +go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1043,8 +1028,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= -go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= +go.uber.org/fx v1.21.1 h1:RqBh3cYdzZS0uqwVeEjOX2p73dddLpym315myy/Bpb0= +go.uber.org/fx v1.21.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -1078,10 +1063,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1091,8 +1074,8 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1115,8 +1098,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1154,10 +1137,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1230,10 +1211,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1245,10 +1225,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1290,8 +1268,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1335,12 +1313,10 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 h1:PgNlNSx2Nq2/j4juYzQBG0/Zdr+WP4z5N01Vk4VYBCY= google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237/go.mod h1:9sVD8c25Af3p0rGs7S7LLsxWKFiJt/65LdSyqXBkX/Y= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1358,10 +1334,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1372,10 +1346,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002 h1:V7Da7qt0MkY3noVANIMVBk28nOnijADeOR3i5Hcvpj4= -google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1416,8 +1388,8 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -lukechampine.com/blake3 v1.2.2 h1:wEAbSg0IVU4ih44CVlpMqMZMpzr5hf/6aqodLlevd/w= -lukechampine.com/blake3 v1.2.2/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/handler/grpc.go b/handler/grpc.go index d35637ba..b36591d9 100644 --- a/handler/grpc.go +++ b/handler/grpc.go @@ -4,11 +4,18 @@ import ( "bytes" "context" "encoding/json" - "github.com/gorilla/rpc/v2/json2" + "io" + "net/http" + "net/url" + "os/exec" + "strings" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/codec" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + + "github.com/gorilla/rpc/v2/json2" + "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -18,11 +25,6 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/types/dynamicpb" - "io" - "net/http" - "net/url" - "os/exec" - "strings" ) var grpcDesc = &grpc.StreamDesc{ServerStreams: true, ClientStreams: true} @@ -78,7 +80,7 @@ func NewGrpcHandler(serviceMetadata *blockchain.ServiceMetadata) grpc.StreamHand h.serviceCredentials = []serviceCredential{} err := config.Vip().UnmarshalKey(config.ServiceCredentialsKey, &h.serviceCredentials) if err != nil { - log.WithError(err).Panic("invalid config") + zap.L().Panic("invalid config", zap.Error(err)) } return h.grpcToHTTP case "process": @@ -90,19 +92,19 @@ func NewGrpcHandler(serviceMetadata *blockchain.ServiceMetadata) grpc.StreamHand func (h grpcHandler) getConnection(endpoint string) (conn *grpc.ClientConn) { passthroughURL, err := url.Parse(endpoint) if err != nil { - log.WithError(err).Panic("error parsing passthrough endpoint") + zap.L().Panic("error parsing passthrough endpoint", zap.Error(err)) } if strings.Compare(passthroughURL.Scheme, "https") == 0 { conn, err = grpc.Dial(passthroughURL.Host, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")), h.options) if err != nil { - log.WithError(err).Panic("error dialing service") + zap.L().Panic("error dialing service", zap.Error(err)) } } else { conn, err = grpc.Dial(passthroughURL.Host, grpc.WithInsecure(), h.options) if err != nil { - log.WithError(err).Panic("error dialing service") + zap.L().Panic("error dialing service", zap.Error(err)) } } return @@ -113,7 +115,7 @@ Modified from https://github.com/mwitkow/grpc-proxy/blob/67591eb23c48346a480470e Original Copyright 2017 Michal Witkowski. All Rights Reserved. See LICENSE-GRPC-PROXY for licensing terms. Modifications Copyright 2018 SingularityNET Foundation. All Rights Reserved. See LICENSE for licensing terms. */ -func (g grpcHandler) grpcToGRPC(srv interface{}, inStream grpc.ServerStream) error { +func (g grpcHandler) grpcToGRPC(srv any, inStream grpc.ServerStream) error { method, ok := grpc.MethodFromServerStream(inStream) if !ok { @@ -254,7 +256,7 @@ type serviceCredential struct { Location httpLocation `json:"location"` } -func (g grpcHandler) grpcToHTTP(srv interface{}, inStream grpc.ServerStream) error { +func (g grpcHandler) grpcToHTTP(srv any, inStream grpc.ServerStream) error { method, ok := grpc.MethodFromServerStream(inStream) if !ok { @@ -264,22 +266,22 @@ func (g grpcHandler) grpcToHTTP(srv interface{}, inStream grpc.ServerStream) err methodSegs := strings.Split(method, "/") method = methodSegs[len(methodSegs)-1] - log.Debugln("Calling Method: ", method) + zap.L().Info("Calling method", zap.String("method", method)) f := &codec.GrpcFrame{} if err := inStream.RecvMsg(f); err != nil { - log.Println(err) + zap.L().Error(err.Error()) return status.Errorf(codes.Internal, "error receiving request; error: %+cred", err) } // convert proto msg to json jsonBody := protoToJson(g.serviceMetaData.ProtoFile, f.Data, method) - log.Debugln("Proto to json: ", string(jsonBody)) + zap.L().Debug("Proto to json", zap.String("json", string(jsonBody))) base, err := url.Parse(g.passthroughEndpoint) if err != nil { - log.Println("cant' parse passthroughEndpoint: ", err) + zap.L().Error("can't parse passthroughEndpoint", zap.Error(err)) } base.Path += method // method from proto should be the same as http handler path @@ -314,12 +316,12 @@ func (g grpcHandler) grpcToHTTP(srv interface{}, inStream grpc.ServerStream) err if err == nil { jsonBody = newJson } else { - log.Debugln("Can't marshal json: ", err) + zap.L().Debug("Can't marshal json", zap.Error(err)) } } base.RawQuery = params.Encode() - log.Debugln("Calling URL: ", base.String()) + zap.L().Debug("Calling URL", zap.String("Url", base.String())) httpReq, err := http.NewRequest("POST", base.String(), bytes.NewBuffer(jsonBody)) httpReq.Header = headers if err != nil { @@ -338,7 +340,7 @@ func (g grpcHandler) grpcToHTTP(srv interface{}, inStream grpc.ServerStream) err if err != nil { return status.Errorf(codes.Internal, "error reading response; error: %+cred", err) } - log.Println("string resp: ", string(resp)) + zap.L().Debug("Getting response", zap.String("response", string(resp))) protoMessage := jsonToProto(g.serviceMetaData.ProtoFile, resp, method) if err = inStream.SendMsg(protoMessage); err != nil { @@ -350,31 +352,31 @@ func (g grpcHandler) grpcToHTTP(srv interface{}, inStream grpc.ServerStream) err func jsonToProto(protoFile protoreflect.FileDescriptor, json []byte, methodName string) (proto proto.Message) { - log.Debugln("Processing file:", protoFile.Name()) - log.Debugln("Count services: ", protoFile.Services().Len()) + zap.L().Debug("Processing file", zap.String("fileName", string(protoFile.Name()))) + zap.L().Debug("Count services: ", zap.Int("value", protoFile.Services().Len())) if protoFile.Services().Len() == 0 { - log.Println("service in proto not found") + zap.L().Warn("service in proto not found") return proto } service := protoFile.Services().Get(0) if service == nil { - log.Println("service in proto not found") + zap.L().Warn("service in proto not found") return proto } method := service.Methods().ByName(protoreflect.Name(methodName)) if method == nil { - log.Println("method not found") + zap.L().Warn("method not found in proto") return proto } output := method.Output() - log.Debugln("output of calling method:", output.FullName()) + zap.L().Debug("output of calling method", zap.Any("method", output.FullName())) proto = dynamicpb.NewMessage(output) err := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}.Unmarshal(json, proto) if err != nil { - log.Println("Can't unmarshal jsonToProto: ", err) + zap.L().Error("Can't unmarshal jsonToProto", zap.Error(err)) } return proto @@ -383,41 +385,41 @@ func jsonToProto(protoFile protoreflect.FileDescriptor, json []byte, methodName func protoToJson(protoFile protoreflect.FileDescriptor, in []byte, methodName string) (json []byte) { if protoFile.Services().Len() == 0 { - log.Println("service in proto not found") + zap.L().Warn("service in proto not found") return []byte("error, invalid proto file") } service := protoFile.Services().Get(0) if service == nil { - log.Println("service in proto not found") + zap.L().Warn("service in proto not found") return []byte("error, invalid proto file") } method := service.Methods().ByName(protoreflect.Name(methodName)) if method == nil { - log.Println("method not found") + zap.L().Warn("method not found in proto") return []byte("error, invalid proto file or input request") } input := method.Input() - log.Debugln("Input fullname method: ", input.FullName()) + zap.L().Debug("Input fullname method", zap.Any("value", input.FullName())) msg := dynamicpb.NewMessage(input) err := proto.Unmarshal(in, msg) if err != nil { - log.Println("proto.Unmarshal: ", err) + zap.L().Error("Error in unmarshalling", zap.Error(err)) return []byte("error, invalid proto file or input request") } json, err = protojson.MarshalOptions{UseProtoNames: true}.Marshal(msg) if err != nil { - log.Println("protojson.Marshal: ", err) + zap.L().Error("Error in marshaling", zap.Error(err)) return []byte("error, invalid proto file or input request") } - log.Debugln("jsonBytes: ", string(json)) + zap.L().Debug("Getting json", zap.String("json", string(json))) return json } -func (g grpcHandler) grpcToJSONRPC(srv interface{}, inStream grpc.ServerStream) error { +func (g grpcHandler) grpcToJSONRPC(srv any, inStream grpc.ServerStream) error { method, ok := grpc.MethodFromServerStream(inStream) if !ok { @@ -436,7 +438,7 @@ func (g grpcHandler) grpcToJSONRPC(srv interface{}, inStream grpc.ServerStream) return status.Errorf(codes.Internal, "error receiving request; error: %+v", err) } - params := new(interface{}) + params := new(any) if err := json.Unmarshal(f.Data, params); err != nil { return status.Errorf(codes.Internal, "error unmarshaling request; error: %+v", err) @@ -523,19 +525,19 @@ func (f *WrapperServerStream) Context() context.Context { return f.stream.Context() } -func (f *WrapperServerStream) SendMsg(m interface{}) error { +func (f *WrapperServerStream) SendMsg(m any) error { return f.stream.SendMsg(m) } -func (f *WrapperServerStream) RecvMsg(m interface{}) error { +func (f *WrapperServerStream) RecvMsg(m any) error { return f.stream.RecvMsg(m) } -func (f *WrapperServerStream) OriginalRecvMsg() interface{} { +func (f *WrapperServerStream) OriginalRecvMsg() any { return f.recvMessage } -func (g grpcHandler) grpcToProcess(srv interface{}, inStream grpc.ServerStream) error { +func (g grpcHandler) grpcToProcess(srv any, inStream grpc.ServerStream) error { method, ok := grpc.MethodFromServerStream(inStream) if !ok { @@ -577,7 +579,7 @@ func (g grpcHandler) grpcToProcess(srv interface{}, inStream grpc.ServerStream) return nil } -func grpcLoopback(srv interface{}, inStream grpc.ServerStream) error { +func grpcLoopback(srv any, inStream grpc.ServerStream) error { f := &codec.GrpcFrame{} if err := inStream.RecvMsg(f); err != nil { return status.Errorf(codes.Internal, "error receiving request; error: %+v", err) diff --git a/handler/grpc_test.go b/handler/grpc_test.go index 4c86e3a1..c7ffca0d 100644 --- a/handler/grpc_test.go +++ b/handler/grpc_test.go @@ -77,7 +77,8 @@ func (suite *GrpcTestSuite) TestReturnCustomErrorCodeViaGrpc() { _, err := client.Ping(context.Background(), &Input{Message: "ping"}) - assert.Equal(suite.T(), err, expectedErr) + assert.Equal(suite.T(), status.Code(err), status.Code(expectedErr)) + assert.Equal(suite.T(), status.Convert(err).Message(), status.Convert(expectedErr).Message()) } func (suite *GrpcTestSuite) TestPassThroughEndPoint() { diff --git a/handler/interceptors.go b/handler/interceptors.go index 0a426470..5633eaac 100644 --- a/handler/interceptors.go +++ b/handler/interceptors.go @@ -2,21 +2,24 @@ package handler import ( "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" "github.com/singnet/snet-daemon/configuration_service" "github.com/singnet/snet-daemon/metrics" "github.com/singnet/snet-daemon/ratelimit" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" + + "math/big" + "strings" + "time" + "golang.org/x/time/rate" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" - "math/big" - "strings" - "time" ) const ( @@ -85,7 +88,7 @@ func (context *GrpcStreamContext) String() string { // Payment represents payment handler specific data which is validated // and used to complete payment. -type Payment interface{} +type Payment any // Custom gRPC codes to return to the client const ( @@ -125,7 +128,7 @@ func NewGrpcError(code codes.Code, message string) *GrpcError { // NewGrpcErrorf returns new error which contains gRPC status with provided // code and message formed from format string and args. -func NewGrpcErrorf(code codes.Code, format string, args ...interface{}) *GrpcError { +func NewGrpcErrorf(code codes.Code, format string, args ...any) *GrpcError { return &GrpcError{ Status: status.Newf(code, format, args...), } @@ -178,8 +181,8 @@ func GrpcMeteringInterceptor() grpc.StreamServerInterceptor { } // Monitor requests arrived and responses sent and publish these stats for Reporting -func interceptMetering(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { - var e error +func interceptMetering(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + var err error var start time.Time start = time.Now() //Get the method name @@ -193,29 +196,29 @@ func interceptMetering(srv interface{}, ss grpc.ServerStream, info *grpc.StreamS } defer func() { - go metrics.PublishResponseStats(commonStats, time.Now().Sub(start), e) + go metrics.PublishResponseStats(commonStats, time.Now().Sub(start), err) }() - e = handler(srv, ss) - if e != nil { - log.WithError(e) - return e + err = handler(srv, ss) + if err != nil { + zap.L().Error(err.Error()) + return err } return nil } -func (interceptor *rateLimitInterceptor) intercept(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { +func (interceptor *rateLimitInterceptor) intercept(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { if interceptor.processRequest == configuration_service.STOP_PROCESING_ANY_REQUEST { return status.New(codes.Unavailable, "No requests are currently being processed, please try again later").Err() } if !interceptor.rateLimiter.Allow() { - log.WithField("rateLimiter.Burst()", interceptor.rateLimiter.Burst()).Info("rate limit reached, too many requests to handle") + zap.L().Info("rate limit reached, too many requests to handle", zap.Any("rateLimiter.Burst()", interceptor.rateLimiter.Burst())) return status.New(codes.ResourceExhausted, "rate limiting , too many requests to handle").Err() } - e := handler(srv, ss) - if e != nil { - log.WithError(e) - return e + err := handler(srv, ss) + if err != nil { + zap.L().Error(err.Error()) + return err } return nil } @@ -230,10 +233,10 @@ func GrpcPaymentValidationInterceptor(serviceData *blockchain.ServiceMetadata, d } interceptor.paymentHandlers[defaultPaymentHandler.Type()] = defaultPaymentHandler - log.WithField("defaultPaymentType", defaultPaymentHandler.Type()).Info("Default payment handler registered") + zap.L().Info("Default payment handler registered", zap.Any("defaultPaymentType", defaultPaymentHandler.Type())) for _, handler := range paymentHandler { interceptor.paymentHandlers[handler.Type()] = handler - log.WithField("paymentType", handler.Type()).Info("Payment handler for type registered") + zap.L().Info("Payment handler for type registered", zap.Any("paymentType", handler.Type())) } return interceptor.intercept @@ -246,7 +249,7 @@ type paymentValidationInterceptor struct { paymentHandlers map[string]PaymentHandler } -func (interceptor *paymentValidationInterceptor) intercept(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) (e error) { +func (interceptor *paymentValidationInterceptor) intercept(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) (e error) { var err *GrpcError wrapperStream := ss // check we need to have dynamic pricing here @@ -261,7 +264,7 @@ func (interceptor *paymentValidationInterceptor) intercept(srv interface{}, ss g if err != nil { return err.Err() } - log.WithField("context", context).Debug("New gRPC call received") + zap.L().Debug("New gRPC call received", zap.Any("context", context)) paymentHandler, err := interceptor.getPaymentHandler(context) if err != nil { @@ -275,7 +278,7 @@ func (interceptor *paymentValidationInterceptor) intercept(srv interface{}, ss g defer func() { if r := recover(); r != nil { - log.WithField("panicValue", r).Warn("Service handler called panic(panicValue)") + zap.L().Warn("Service handler called panic(panicValue)", zap.Any("panicValue", r)) paymentHandler.CompleteAfterError(payment, fmt.Errorf("Service handler called panic(%v)", r)) panic("re-panic after payment handler error handling") } else if e == nil { @@ -293,11 +296,11 @@ func (interceptor *paymentValidationInterceptor) intercept(srv interface{}, ss g } }() - log.WithField("payment", payment).Debug("New payment received") + zap.L().Debug("New payment received", zap.Any("payment", payment)) e = handler(srv, wrapperStream) if e != nil { - log.WithError(e).Warn("gRPC handler returned error") + zap.L().Warn("gRPC handler returned error", zap.Error(e)) return e } @@ -307,7 +310,7 @@ func (interceptor *paymentValidationInterceptor) intercept(srv interface{}, ss g func getGrpcContext(serverStream grpc.ServerStream, info *grpc.StreamServerInfo) (context *GrpcStreamContext, err *GrpcError) { md, ok := metadata.FromIncomingContext(serverStream.Context()) if !ok { - log.WithField("info", info).Error("Invalid metadata") + zap.L().Error("Invalid metadata", zap.Any("info", info)) return nil, NewGrpcError(codes.InvalidArgument, "missing metadata") } @@ -321,18 +324,19 @@ func getGrpcContext(serverStream grpc.ServerStream, info *grpc.StreamServerInfo) func (interceptor *paymentValidationInterceptor) getPaymentHandler(context *GrpcStreamContext) (handler PaymentHandler, err *GrpcError) { paymentTypeMd, ok := context.MD[PaymentTypeHeader] if !ok || len(paymentTypeMd) == 0 { - log.WithField("defaultPaymentHandlerType", interceptor.defaultPaymentHandler.Type()).Debug("Payment type was not set by caller, return default payment handler") + zap.L().Debug("Payment type was not set by caller, return default payment handler", + zap.String("defaultPaymentHandlerType", interceptor.defaultPaymentHandler.Type())) return interceptor.defaultPaymentHandler, nil } paymentType := paymentTypeMd[0] paymentHandler, ok := interceptor.paymentHandlers[paymentType] if !ok { - log.WithField("paymentType", paymentType).Error("Unexpected payment type") + zap.L().Error("Unexpected payment type", zap.String("paymentType", paymentType)) return nil, NewGrpcErrorf(codes.InvalidArgument, "unexpected \"%v\", value: \"%v\"", PaymentTypeHeader, paymentType) } - log.WithField("paymentType", paymentType).Debug("Return payment handler by type") + zap.L().Debug("Return payment handler by type", zap.Any("paymentType", paymentType)) return paymentHandler, nil } @@ -393,7 +397,7 @@ func GetSingleValue(md metadata.MD, key string) (value string, err *GrpcError) { } // NoOpInterceptor is a gRPC interceptor which doesn't do payment checking. -func NoOpInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, +func NoOpInterceptor(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { return handler(srv, ss) } diff --git a/handler/interceptors_test.go b/handler/interceptors_test.go index afe6f0d7..54ea93d5 100644 --- a/handler/interceptors_test.go +++ b/handler/interceptors_test.go @@ -34,11 +34,11 @@ func (m *serverStreamMock) SendHeader(metadata.MD) error { func (m *serverStreamMock) SetTrailer(metadata.MD) { } -func (m *serverStreamMock) SendMsg(interface{}) error { +func (m *serverStreamMock) SendMsg(any) error { return errors.New("not implemented in mock") } -func (m *serverStreamMock) RecvMsg(interface{}) error { +func (m *serverStreamMock) RecvMsg(any) error { return errors.New("not implemented in mock") } @@ -110,13 +110,13 @@ type InterceptorsSuite struct { } func (suite *InterceptorsSuite) SetupSuite() { - suite.successHandler = func(srv interface{}, stream grpc.ServerStream) error { + suite.successHandler = func(srv any, stream grpc.ServerStream) error { return nil } - suite.returnErrorHandler = func(srv interface{}, stream grpc.ServerStream) error { + suite.returnErrorHandler = func(srv any, stream grpc.ServerStream) error { return errors.New("some error") } - suite.panicHandler = func(srv interface{}, stream grpc.ServerStream) error { + suite.panicHandler = func(srv any, stream grpc.ServerStream) error { panic("some panic") } suite.defaultPaymentHandler = &paymentHandlerMock{typ: defaultPaymentHandlerType} diff --git a/ipfsutils/ipfsutils.go b/ipfsutils/ipfsutils.go index 0daa4fde..4debf671 100644 --- a/ipfsutils/ipfsutils.go +++ b/ipfsutils/ipfsutils.go @@ -4,10 +4,12 @@ import ( "archive/tar" "context" "fmt" + "github.com/ipfs/go-cid" "github.com/ipfs/kubo/client/rpc" "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" + "io" "net/http" "strings" @@ -27,19 +29,19 @@ func ReadFilesCompressed(compressedFile string) (protofiles []string, err error) break } if err != nil { - log.WithError(err) + zap.L().Error(err.Error()) return nil, err } name := header.Name switch header.Typeflag { case tar.TypeDir: - log.WithField("Directory Name", name).Debug("Directory name ") + zap.L().Debug("Directory name", zap.Any("name", name)) case tar.TypeReg: - log.WithField("file Name:", name).Debug("File name ") + zap.L().Debug("File name", zap.Any("name", name)) data := make([]byte, header.Size) _, err := tarReader.Read(data) if err != nil && err != io.EOF { - log.WithError(err) + zap.L().Error(err.Error()) return nil, err } protofiles = append(protofiles, string(data)) @@ -50,7 +52,7 @@ func ReadFilesCompressed(compressedFile string) (protofiles []string, err error) "in file", name, )) - log.WithError(err) + zap.L().Error(err.Error()) return nil, err } } @@ -59,33 +61,33 @@ func ReadFilesCompressed(compressedFile string) (protofiles []string, err error) func GetIpfsFile(hash string) (content string) { - log.WithField("hash", hash).Debug("Hash Used to retrieve from IPFS") + zap.L().Debug("Hash Used to retrieve from IPFS", zap.String("hash", hash)) ipfsClient := GetIPFSClient() cID, err := cid.Parse(hash) if err != nil { - log.WithError(err).WithField("hashFromMetaData", hash).Panic("error parsing the ipfs hash") + zap.L().Panic("error parsing the ipfs hash", zap.String("hashFromMetaData", hash), zap.Error(err)) } req := ipfsClient.Request("cat", cID.String()) if err != nil { - log.WithError(err).WithField("hashFromMetaData", hash).Panic("error executing the cat command in ipfs") + zap.L().Panic("error executing the cat command in ipfs", zap.String("hashFromMetaData", hash), zap.Error(err)) return } resp, err := req.Send(context.Background()) defer resp.Close() if err != nil { - log.WithError(err).WithField("hashFromMetaData", hash).Panic("error executing the cat command in ipfs") + zap.L().Panic("error executing the cat command in ipfs", zap.String("hashFromMetaData", hash), zap.Error(err)) return } if resp.Error != nil { - log.WithError(err).WithField("hashFromMetaData", hash).Panic("error executing the cat command in ipfs") + zap.L().Panic("error executing the cat command in ipfs", zap.String("hashFromMetaData", hash), zap.Error(err)) return } fileContent, err := io.ReadAll(resp.Output) if err != nil { - log.WithError(err).WithField("hashFromMetaData", hash).Panicf("error: in Reading the meta data file %s", err) + zap.L().Panic("error: in Reading the meta data file", zap.Error(err), zap.String("hashFromMetaData", hash)) return } @@ -94,13 +96,15 @@ func GetIpfsFile(hash string) (content string) { // Create a cid manually to check cid _, c, err := cid.CidFromBytes(append(cID.Bytes(), fileContent...)) if err != nil { - log.WithError(err).WithField("hashFromMetaData", hash).Panic("error generating ipfs hash") + zap.L().Panic("error generating ipfs hash", zap.String("hashFromMetaData", hash), zap.Error(err)) return } // To test if two cid's are equivalent, be sure to use the 'Equals' method: if !c.Equals(cID) { - log.WithError(err).WithField("hashFromIPFSContent", c.String()).Panicf("IPFS hash verification failed. Generated hash doesnt match with expected hash %s", hash) + zap.L().Panic("IPFS hash verification failed. Generated hash doesnt match with expected hash", + zap.String("expectedHash", hash), + zap.String("hashFromIPFSContent", c.String())) } return string(fileContent) @@ -112,7 +116,7 @@ func GetIPFSClient() *rpc.HttpApi { } ifpsClient, err := rpc.NewURLApiWithClient(config.GetString(config.IpfsEndPoint), &httpClient) if err != nil { - log.WithError(err).Panicf("Connection failed to IPFS: %s", config.GetString(config.IpfsEndPoint)) + zap.L().Panic("Connection failed to IPFS", zap.String("IPFS", config.GetString(config.IpfsEndPoint)), zap.Error(err)) } return ifpsClient } diff --git a/license_server/license_service.go b/license_server/license_service.go index fb754ba2..2e156032 100644 --- a/license_server/license_service.go +++ b/license_server/license_service.go @@ -15,7 +15,7 @@ type LockingLicenseService struct { ServiceMetaData *blockchain.ServiceMetadata } -//Will be used in the components to create a new instance of LicenseService +// Will be used in the components to create a new instance of LicenseService func NewLicenseService( detailsStorage storage.TypedAtomicStorage, licenseStorage storage.TypedAtomicStorage, orgData *blockchain.OrganizationMetaData, @@ -73,9 +73,9 @@ func (h *LockingLicenseService) UpdateLicenseForChannel(channelId *big.Int, serv return h.LicenseDetailsStorage.Put(LicenseDetailsKey{ServiceID: serviceId, ChannelID: channelId}, &LicenseDetailsData{License: license}) } -//Defines the condition that needs to be met, it generates the respective typed Data when -//conditions are satisfied, you define your own validations in here -//It takes in the latest typed values read. +// Defines the condition that needs to be met, it generates the respective typed Data when +// conditions are satisfied, you define your own validations in here +// It takes in the latest typed values read. type ConditionFuncForLicense func(conditionValues []storage.TypedKeyValueData, incrementUsage *big.Int, channelId *big.Int, serviceId string) ([]storage.TypedKeyValueData, error) @@ -119,7 +119,7 @@ func (h *LockingLicenseService) UpdateLicenseUsage(channelId *big.Int, serviceId } return nil } -func getAllLicenseKeys(channelId *big.Int, serviceId string) []interface{} { +func getAllLicenseKeys(channelId *big.Int, serviceId string) []any { keys := make([]interface{}, 3) for i, usageType := range []string{REFUND, PLANNED, USED} { keys[i] = LicenseUsageTrackerKey{ChannelID: channelId, ServiceID: serviceId, UsageType: usageType} @@ -127,8 +127,8 @@ func getAllLicenseKeys(channelId *big.Int, serviceId string) []interface{} { return keys } -//this function will be used to read typed data ,convert it in to a business structure -//on which validations can be easily performed and return back the business structure. +// this function will be used to read typed data ,convert it in to a business structure +// on which validations can be easily performed and return back the business structure. func convertTypedDataToLicenseDataUsage(data []storage.TypedKeyValueData) (new *LicenseUsageData, err error) { usageData := &LicenseUsageData{ Planned: &UsageInAmount{Amount: big.NewInt(0), UsageType: PLANNED}, @@ -244,7 +244,7 @@ func updateLicenseUsageData(usageData *LicenseUsageData, key LicenseUsageTracker usageData.Used.SetUsage(oldUsage.Add(oldUsage, usage)) } case PLANNED: - //reset the counter , Planned Amount will be updated ONLY when the License is Purchased or Renewed + //reset the counter, Planned Amount will be updated ONLY when the License is Purchased or Renewed { usageData.Planned.SetUsage(usage) usageData.Used.SetUsage(big.NewInt(0)) diff --git a/license_server/license_storage.go b/license_server/license_storage.go index 546fe089..ba31c41a 100644 --- a/license_server/license_storage.go +++ b/license_server/license_storage.go @@ -55,7 +55,7 @@ func (key *LicenseDetailsKey) String() string { return fmt.Sprintf("{ID:%v/%v}", key.ChannelID, key.ServiceID) } -func serializeLicenseDetailsKey(key interface{}) (serialized string, err error) { +func serializeLicenseDetailsKey(key any) (serialized string, err error) { myKey := key.(LicenseDetailsKey) return myKey.String(), nil } @@ -74,7 +74,7 @@ type LicenseUsageTrackerKey struct { UsageType string } -func serializeLicenseUsageTrackerKey(key interface{}) (serialized string, err error) { +func serializeLicenseUsageTrackerKey(key any) (serialized string, err error) { myKey := key.(LicenseUsageTrackerKey) return myKey.String(), nil } @@ -343,7 +343,7 @@ func NewLicenseDetailsStorage(atomicStorage storage.AtomicStorage) storage.Typed reflect.TypeOf(LicenseDetailsData{})) } -func serializeLicenseDetailsData(value interface{}) (slice string, err error) { +func serializeLicenseDetailsData(value any) (slice string, err error) { var b bytes.Buffer e := gob.NewEncoder(&b) gob.Register(&Subscription{}) @@ -362,7 +362,7 @@ func serializeLicenseDetailsData(value interface{}) (slice string, err error) { slice = string(b.Bytes()) return } -func deserializeLicenseDetailsData(slice string, value interface{}) (err error) { +func deserializeLicenseDetailsData(slice string, value any) (err error) { b := bytes.NewBuffer([]byte(slice)) gob.Register(&Subscription{}) gob.Register(&ValidityPeriod{}) @@ -376,7 +376,7 @@ func deserializeLicenseDetailsData(slice string, value interface{}) (err error) return } -func serializeLicenseTrackerData(value interface{}) (slice string, err error) { +func serializeLicenseTrackerData(value any) (slice string, err error) { var b bytes.Buffer e := gob.NewEncoder(&b) gob.Register(&UsageInCalls{}) @@ -390,7 +390,7 @@ func serializeLicenseTrackerData(value interface{}) (slice string, err error) { return } -func deserializeLicenseTrackerData(slice string, value interface{}) (err error) { +func deserializeLicenseTrackerData(slice string, value any) (err error) { b := bytes.NewBuffer([]byte(slice)) d := gob.NewDecoder(b) gob.Register(&UsageInCalls{}) diff --git a/logger/README.md b/logger/README.md index 73bf138e..4158fffe 100644 --- a/logger/README.md +++ b/logger/README.md @@ -1,146 +1,167 @@ # Logger configuration -```snet-daemon``` uses [logrus](https://github.com/sirupsen/logrus) log +```snet-daemon``` uses [zap](https://github.com/uber-go/zap) log library. Logger configuration is a set of properties started from ```log.``` prefix. If configuration file is formatted using JSON then all logger configuration is one JSON object located in ```log``` field. * **log** - log configuration section - * **level** (default: info) - log level. Possible values are - [logrus](https://github.com/sirupsen/logrus) log levels - * debug - * info - * warn - * error - * fatal - * panic - - * **timezone** (default: UTC) - timezone to format timestamps and log - file names. It should be name of the time.Location, see - [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation). - - * **formatter** - set of properties with ```log.formatter.``` prefix - describes logger formatter configuration. - - * **type** (default: json) - type of the log formatter. Two types are - supported, which correspond to ```logrus``` formatter types, see [logrus - Formatter](https://github.com/sirupsen/logrus#formatters) - * json - * text - - * **timestamp_format** (default: "2006-01-02T15:04:05.999999999Z07:00") - - timestamp format to use in log lines, standard time.Time formats are - supported, see [time.Time.Format](https://golang.org/pkg/time/#Time.Format) - - * **output** - set of properties with ```log.output.``` prefix describes - logger output configuration. - - * **type** (default: file) - type of the logger output. Two types are - supported: - * file - - [file-rotatelogs](https://github.com/lestrrat-go/file-rotatelogs) - output which supports log rotation - * stdout - os.Stdout - - * **file_pattern** (default: ./snet-daemon.%Y%m%d.log) - log file name - which may include date/time patterns in ```strftime (3)``` format. Time - and date in file name are necessary to support log rotation. - - * **current_link** (default: ./snet-daemon.log) - link to the latest log - file. - - * **rotation_time_in_sec** (default: 86400 (1 day)) - number of seconds - before log rotation happens. - - * **max_age_in_sec** (default: 604800 (1 week)) - number of seconds since - last modification time before log file is removed. - - * **rotation_count** (default: 0 (disabled)) - max number of rotation - files. When number of log files becomes greater then oldest log file is - removed. - - * **hooks** (default: []) - list of names of the hooks which will be executed - when message with specified log level appears in log. See [logrus - hooks](https://github.com/sirupsen/logrus#hooks). List contains names of - the hooks and hook configuration can be found by name prefix. Thus for - hook named `````` properties will start from - ```log..``` prefix. - - * **``````** - configuration of log hook with `` name - - * **type** (required) - Type of the hook. this type is used to find actual - hook implementation. Hook types supported: - * mail_auth - [logrus_mail](https://github.com/zbindenren/logrus_mail) - - * **levels** (required) - list of log levels to trigger the hook. - - * **config** (depends on hook implementation) - set of properties with - ```log..config``` prefix are passed to the hook implementation - when it is initialized. This list of properties is hook specific. - -## logrus_mail hook config - -Its configuration should contain all of the properties which are required to -call [NewMailAuthHook method](https://godoc.org/github.com/zbindenren/logrus_mail#NewMailAuthHook) -* application_name -* host -* port -* from -* to -* username -* password - -Resulting log configuration using logrus_mail hook: + * **level** (default: info) - log level. Possible values are: + * debug + * info + * warn + * error + * fatal + * panic + + * **timezone** (default: UTC) - timezone to format timestamps and log + file names. It should be name of the time.Location, see + [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation). + + * **formatter** - set of properties with ```log.formatter.``` prefix + describes logger formatter configuration. + + * **type** (default: json) - type of the log formatter. Two types are + supported, which correspond to ```zap``` formatter types + * json + * text + + * **timestamp_format** (default: "2006-01-02T15:04:05.999999999Z07:00") - + timestamp format to use in log lines, standard time.Time formats are + supported, see [time.Time.Format](https://golang.org/pkg/time/#Time.Format) + + * **output** - set of properties with ```log.output.``` prefix describes + logger output configuration. + + * **type** (default: file) - type of the logger output. Two types are + supported: + * file - + [lumberjack](https://github.com/natefinch/lumberjack) + output which supports log rotation + * stdout - os.Stdout + * stderr - os.Stderr + + * **file_pattern** (default: ./snet-daemon.%Y%m%d.log) - log file name + which may include date/time patterns in ```strftime (3)``` format. Time + and date in file name are necessary to support log rotation. + + * **current_link** (default: ./snet-daemon.log) - link to the latest log + file. + + * **max_size_in_mb** (default: 10 Mb) - max size of current log file in megabytes. + + * **max_age_in_days** (default: 7 days) - number of days since + last modification time before log file is removed. + + * **rotation_count** (default: 0 (disabled)) - max number of rotation + files. When number of log files becomes greater then oldest log file is + removed. + + * **hooks** (optional, default empty) - list of names of the hooks which will be executed + when message with specified log level appears in log. List contains names of + the hooks and hook configuration can be found by name prefix. Thus for + hook named `````` properties will start from + ```log..``` prefix. + + * **``````** - configuration of log hook with `` name + + * **type** (required always) - Type of the hook. This type is used to find actual + hook implementation. Hook types supported: + + 1) `email` + 2) `telegram_bot` + + * **levels** (required always) - list of log levels to trigger the hook. + + Next are the parameters depending on the type of hook: + + #### Email hook configuration + + For hook type `email`. Its configuration should contain all the properties which are required to send email: + + * **host** (required) - host of mail server. + * **port** (required) - port of mail server. + * **from** (required) - the mail from which the logs will be sent. + * **to** (required) - the mail to which the logs will be sent. + * **username** (required) - username is often equal to **from**. + * **password** (required) - password (to send from a Google account, you will need to create the special "app password"). + * **application_name** (optional, default empty) - for smtp auth. + + #### Telegram bot hook configuration + + For hook type `telegram_bot`: + + * **telegram_api_key** (required) - api key of your telegram bot. + * **telegram_chat_id** (required) - the chat id to which the logs will be sent. + * **disable_notification** (optional, default `false`) - if `true`, the bot will send the message silently. + + +## Default logger configuration in JSON format + ```json "log": { - ... - "hooks": [ "send-mail" ], - "send-mail": { - "type": "mail_auth", - "levels": ["Error", "Warn"], - "config": { - "application_name": "test-application-name", - "host": "smtp.gmail.com", - "port": 587, - "from": "from-user@gmail.com", - "to": "to-user@gmail.com", - "username": "smtp-username", - "password": "secret" - } - }, - } +"formatter": { +"timestamp_format": "2006-01-02T15:04:05.999999999Z07:00", +"type": "text" +}, +"level": "info", +"output": { +"current_link": "./snet-daemon.log", +"file_pattern": "./snet-daemon.%Y%m%d.log", +"max_age_in_days": 604800, +"rotation_count": 0, +"max_size_in_mb": 86400, +"type": "file" +}, +"timezone": "UTC" +} ``` -# Default logger configuration in JSON format +## Email hook configuration + ```json "log": { - "formatter": { - "timestamp_format": "2006-01-02T15:04:05.999999999Z07:00", - "type": "text" - }, - "hooks": [], - "level": "info", - "output": { - "current_link": "./snet-daemon.log", - "file_pattern": "./snet-daemon.%Y%m%d.log", - "max_age_in_sec": 604800, - "rotation_count": 0, - "rotation_time_in_sec": 86400, - "type": "file" +... +"hooks": ["send-mail"], +"send-mail": { +"type": "email", +"levels": ["error", "warn", "fatal"], +"config": { +"application_name": "test-application-name", +"host": "smtp.gmail.com", +"port": 587, +"from": "from-user@gmail.com", +"to": "to-user@gmail.com", +"username": "from-user@gmail.com", +"password": "secret" +} +}, +} +``` + +## Telegram bot hook configuration + +``` +"hooks":["tg"], + "tg": { + "telegram_api_key": "7258436601:AAFlAm8gIGIyOTEv7lb9ipHcuB7YTR9-TuR", + "telegram_chat_id": -4103253970, + "disable_notification": false, + "type": "telegram_bot", + "levels": [ + "error", + "panic" + ] }, - "timezone": "UTC" - } ``` -# Adding new hooks implementations +## Adding new hooks implementations -Adding new hook implementation is trivial. You should implement factory method +Adding a new hook implementation is trivial. You should implement factory method which inputs hook configuration as [Viper](https://godoc.org/github.com/spf13/viper#Viper) -config and returns new instance of the Hook structure. Then register new hook -type by calling RegisterHookType() function from init() method. +config and returns new instance of the Hook structure. Then register the new hook +type by calling RegisterHookType() function from init() method. -Please see "mail_auth" hook implementation as example: -* [factory method implementation](https://github.com/singnet/snet-daemon/blob/7b897738b17a21fd105a8a69d4d6841fa5f88dbd/logger/hook.go#L106) -* [registering new hook type](https://github.com/singnet/snet-daemon/blob/7b897738b17a21fd105a8a69d4d6841fa5f88dbd/logger/hook.go#L43) +Please see "email" hook implementation as example in hook.go file diff --git a/logger/hook.go b/logger/hook.go index e4570f9a..27b92eaf 100644 --- a/logger/hook.go +++ b/logger/hook.go @@ -1,123 +1,244 @@ package logger import ( + "bytes" + "context" + "encoding/json" "errors" "fmt" - log "github.com/sirupsen/logrus" + "github.com/singnet/snet-daemon/config" "github.com/spf13/viper" - "github.com/zbindenren/logrus_mail" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "io" + "net/http" + "net/smtp" + "time" ) +var InvalidMailHookConf = errors.New("unable to create instance of mail auth hook: invalid configuration") +var InvalidTelegramBotHookConf = errors.New("unable to create instance of telegram bot hook: invalid configuration") +var NoLevelsSpecifiedError = errors.New("no levels in hook config") + const ( LogHookTypeKey = "type" LogHookLevelsKey = "levels" - LogHookConfigKey = "config" - - LogHookMailApplicationNameKey = "application_name" - LogHookMailHostKey = "host" - LogHookMailPortKey = "port" - LogHookMailFromKey = "from" - LogHookMailToKey = "to" - LogHookMailUsernameKey = "username" - LogHookMailPasswordKey = "password" + LogHooksKey = "log.hooks" + + LogHookMailApplicationNameKey = "application_name" + LogHookMailHostKey = "host" + LogHookMailPortKey = "port" + LogHookMailFromKey = "from" + LogHookMailToKey = "to" + LogHookMailUsernameKey = "username" + LogHookMailPasswordKey = "password" + LogHookTelegramAPIKey = "telegram_api_key" + LogHookTelegramChatID = "telegram_chat_id" + LogHookTelegramDisNotifications = "telegram_disable_notifications" ) -// Hook is a structure to return new log message hooks instances from factory -// method. -type Hook struct { - // Delegate keeps logrus hook pointer to call on message. - Delegate log.Hook - // ExitHandler is a function to be called before terminating application - // when logrus.Fatal() method was called. - ExitHandler func() -} - // RegisterHookType registers new hook type in the system. -func RegisterHookType(hookType string, hookFactoryMethod func(*viper.Viper) (*Hook, error)) { - hookFactoryMethodsByType[hookType] = hookFactoryMethod +func RegisterHookType(hookType string, f func(config *viper.Viper) (hook, error)) { + hookFactoryMethodsByType[hookType] = f } -var hookFactoryMethodsByType = map[string]func(*viper.Viper) (*Hook, error){} +var hookFactoryMethodsByType = map[string]func(config *viper.Viper) (hook, error){} func init() { - RegisterHookType("mail_auth", newMailAuthHook) + RegisterHookType("email", newMailAuthHook) + RegisterHookType("telegram_bot", newTelegramBotHook) } -type internalHook struct { - delegate log.Hook - exitHandler func() - levels []log.Level +type hook interface { + call(entry zapcore.Entry) error +} + +func initHookByConfig(conf *viper.Viper) (hook zap.Option, err error) { + + if conf == nil { + return nil, errors.New("no hook definition") + } + + var hookType = conf.GetString(LogHookTypeKey) + if hookType == "" { + return nil, errors.New("no hook type in hook config") + } + + hookInit, ok := hookFactoryMethodsByType[hookType] + if !ok { + return nil, fmt.Errorf("unexpected hook type: \"%v\"", hookType) + } + + internalHook, err := hookInit(conf) + if err != nil { + return nil, err + } + + if conf.Get(LogHookLevelsKey) == nil { + return nil, NoLevelsSpecifiedError + } + + var levels []zapcore.Level + for _, levelString := range conf.GetStringSlice(LogHookLevelsKey) { + var level zapcore.Level + level, err = getLoggerLevel(levelString) + if err != nil { + return nil, fmt.Errorf("unable parse log level string: \"%v\", err: %v", levelString, err) + } + levels = append(levels, level) + } + + if len(levels) == 0 { + return nil, NoLevelsSpecifiedError + } + + return zap.Hooks(func(entry zapcore.Entry) error { + for _, level := range levels { + if level == entry.Level { + return internalHook.call(entry) + } + } + return nil + }), nil } -func (hook *internalHook) Fire(entry *log.Entry) error { - return hook.delegate.Fire(entry) +type telegramBotHook struct { + ChatID int64 + APIKey string + DisableNotification bool } -func (hook *internalHook) Levels() []log.Level { - return hook.levels +type emailHook struct { + Username string + From string + Password string + To string + Host string + Port int + applicationName string } -func addHookByConfig(logger *log.Logger, config *viper.Viper) error { - var err error - var ok bool +const sendTGMessageURLTemplate = "https://api.telegram.org/bot%s/sendMessage" +// message is JSON payload representation sent to Telegram API. +type telegramMessage struct { + ChatID int64 `json:"chat_id"` + Text string `json:"text"` + DisableNotification bool `json:"disable_notification"` +} + +func newMailAuthHook(config *viper.Viper) (hook, error) { if config == nil { - return errors.New("No hook definition") + return nil, errors.New("unable to create instance of mail auth hook: no config provided") + } + hook := &emailHook{ + applicationName: config.GetString(LogHookMailApplicationNameKey), + From: config.GetString(LogHookMailFromKey), + Host: config.GetString(LogHookMailHostKey), + Port: config.GetInt(LogHookMailPortKey), + Password: config.GetString(LogHookMailPasswordKey), + To: config.GetString(LogHookMailToKey), + Username: config.GetString(LogHookMailUsernameKey), } + if hook.Username == "" { + hook.Username = hook.From + } + if hook.Password == "" || hook.From == "" || hook.Host == "" || hook.To == "" || hook.Port == 0 { + return nil, InvalidMailHookConf + } + return hook, nil +} - var hookType = config.GetString(LogHookTypeKey) - if hookType == "" { - return errors.New("No hook type in hook config") +func newTelegramBotHook(config *viper.Viper) (hook, error) { + if config == nil { + return nil, errors.New("unable to create instance of mail auth hook: no config provided") + } + hook := telegramBotHook{ + ChatID: config.GetInt64(LogHookTelegramChatID), + APIKey: config.GetString(LogHookTelegramAPIKey), + DisableNotification: config.GetBool(LogHookTelegramDisNotifications), } + if hook.ChatID == 0 || hook.APIKey == "" { + return nil, InvalidTelegramBotHookConf + } + return hook, nil +} - var hookFactoryMethod func(*viper.Viper) (*Hook, error) - hookFactoryMethod, ok = hookFactoryMethodsByType[hookType] - if !ok { - return fmt.Errorf("Unexpected hook type: \"%v\"", hookType) +func (t telegramBotHook) call(entry zapcore.Entry) error { + + msg := "⚠️Daemon hook⚠️\r\n" + + "\r\nOrgID: " + config.GetString(config.OrganizationId) + + "\r\nServiceID: " + config.GetString(config.ServiceId) + + "\r\nLog Level: " + entry.Level.String() + + "\r\nUTC Time: " + entry.Time.UTC().String() + + "\r\nTime: " + entry.Time.String() + + "\r\nFullPath: " + entry.Caller.FullPath() + + "\r\nMessage: " + entry.Message + + "\r\nStack: " + entry.Stack + + encoded, err := json.Marshal(telegramMessage{ + ChatID: t.ChatID, + Text: msg, + DisableNotification: t.DisableNotification, + }) + if err != nil { + return err } - var hook *Hook - hook, err = hookFactoryMethod(config.Sub(LogHookConfigKey)) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + request, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf(sendTGMessageURLTemplate, t.APIKey), bytes.NewBuffer(encoded)) if err != nil { - return fmt.Errorf("Cannot create hook instance: %v", err) + return err } - var internalHook = internalHook{delegate: hook.Delegate, exitHandler: hook.ExitHandler} + request.Header.Set("Content-Type", "application/json") - if config.Get(LogHookLevelsKey) == nil { - return errors.New("No levels in hook config") + response, err := http.DefaultClient.Do(request) + if err != nil { + return fmt.Errorf("failed to send HTTP request to Telegram API: %w", err) } - var levels []log.Level - for _, levelString := range config.GetStringSlice(LogHookLevelsKey) { - var level log.Level - level, err = log.ParseLevel(levelString) + + defer func(body io.ReadCloser) { + err := body.Close() if err != nil { - return fmt.Errorf("Unable parse log level string: \"%v\", err: %v", levelString, err) + zap.L().Warn("can't close body", zap.Error(err)) } - levels = append(levels, level) - } - internalHook.levels = levels + }(response.Body) - logger.AddHook(&internalHook) - log.RegisterExitHandler(internalHook.exitHandler) + if response.StatusCode != http.StatusOK { + return fmt.Errorf("response status code is not 200, it is %d", response.StatusCode) + } + if err := response.Body.Close(); err != nil { + return err + } return nil } -func newMailAuthHook(config *viper.Viper) (*Hook, error) { - if config == nil { - return nil, errors.New("Unable to create instance of mail auth hook: no config provided") - } - var mailAuthHook, err = logrus_mail.NewMailAuthHook( - config.GetString(LogHookMailApplicationNameKey), - config.GetString(LogHookMailHostKey), - config.GetInt(LogHookMailPortKey), - config.GetString(LogHookMailFromKey), - config.GetString(LogHookMailToKey), - config.GetString(LogHookMailUsernameKey), - config.GetString(LogHookMailPasswordKey), - ) +func (t emailHook) call(entry zapcore.Entry) error { + // Set up authentication information. + auth := smtp.PlainAuth(t.applicationName, t.Username, t.Password, t.Host) + + // Connect to the server, authenticate, set the sender and recipient, + // and send the email all in one step. + to := []string{t.To} + msg := []byte("To: " + t.To + + "\r\nSubject: Daemon hook!\r\n" + + "\r\nOrgID: " + config.GetString(config.OrganizationId) + + "\r\nServiceID: " + config.GetString(config.ServiceId) + + "\r\nNetwork: " + config.GetString(config.BlockChainNetworkSelected) + + "\r\nDaemon version: " + config.GetVersionTag() + + "\r\nLog level: " + entry.Level.String() + + "\r\nTime UTC: " + entry.Time.UTC().String() + + "\r\nTime: " + entry.Time.String() + + "\r\nFullPath: " + entry.Caller.FullPath() + + "\r\nMessage: " + entry.Message + + "\r\nStack: " + entry.Stack) + + err := smtp.SendMail(fmt.Sprintf("%s:%d", t.Host, t.Port), auth, t.From, to, msg) if err != nil { - return nil, fmt.Errorf("Unable to create instance of mail auth hook: %v", err) + zap.L().Warn("can't send email via hook", zap.Error(err)) } - return &Hook{Delegate: mailAuthHook, ExitHandler: func() {}}, nil + return err } diff --git a/logger/hook_test.go b/logger/hook_test.go index e47d36e7..e6e34b81 100644 --- a/logger/hook_test.go +++ b/logger/hook_test.go @@ -2,256 +2,175 @@ package logger import ( "errors" - log "github.com/sirupsen/logrus" + "github.com/singnet/snet-daemon/config" "github.com/spf13/viper" "github.com/stretchr/testify/assert" - "github.com/zbindenren/logrus_mail" + "go.uber.org/zap/zapcore" + "strconv" "testing" ) func init() { - RegisterHookType("test-hook", testHookFactoryMethod) - RegisterHookType("test-hook-error", testHookFactoryMethodReturnError) + RegisterHookType("test-hook", newTestHook) // for tests only } type testHook struct { config *viper.Viper - log []*log.Entry } -func (hook *testHook) Fire(entry *log.Entry) error { - hook.log = append(hook.log, entry) +func (t testHook) call(entry zapcore.Entry) error { return nil } -func (hook *testHook) Levels() []log.Level { - return nil -} - -func testHookFactoryMethod(config *viper.Viper) (*Hook, error) { - var hook = testHook{config: config} - return &Hook{Delegate: &hook, ExitHandler: func() {}}, nil -} - -func testHookFactoryMethodReturnError(config *viper.Viper) (*Hook, error) { - return nil, errors.New("as expected") -} - -func TestHookFireOnError(t *testing.T) { - const loggerConfigJson = ` - { - "hooks": [ "some-hook" ], - "some-hook": { - "type": "test-hook", - "levels": ["Error"], - "config": { - "test_config_field": "test config value" +func newTestHook(config *viper.Viper) (hook, error) { + if config == nil { + return nil, errors.New("unable to create instance of test hook: no config provided") + } + return &testHook{ + config: config, + }, nil +} + +func TestHooksInitError(t *testing.T) { + + tests := []struct { + hookConf string + wantErr error + }{ + {`{ + "telegram_api_key": "7358436602:xxx", + "telegram_chat_id": -103263970, + "disable_notification": true, + "type": "telegram_bot", + "levels": ["warn","error","panic"]}`, nil}, + {`{ + "telegram_api_key": "7358436602:xxx", + "telegram_chat_id": 0, + "disable_notification": true, + "type": "telegram_bot", + "levels": [ "warn","error","panic" + ]}`, InvalidTelegramBotHookConf}, + {`{"type": "telegram_bot", "levels": ["error"]}`, InvalidTelegramBotHookConf}, + {`{"type": "email", "levels": ["error"]}`, InvalidMailHookConf}, + } + for i, tt := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + _, gotErr := initHookByConfig(config.NewJsonConfigFromString(tt.hookConf)) + if !errors.Is(gotErr, tt.wantErr) { + t.Errorf("initHookByConfig() = %v, want %v", gotErr, tt.wantErr) } - } - }` - var loggerConfig = newConfigFromString(loggerConfigJson, defaultLogConfig) - var logger = log.New() - var err = initLogger(logger, loggerConfig) - assert.Nil(t, err) - - logger.Error("error test") - - assert.Equal(t, 1, len(logger.Hooks[log.ErrorLevel])) - var hook = logger.Hooks[log.ErrorLevel][0].(*internalHook).delegate.(*testHook) - assert.Equal(t, "error test", hook.log[0].Message) - assert.Equal(t, "test config value", hook.config.GetString("test_config_field")) -} - -func TestHookNoFireOnInfo(t *testing.T) { - const loggerConfigJson = ` - { - "hooks": [ "some-hook" ], - "some-hook": { - "type": "test-hook", - "levels": ["Error"], - "config": { } - } - }` - var loggerConfig = newConfigFromString(loggerConfigJson, defaultLogConfig) - var logger = log.New() - var err = initLogger(logger, loggerConfig) - assert.Nil(t, err) - - logger.Info("info test") - - assert.Equal(t, 1, len(logger.Hooks[log.ErrorLevel])) - var hook = logger.Hooks[log.ErrorLevel][0].(*internalHook).delegate.(*testHook) - assert.Equal(t, 0, len(hook.log)) -} - -func TestInitLoggerUnknownHook(t *testing.T) { - const loggerConfigJson = ` - { - "hooks": [ "some-hook" ] - }` - var loggerConfig = newConfigFromString(loggerConfigJson, defaultLogConfig) - var logger = log.New() - - var err = initLogger(logger, loggerConfig) - - assert.Equal(t, errors.New("Unable to add log hook \"some-hook\", error: No hook definition"), err) + }) + } } func TestInitLoggerUnknownHookType(t *testing.T) { const loggerConfigJson = ` - { - "hooks": [ "some-hook" ], - "some-hook": { - "type": "UNKNOWN" - } - }` - var loggerConfig = newConfigFromString(loggerConfigJson, defaultLogConfig) - var logger = log.New() - - var err = initLogger(logger, loggerConfig) - - assert.Equal(t, errors.New("Unable to add log hook \"some-hook\", error: Unexpected hook type: \"UNKNOWN\""), err) -} - -func TestAddHookNoFactoryMethod(t *testing.T) { - const hookConfigJson = ` { "type": "UNKNOWN", - "levels": ["Error"], - "config": { } - }` - var hookConfig = newConfigFromString(hookConfigJson, nil) - var logger = log.New() - - var err = addHookByConfig(logger, hookConfig) - - assert.Equal(t, errors.New("Unexpected hook type: \"UNKNOWN\""), err) -} - -func TestAddHookFactoryMethodReturnsError(t *testing.T) { - const hookConfigJson = ` - { - "type": "test-hook-error", - "levels": ["Error"], - "config": { } + "levels":["error"] }` - var hookConfig = newConfigFromString(hookConfigJson, nil) - var logger = log.New() - - var err = addHookByConfig(logger, hookConfig) - - assert.Equal(t, errors.New("Cannot create hook instance: as expected"), err) + var conf = config.NewJsonConfigFromString(loggerConfigJson) + _, err := initHookByConfig(conf) + assert.Equal(t, errors.New("unexpected hook type: \"UNKNOWN\""), err) } func TestAddHookCannotParseLevels(t *testing.T) { const hookConfigJson = ` { - "type": "test-hook", - "levels": ["Error", "UNKNOWN"], - "config": { } + "type": "telegram_bot", + "levels": ["error", "UNKNOWN"], + "telegram_api_key":"123", + "telegram_chat_id":1 }` - var hookConfig = newConfigFromString(hookConfigJson, nil) - var logger = log.New() - - var err = addHookByConfig(logger, hookConfig) - - assert.Equal(t, errors.New("Unable parse log level string: \"UNKNOWN\", err: not a valid logrus Level: \"UNKNOWN\""), err) + var hookConfig = config.NewJsonConfigFromString(hookConfigJson) + _, err := initHookByConfig(hookConfig) + assert.Equal(t, errors.New("unable parse log level string: \"UNKNOWN\", err: wrong string for level: UNKNOWN. Available options: debug, info, warn, error, panic"), err) } func TestAddHookNoType(t *testing.T) { const hookConfigJson = ` - { - "levels": ["Error", "UNKNOWN"], - "config": { } - }` - var hookConfig = newConfigFromString(hookConfigJson, nil) - var logger = log.New() - - var err = addHookByConfig(logger, hookConfig) - - assert.Equal(t, errors.New("No hook type in hook config"), err) + { + "levels": ["error", "warn"], + "port": 587, + "config": { } + }` + var hookConfig = config.NewJsonConfigFromString(hookConfigJson) + _, err := initHookByConfig(hookConfig) + assert.Equal(t, errors.New("no hook type in hook config"), err) } func TestAddHookNoLevels(t *testing.T) { const hookConfigJson = ` - { - "type": "test-hook", - "config": { } - }` - var hookConfig = newConfigFromString(hookConfigJson, nil) - var logger = log.New() - - var err = addHookByConfig(logger, hookConfig) - - assert.Equal(t, errors.New("No levels in hook config"), err) + { + "type": "test-hook", + "config": { } + }` + var hookConfig = config.NewJsonConfigFromString(hookConfigJson) + _, err := initHookByConfig(hookConfig) + assert.Equal(t, NoLevelsSpecifiedError, err) } func TestAddHookEmptyLevels(t *testing.T) { const hookConfigJson = ` - { - "type": "test-hook", - "levels": [], - "config": { } - }` - var hookConfig = newConfigFromString(hookConfigJson, nil) - var logger = log.New() - - var err = addHookByConfig(logger, hookConfig) - - assert.Nil(t, err) + { + "type": "test-hook", + "levels": [], + "config": { } + }` + var hookConfig = config.NewJsonConfigFromString(hookConfigJson) + _, err := initHookByConfig(hookConfig) + assert.Equal(t, NoLevelsSpecifiedError, err) } -func TestNewMailAuthHook(t *testing.T) { - t.Skip("depends on network") +func TestNewMailHook(t *testing.T) { var err error const mailAuthHookConfigJson = ` - { - "application_name": "test-application-name", - "host": "smtp.gmail.com", - "port": 587, - "from": "from-user@gmail.com", - "to": "to-user@gmail.com", - "username": "smtp-username", - "password": "secret" - }` - var mailAuthHookConfig = newConfigFromString(mailAuthHookConfigJson, nil) - - var hook *Hook - hook, err = newMailAuthHook(mailAuthHookConfig) + { + "application_name": "test-application-name", + "host": "smtp.gmail.com", + "port": 587, + "from": "from-user@gmail.com", + "to": "to-user@gmail.com", + "username": "smtp-username", + "password": "secret" + }` + var mailAuthHookConfig = config.NewJsonConfigFromString(mailAuthHookConfigJson) + hook, err := newMailAuthHook(mailAuthHookConfig) assert.Nil(t, err) + assert.NotNil(t, hook) +} - var expectedHook *logrus_mail.MailAuthHook - expectedHook, err = logrus_mail.NewMailAuthHook( - "test-application-name", - "smtp.gmail.com", - 587, - "from-user@gmail.com", - "to-user@gmail.com", - "smtp-username", - "secret") - assert.Nil(t, err) - assert.Equal(t, hook.Delegate, expectedHook) +func TestNewMailHookInvalidPort(t *testing.T) { + const mailAuthHookConfigJson = ` + { + "application_name": "test-application-name", + "host": "smtp.gmail.com", + "port": "port", + "from": "from-user@gmail.com", + "to": "to-user@gmail.com", + "username": "smtp-username", + "password": "secret" + }` + var mailAuthHookConfig = config.NewJsonConfigFromString(mailAuthHookConfigJson) + _, err := newMailAuthHook(mailAuthHookConfig) + assert.NotNil(t, err) } func TestNewMailAuthHookError(t *testing.T) { - t.Skip("depends on network") const mailAuthHookConfigJson = ` { "application_name": "test-application-name", "host": "smtp.gmail.com", "port": 587 }` - var mailAuthHookConfig = newConfigFromString(mailAuthHookConfigJson, nil) - + var mailAuthHookConfig = config.NewJsonConfigFromString(mailAuthHookConfigJson) var hook, err = newMailAuthHook(mailAuthHookConfig) - - assert.Equal(t, errors.New("Unable to create instance of mail auth hook: mail: no address"), err) + assert.Equal(t, errors.New("unable to create instance of mail auth hook: invalid configuration"), err) assert.Nil(t, hook) } func TestNewMailAuthHookNoConfig(t *testing.T) { var hook, err = newMailAuthHook(nil) - - assert.Equal(t, errors.New("Unable to create instance of mail auth hook: no config provided"), err) + assert.Equal(t, errors.New("unable to create instance of mail auth hook: no config provided"), err) assert.Nil(t, hook) } diff --git a/logger/logger.go b/logger/logger.go index 95388485..9274a7e0 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -1,153 +1,221 @@ package logger import ( + "errors" "fmt" - "github.com/lestrrat-go/file-rotatelogs" - log "github.com/sirupsen/logrus" - "github.com/spf13/viper" - "io" "os" + "slices" + "strings" "time" + + "github.com/singnet/snet-daemon/config" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" ) -// Logger configuration keys const ( - LogLevelKey = "level" - LogTimezoneKey = "timezone" - LogFormatterKey = "formatter" - LogOutputKey = "output" - LogHooksKey = "hooks" - - LogFormatterTypeKey = "type" - LogFormatterTimezoneKey = "timezone" - LogFormatterTimestampFormat = "timestamp_format" - - LogOutputTypeKey = "type" - LogOutputFileFilePatternKey = "file_pattern" - LogOutputFileCurrentLinkKey = "current_link" - LogOutputFileClockTimezoneKey = "clock_timezone" - LogOutputFileRotationTimeInSecKey = "rotation_time_in_sec" - LogOutputFileMaxAgeInSecKey = "max_age_in_sec" - LogOutputFileRotationCountKey = "rotation_count" + LogLevelKey = "log.level" + LogTimezoneKey = "log.timezone" + + LogFormatterTypeKey = "log.formatter.type" + LogTimestampFormatKey = "log.formatter.timestamp_format" + + LogOutputTypeKey = "log.output.type" + LogOutputFilePatternKey = "log.output.file_pattern" + LogOutputCurrentLinkKey = "log.output.current_link" + LogMaxSizeKey = "log.output.max_size_in_mb" + LogMaxAgeKey = "log.output.max_age_in_days" + LogRotationCountKey = "log.output.rotation_count" ) // InitLogger initializes logger using configuration provided by viper // instance. // -// Function designed to configure few different loggers with different +// Function designed to configure a few different loggers with different // formatter and output settings. To achieve this viper configuration // contains separate sections for each logger, each output and // each formatter. -func InitLogger(config *viper.Viper) error { - return initLogger(log.StandardLogger(), config) -} -func initLogger(logger *log.Logger, config *viper.Viper) error { - var err error +func Initialize() { - var level log.Level - var levelString = config.GetString(LogLevelKey) - level, err = log.ParseLevel(levelString) + levelString := config.GetString(LogLevelKey) + level, err := getLoggerLevel(levelString) if err != nil { - return fmt.Errorf("Unable parse log level string: %v, err: %v", levelString, err) + panic(fmt.Errorf("failed to get logger level: %v", err)) } - logger.SetLevel(level) - var timezone = config.GetString(LogTimezoneKey) + encoderConfig, err := createEncoderConfig() + if err != nil { + panic(fmt.Errorf("failed to create encoder config, error: %v", err)) + } - var formatter log.Formatter - var formatterConfig = config.Sub(LogFormatterKey) - formatterConfig.SetDefault(LogFormatterTimezoneKey, timezone) - formatter, err = newFormatterByConfig(formatterConfig) + encoder, err := createEncoder(encoderConfig) if err != nil { - return fmt.Errorf("Unable initialize log formatter, error: %v", err) + panic(fmt.Errorf("failed to get encoder, error: %v", err)) } - logger.SetFormatter(formatter) - var output io.Writer - var outputConfig = config.Sub(LogOutputKey) - outputConfig.SetDefault(LogOutputFileClockTimezoneKey, timezone) - output, err = newOutputByConfig(outputConfig) + writerSyncer, err := createWriterSyncer() if err != nil { - return fmt.Errorf("Unable initialize log output, error: %v", err) + panic(fmt.Errorf("failed to get logger writer, error: %v", err)) } - logger.SetOutput(output) + + core := zapcore.NewCore(encoder, writerSyncer, level) + logger := zap.New(core) + + var hooks []zap.Option for _, hookConfigName := range config.GetStringSlice(LogHooksKey) { - err = addHookByConfig(logger, config.Sub(hookConfigName)) + hook, err := initHookByConfig(config.Vip().Sub(config.LogKey + "." + hookConfigName)) if err != nil { - return fmt.Errorf("Unable to add log hook \"%v\", error: %v", hookConfigName, err) + fmt.Printf("unable to add log hook \"%v\", error: %v", hookConfigName, err) } + hooks = append(hooks, hook) } - logger.Info("Logger initialized") + zap.ReplaceGlobals(logger.WithOptions(hooks...)) - return nil + logger.Info("Logger initialized") } -func newFormatterByConfig(config *viper.Viper) (*timezoneFormatter, error) { - var err error - var formatter = &timezoneFormatter{} - - var timestampFormat = config.GetString(LogFormatterTimestampFormat) - - switch formatterType := config.GetString(LogFormatterTypeKey); formatterType { - case "text": - formatter.delegate = &log.TextFormatter{FullTimestamp: true, TimestampFormat: timestampFormat} - case "json": - formatter.delegate = &log.JSONFormatter{TimestampFormat: timestampFormat} +func getLoggerLevel(levelString string) (zapcore.Level, error) { + switch levelString { + case "debug": + return zap.DebugLevel, nil + case "info": + return zap.InfoLevel, nil + case "warn": + return zap.WarnLevel, nil + case "warning": + return zap.WarnLevel, nil + case "error": + return zap.ErrorLevel, nil + case "fatal": + return zap.FatalLevel, nil + case "panic": + return zap.PanicLevel, nil default: - return nil, fmt.Errorf("Unexpected formatter type: %v", formatterType) + return zapcore.Level(0), fmt.Errorf("wrong string for level: %v. Available options: debug, info, warn, error, panic", levelString) } +} - var location *time.Location - location, err = time.LoadLocation(config.GetString(LogFormatterTimezoneKey)) +func createEncoderConfig() (*zapcore.EncoderConfig, error) { + location, err := getLocationTimezone() if err != nil { return nil, err } - formatter.timestampLocation = location + encoderConfig := zap.NewProductionEncoderConfig() + if config.GetString(LogTimestampFormatKey) != "" { + customTimeFormat := config.GetString(LogTimestampFormatKey) + encoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.In(location).Format(customTimeFormat)) + } + } else { + encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(time.RFC3339) + encoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.In(location).Format(time.RFC3339)) + } + } + encoderConfig.EncodeCaller = zapcore.FullCallerEncoder + encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder - return formatter, nil -} + // colorless logs for files + if slices.Contains(config.GetStringSlice(LogOutputTypeKey), "file") { + encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder + } -type timezoneFormatter struct { - delegate log.Formatter - timestampLocation *time.Location + return &encoderConfig, nil } -func (formatter *timezoneFormatter) Format(entry *log.Entry) ([]byte, error) { - entry.Time = entry.Time.In(formatter.timestampLocation) - return formatter.delegate.Format(entry) +func getLocationTimezone() (location *time.Location, err error) { + timezone := config.GetString(LogTimezoneKey) + location, err = time.LoadLocation(timezone) + return } -func newOutputByConfig(config *viper.Viper) (io.Writer, error) { - var err error +func formatFileName(pattern string, now time.Time) (string, error) { + formatMap := map[string]string{ + "%Y": fmt.Sprintf("%04d", now.Year()), + "%m": fmt.Sprintf("%02d", int(now.Month())), + "%d": fmt.Sprintf("%02d", now.Day()), + "%H": fmt.Sprintf("%02d", now.Hour()), + "%M": fmt.Sprintf("%02d", now.Minute()), + "%S": fmt.Sprintf("%02d", now.Second()), + } - switch outputType := config.GetString(LogOutputTypeKey); outputType { - case "file": + parts := strings.Split(pattern, "%") - var location *time.Location - if location, err = time.LoadLocation(config.GetString(LogOutputFileClockTimezoneKey)); err != nil { - return nil, err + for _, part := range parts[1:] { + if len(part) > 0 && !strings.ContainsAny(part[0:1], "YmdHMS") { + return "", errors.New("invalid placeholder found in pattern: %" + part[0:1]) } + } - var fileWriter io.Writer - fileWriter, err = rotatelogs.New(config.GetString(LogOutputFileFilePatternKey), - rotatelogs.WithLocation(location), - rotatelogs.WithLinkName(config.GetString(LogOutputFileCurrentLinkKey)), - rotatelogs.WithRotationTime(config.GetDuration(LogOutputFileRotationTimeInSecKey)*time.Second), - rotatelogs.WithMaxAge(config.GetDuration(LogOutputFileMaxAgeInSecKey)*time.Second), - rotatelogs.WithRotationCount(uint(config.GetInt(LogOutputFileRotationCountKey))), - ) - if err != nil { - return nil, err - } + for placeholder, value := range formatMap { + pattern = strings.ReplaceAll(pattern, placeholder, value) + } - return fileWriter, nil - case "stdout": - return os.Stdout, nil + return pattern, nil +} + +func createEncoder(encoderConfig *zapcore.EncoderConfig) (zapcore.Encoder, error) { + var encoder zapcore.Encoder + switch config.GetString(LogFormatterTypeKey) { + case "json": + encoder = zapcore.NewJSONEncoder(*encoderConfig) + case "text": + encoder = zapcore.NewConsoleEncoder(*encoderConfig) default: - return nil, fmt.Errorf("Unexpected output type: %v", outputType) + return nil, fmt.Errorf("unsupported log formatter type: %v", config.GetString(LogFormatterTypeKey)) } + return encoder, nil +} + +func createWriterSyncer() (zapcore.WriteSyncer, error) { + var writers []zapcore.WriteSyncer + + configWriters := config.GetStringSlice(LogOutputTypeKey) + + if len(configWriters) == 0 { + return nil, fmt.Errorf("failed to read log.output.type from config: %v", configWriters) + } + + for _, writer := range configWriters { + switch writer { + case "stdout": + writers = append(writers, zapcore.AddSync(os.Stdout)) + case "stderr": + writers = append(writers, zapcore.AddSync(os.Stderr)) + case "file": + fileName, err := formatFileName(config.GetString(LogOutputFilePatternKey), time.Now()) + if err != nil { + return nil, fmt.Errorf("failed to create file writer for logger, %v", err) + } + writers = append(writers, zapcore.AddSync(&lumberjack.Logger{ + Filename: fileName, + MaxSize: config.GetInt(LogMaxSizeKey), + MaxAge: config.GetInt(LogMaxAgeKey), + MaxBackups: config.GetInt(LogRotationCountKey), + Compress: true, + })) + + currentLink := config.GetString(LogOutputCurrentLinkKey) + if currentLink != "" { + if _, err := os.Lstat(currentLink); err == nil { + if err := os.Remove(currentLink); err != nil { + return nil, fmt.Errorf("failed to remove existing symlink: %v", err) + } + } + if err := os.Symlink(fileName, currentLink); err != nil { + return nil, fmt.Errorf("failed to create symlink: %v", err) + } + } + default: + return nil, fmt.Errorf("unsupported log output type: %v", writer) + } + } + + multipleWs := zapcore.NewMultiWriteSyncer(writers...) + return multipleWs, nil } diff --git a/logger/logger_test.go b/logger/logger_test.go index 4e4659e7..78c44b04 100644 --- a/logger/logger_test.go +++ b/logger/logger_test.go @@ -1,60 +1,56 @@ package logger import ( - "bytes" - "encoding/json" - "errors" "fmt" "os" "path/filepath" "testing" "time" - "github.com/jonboulle/clockwork" - "github.com/lestrrat-go/file-rotatelogs" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" "github.com/singnet/snet-daemon/config" ) -const defaultFormatterConfigJSON = ` - { - "type": "json", - "timezone": "UTC" - }` - -const defaultOutputConfigJSON = ` - { - "type": "file", - "file_pattern": "/tmp/snet-daemon.%Y%m%d.log", - "current_link": "/tmp/snet-daemon.log", - "clock_timezone": "UTC", - "rotation_time_in_sec": 86400, - "max_age_in_sec": 604800, - "rotation_count": 0 - }` const defaultLogConfigJSON = ` { "level": "info", "timezone": "UTC", "formatter": { - "type": "json" + "type": "json", + "timestamp_format": "2006-01-02T15:04:05.999999999Z07:00" }, "output": { "type": "file", "file_pattern": "/tmp/snet-daemon.%Y%m%d.log", "current_link": "/tmp/snet-daemon.log", - "rotation_time_in_sec": 86400, - "max_age_in_sec": 604800, + "max_size_in_mb": 86400, + "max_age_in_days": 604800, "rotation_count": 0 } }` -var defaultFormatterConfig = readConfig(defaultFormatterConfigJSON) -var defaultOutputConfig = readConfig(defaultOutputConfigJSON) -var defaultLogConfig = readConfig(defaultLogConfigJSON) +var vip *viper.Viper + +func setupConfig() { + vip = viper.New() + vip.SetEnvPrefix("SNET") + vip.AutomaticEnv() + + defaults := viper.New() + err := config.ReadConfigFromJsonString(defaults, defaultLogConfigJSON) + if err != nil { + panic(fmt.Sprintf("Cannot load default config: %v", err)) + } + config.SetDefaultFromConfig(vip, defaults) + + vip.AddConfigPath(".") + + config.SetVip(vip) +} func TestMain(m *testing.M) { result := m.Run() @@ -65,390 +61,418 @@ func TestMain(m *testing.M) { os.Exit(result) } -func readConfig(configJSON string) *viper.Viper { - var err error - - var vip = viper.New() - err = config.ReadConfigFromJsonString(vip, configJSON) - if err != nil { - panic(fmt.Sprintf("Cannot read test config: %v", err)) - } - - return vip -} - func removeLogFiles(pattern string) { var err error var files []string files, err = filepath.Glob(pattern) if err != nil { - panic(fmt.Sprintf("Cannot find files using pattern: %v", err)) + fmt.Printf("\nWarn:Cannot find files using pattern: %v", err) } for _, file := range files { err = os.Remove(file) if err != nil { - panic(fmt.Sprintf("Cannot remove file: %v, error: %v", file, err)) + fmt.Printf("\nWarn:Cannot remove file: %v, error: %v", file, err) } } } -func newConfigFromString(configString string, defaultVip *viper.Viper) *viper.Viper { - var err error - var configVip = viper.New() - - err = config.ReadConfigFromJsonString(configVip, configString) - if err != nil { - panic(fmt.Sprintf("Cannot read test config: %v", configString)) - } - - if defaultVip != nil { - config.SetDefaultFromConfig(configVip, defaultVip) - } - - return configVip +type testGetLocationTimezone struct { + name string + timezone string + expectedError string } -func TestNewFormatterTextType(t *testing.T) { - var formatterText = `{ - "type": "text", - "timezone": "Local" - }` - var formatterConfig = newConfigFromString(formatterText, nil) +func TestGetLocationTimezone(t *testing.T) { + setupConfig() - var formatter, err = newFormatterByConfig(formatterConfig) + testCases := []testGetLocationTimezone{ + { + name: "Valid timzone", + timezone: "UTC", + }, + { + name: "Invalid timzone", + timezone: "INVALID", + expectedError: "unknown time zone INVALID", + }, + { + name: "Valid timezone", + timezone: "America/New_York", + }, + } - assert.Nil(t, err) - _, isFormatterDelegate := formatter.delegate.(*log.TextFormatter) - assert.True(t, isFormatterDelegate, "Unexpected underlying formatter type, actual: %T, expected: %T", formatter.delegate, &log.TextFormatter{}) - assert.Equal(t, time.Local, formatter.timestampLocation) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + vip.Set(LogTimezoneKey, tc.timezone) + + timezone, err := getLocationTimezone() + + if tc.expectedError != "" { + assert.Error(t, err) + assert.Equal(t, tc.expectedError, err.Error()) + } else { + assert.NoError(t, err) + currentTime := time.Now() + assert.Equal(t, currentTime.Format(tc.timezone), currentTime.Format(timezone.String())) + } + }) + } } -func TestNewFormatterTextTypeTimestampFormat(t *testing.T) { - var formatterText = `{ - "type": "text", - "timezone": "UTC", - "timestamp_format": "2006-01-02T15:04:05.999999999Z07:00" - }` - var formatterConfig = newConfigFromString(formatterText, nil) - - var formatter, err = newFormatterByConfig(formatterConfig) - assert.Nil(t, err) - data, err := formatter.Format(&log.Entry{ - Level: log.InfoLevel, - Time: time.Date(2019, time.February, 5, 16, 29, 13, 123456789, time.UTC), - Message: "test message", - }) - assert.Nil(t, err) - assert.Equal(t, "time=\"2019-02-05T16:29:13.123456789Z\" level=info msg=\"test message\"\n", string(data)) +type encoderConfigTestCase struct { + name string + timeStampFormat string + timezone string + expectedError string } -func TestNewFormatterJsonType(t *testing.T) { - var formatterJSON = `{ - "type": "json", - "timezone": "Local" - }` - var formatterConfig = newConfigFromString(formatterJSON, nil) +func TestCreateEncoderConfig(t *testing.T) { + setupConfig() - var formatter, err = newFormatterByConfig(formatterConfig) - - assert.Nil(t, err) - _, isFormatterDelegate := formatter.delegate.(*log.JSONFormatter) - assert.True(t, isFormatterDelegate, "Unexpected underlying formatter type, actual: %T, expected: %T", formatter.delegate, &log.JSONFormatter{}) - assert.Equal(t, time.Local, formatter.timestampLocation) -} + testCases := []encoderConfigTestCase{ + { + name: "Valid timestamp format", + timeStampFormat: "2006-01-02", + timezone: "UTC", + }, + { + name: "Default timestamp format", + timezone: "UTC", + }, + { + name: "Invalid timezone", + timezone: "INVALID", + expectedError: "unknown time zone INVALID", + }, + { + name: "Invalid timezone", + timezone: "America/New_York", + }, + } -type logLine struct { - Level string - Msg string - Time string + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + vip.Set(LogTimezoneKey, tc.timezone) + if tc.timeStampFormat != "" { + vip.Set(LogTimestampFormatKey, tc.timeStampFormat) + } + + encoderConfig, err := createEncoderConfig() + + if tc.expectedError != "" { + assert.Error(t, err) + assert.Equal(t, tc.expectedError, err.Error()) + } else { + assert.NoError(t, err) + assert.NotNil(t, encoderConfig) + } + }) + } } -func TestNewFormatterJSONTypeTimestampFormat(t *testing.T) { - var formatterJSON = `{ - "type": "json", - "timezone": "UTC", - "timestamp_format": "2006-01-02T15:04:05.999999999Z07:00" - }` - var formatterConfig = newConfigFromString(formatterJSON, nil) - - var formatter, err = newFormatterByConfig(formatterConfig) - assert.Nil(t, err) - buffer, err := formatter.Format(&log.Entry{ - Level: log.InfoLevel, - Time: time.Date(2019, time.February, 5, 16, 29, 13, 123456789, time.UTC), - Message: "test message", - }) - assert.Nil(t, err) - var data = logLine{} - err = json.Unmarshal(buffer, &data) - assert.Nil(t, err) - assert.Equal(t, logLine{ - Level: "info", - Msg: "test message", - Time: "2019-02-05T16:29:13.123456789Z", - }, data) +type loggerEncoderTestCases struct { + name string + formatterType string + expectedError string } -func TestNewFormatterIncorrectType(t *testing.T) { - var formatterJSON = `{ - "type": "UNKNOWN" - }` - var formatterConfig = newConfigFromString(formatterJSON, defaultFormatterConfig) +func TestGetLoggerEncoder(t *testing.T) { + setupConfig() - var _, err = newFormatterByConfig(formatterConfig) + testCases := []loggerEncoderTestCases{ + { + name: "Valid formatter type", + formatterType: "text", + }, + { + name: "Valid formatter type", + formatterType: "json", + }, + { + name: "Invalid formatter type", + formatterType: "invalid", + expectedError: "unsupported log formatter type: invalid", + }, + } - assert.NotNil(t, err) - assert.Equal(t, errors.New("Unexpected formatter type: UNKNOWN"), err) -} + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + vip.Set(LogFormatterTypeKey, tc.formatterType) -func TestNewFormatterIncorrectTimestampTimezone(t *testing.T) { - var formatterJSON = `{ - "timezone": "UNKNOWN..." - }` - var formatterConfig = newConfigFromString(formatterJSON, defaultFormatterConfig) + encoderConfig, err := createEncoderConfig() - var _, err = newFormatterByConfig(formatterConfig) + assert.NoError(t, err) + assert.NotNil(t, encoderConfig) - assert.Equal(t, errors.New("time: invalid location name"), err) -} + encoder, err := createEncoder(encoderConfig) -type underlyingFormatterMock struct { -} + if tc.expectedError != "" { + assert.Error(t, err) + assert.Equal(t, tc.expectedError, err.Error()) -func (f *underlyingFormatterMock) Format(entry *log.Entry) ([]byte, error) { - var buffer *bytes.Buffer = &bytes.Buffer{} - if _, err := buffer.WriteString(entry.Time.Format(time.RFC3339)); err != nil { - return nil, err - } - return buffer.Bytes(), nil -} + } else { + assert.NoError(t, err) + assert.NotNil(t, encoder) + } -func TestTimezoneFormatter(t *testing.T) { - var clockMock clockwork.FakeClock - if japanTimezone, err := time.LoadLocation("Asia/Tokyo"); err == nil { - clockMock = clockwork.NewFakeClockAt(time.Date(1980, time.August, 3, 13, 0, 0, 0, japanTimezone)) - } else { - t.Fatal("Cannot not get Japan timezone", err) + }) } - var formatter = timezoneFormatter{&underlyingFormatterMock{}, time.UTC} - var timestamp = clockMock.Now() - - var formattedTimestamp, err = formatter.Format(&log.Entry{Time: timestamp}) - - assert.Nil(t, err) - assert.Equal(t, timestamp.In(time.UTC).Format(time.RFC3339), string(formattedTimestamp)) } -func TestNewFormatterDefault(t *testing.T) { - var formatterConfig = viper.New() - config.SetDefaultFromConfig(formatterConfig, defaultFormatterConfig) - - var formatter, err = newFormatterByConfig(formatterConfig) - - assert.Nil(t, err) - _, isFormatterDelegate := formatter.delegate.(*log.JSONFormatter) - assert.True(t, isFormatterDelegate, "Unexpected underlying formatter type, actual: %T, expected: %T", formatter.delegate, &log.JSONFormatter{}) - assert.Equal(t, time.UTC, formatter.timestampLocation) -} - -func TestNewOutputFile(t *testing.T) { - var outputConfigJSON = `{ - "type": "file", - "file_pattern": "/tmp/snet-daemon.%Y%m%d.log", - "current_link": "/tmp/snet-daemon.log", - "clock_timezone": "Local", - "rotation_time_in_sec": 86400, - "max_age_in_sec": 604800, - "rotation_count": 0 - }` - var outputConfig = newConfigFromString(outputConfigJSON, nil) - - var writer, err = newOutputByConfig(outputConfig) - - assert.Nil(t, err) - _, isFileWriter := writer.(*rotatelogs.RotateLogs) - assert.True(t, isFileWriter, "Unexpected writer type, actual: %T, expected: %T", writer, &rotatelogs.RotateLogs{}) - // there is no simple way to check that other parameters are applied - // correctly +type logLevelTestCases struct { + name string + inputLevel string + levelZap zapcore.Level + expectedError string } -func TestNewOutputStdout(t *testing.T) { - var outputConfigJSON = `{ - "type": "stdout" - }` - var outputConfig = newConfigFromString(outputConfigJSON, nil) - - var writer, err = newOutputByConfig(outputConfig) +func TestGetLoggerLevel(t *testing.T) { + testCases := []logLevelTestCases{ + { + name: "Valid log level", + inputLevel: "debug", + levelZap: zap.DebugLevel, + }, + { + name: "Valid log level", + inputLevel: "info", + levelZap: zap.InfoLevel, + }, + { + name: "Valid log level", + inputLevel: "warn", + levelZap: zap.WarnLevel, + }, + { + name: "Valid log level", + inputLevel: "error", + levelZap: zap.ErrorLevel, + }, + { + name: "Valid log level", + inputLevel: "panic", + levelZap: zap.PanicLevel, + }, + { + name: "Invalid log level", + inputLevel: "invalid", + expectedError: "wrong string for level: invalid. Available options: debug, info, warn, error, panic", + }, + } - assert.Nil(t, err) - assert.Equal(t, os.Stdout, writer, "Unexpected writer type") + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + logLevel, err := getLoggerLevel(tc.inputLevel) + if tc.expectedError != "" { + assert.Error(t, err) + assert.Equal(t, tc.expectedError, err.Error()) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.levelZap, logLevel) + } + }) + } } -func TestNewOutputIncorrectType(t *testing.T) { - var outputConfigJSON = `{ - "type": "UNKNOWN" - }` - var outputConfig = newConfigFromString(outputConfigJSON, defaultOutputConfig) - - var _, err = newOutputByConfig(outputConfig) - - assert.NotNil(t, err) - assert.Equal(t, errors.New("Unexpected output type: UNKNOWN"), err) +type formatFileNameTestCases struct { + name string + filePatternName string + expectedFileName string + expectedError string } -func TestNewOutputIncorrectClockTimezone(t *testing.T) { - var outputConfigJSON = `{ - "type": "file", - "clock_timezone": "UNKNOWN..." - }` - var outputConfig = newConfigFromString(outputConfigJSON, defaultOutputConfig) +func TestFormatFileName(t *testing.T) { + mockTime := time.Date(2024, 7, 4, 12, 34, 56, 789000000, time.UTC) - var _, err = newOutputByConfig(outputConfig) + testCases := []formatFileNameTestCases{ + { + name: "Valid file pattern name", + filePatternName: "./snet-daemon.%Y-----%m-----%d--%M.log", + expectedFileName: "./snet-daemon.2024-----07-----04--34.log", + }, + { + name: "Invalid file pattern name", + filePatternName: "./snet-daemon.%L-----%E-----%O--%A.log", + expectedError: "invalid placeholder found in pattern: %L", + }, + } - assert.NotNil(t, err) - assert.Equal(t, errors.New("time: invalid location name"), err) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + fileName, err := formatFileName(tc.filePatternName, mockTime) + + if tc.expectedError != "" { + assert.Error(t, err) + assert.Equal(t, tc.expectedError, err.Error()) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expectedFileName, fileName) + } + }) + } } -func TestNewIncorrectFileOutputFilePattern(t *testing.T) { - var outputConfigJSON = `{ - "type": "file", - "file_pattern": "%5" - }` - var outputConfig = newConfigFromString(outputConfigJSON, defaultOutputConfig) - - var _, err = newOutputByConfig(outputConfig) - - assert.NotNil(t, err) +type createWriterSyncerTestCases struct { + name string + outputType any + filePatternName string + expectedError string } -func TestNewOutputDefault(t *testing.T) { - var outputConfig = viper.New() - config.SetDefaultFromConfig(outputConfig, defaultOutputConfig) +func TestCreateWriterSyncer(t *testing.T) { + setupConfig() - var writer, err = newOutputByConfig(outputConfig) - - assert.Nil(t, err) - _, isFileWriter := writer.(*rotatelogs.RotateLogs) - assert.True(t, isFileWriter, "Unexpected writer type, actual: %T, expected: %T", writer, &rotatelogs.RotateLogs{}) -} - -func TestInitLogger(t *testing.T) { - var loggerConfigJSON = ` - { - "level": "error", - "timezone": "Local", - "formatter": { - "type": "json" + testCases := []createWriterSyncerTestCases{ + { + name: "Valid signle output type", + outputType: "file", + filePatternName: "./snet-daemon.%Y%m%d.log", }, - "output": { - "type": "file", - "file_pattern": "/tmp/snet-daemon.%Y%m%d.log", - "current_link": "/tmp/snet-daemon.log", - "rotation_time_in_sec": 86400, - "max_age_in_sec": 604800, - "rotation_count": 0 - } - }` - var loggerConfig = newConfigFromString(loggerConfigJSON, nil) - var logger = log.New() - - var err = initLogger(logger, loggerConfig) - - assert.Nil(t, err) - assert.Equal(t, log.ErrorLevel, logger.Level) - var formatter = logger.Formatter.(*timezoneFormatter) - assert.Equal(t, time.Local, formatter.timestampLocation) - _, isFormatterDelegate := formatter.delegate.(*log.JSONFormatter) - assert.True(t, isFormatterDelegate, "Unexpected underlying formatter type, actual: %T, expected: %T", formatter.delegate, &log.JSONFormatter{}) - _, isFileWriter := logger.Out.(*rotatelogs.RotateLogs) - assert.True(t, isFileWriter, "Unexpected writer type, actual: %T, expected: %T", logger.Out, &rotatelogs.RotateLogs{}) -} - -func TestInitLoggerIncorrectLevel(t *testing.T) { - var loggerConfigJSON = `{ - "level": "UNKNOWN" - }` - var loggerConfig = newConfigFromString(loggerConfigJSON, defaultLogConfig) - - var err = InitLogger(loggerConfig) - - assert.Equal(t, errors.New("Unable parse log level string: UNKNOWN, err: not a valid logrus Level: \"UNKNOWN\""), err, "Unexpected error message message") -} - -func TestInitLoggerIncorrectFormatter(t *testing.T) { - var loggerConfigJSON = `{ - "formatter": { - "type": "UNKNOWN" - } - }` - var loggerConfig = newConfigFromString(loggerConfigJSON, defaultLogConfig) - - var err = InitLogger(loggerConfig) + { + name: "Valid multiple output types", + outputType: []string{"file", "stdout", "stderr"}, + filePatternName: "./snet-daemon.%Y%m%d%M.log", + }, + { + name: "No output types", + outputType: "", + filePatternName: "./snet-daemon.%Y%m%d%M.log", + expectedError: "failed to read log.output.type from config: []", + }, + { + name: "Invalid single output type", + outputType: "invalid", + filePatternName: "./snet-daemon.%Y%m%d%M.log", + expectedError: "unsupported log output type: invalid", + }, + { + name: "Invalid multiple output types", + outputType: []string{"invalid1", "invalid2"}, + filePatternName: "./snet-daemon.%Y%m%d%M.log", + expectedError: "unsupported log output type: invalid1", + }, + { + name: "Invalid file pattern name", + outputType: "file", + filePatternName: "./snet-daemon.%L.log", + expectedError: "failed to create file writer for logger, invalid placeholder found in pattern: %L", + }, + } - assert.Equal(t, errors.New("Unable initialize log formatter, error: Unexpected formatter type: UNKNOWN"), err, "Unexpected error message") + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + vip.Set(LogOutputTypeKey, tc.outputType) + vip.Set(LogOutputFilePatternKey, tc.filePatternName) + ws, err := createWriterSyncer() + + if tc.expectedError != "" { + assert.NotNil(t, err) + assert.Equal(t, tc.expectedError, err.Error()) + } else { + assert.Nil(t, err) + assert.NotNil(t, ws) + } + }) + } } -func TestInitLoggerIncorrectOutput(t *testing.T) { - var loggerConfigJSON = `{ - "output": { - "type": "UNKNOWN" - } - }` - var loggerConfig = newConfigFromString(loggerConfigJSON, defaultLogConfig) - - var err = InitLogger(loggerConfig) - - assert.Equal(t, errors.New("Unable initialize log output, error: Unexpected output type: UNKNOWN"), err, "Unexpected error message") +type configTestCase struct { + name string + config map[string]any + expectPanic bool + expectedLog *zap.Logger } -func TestInitLoggerIncorrectTimezone(t *testing.T) { - var loggerConfigJSON = `{ - "timezone": "UNKNOWN..." - }` - var loggerConfig = newConfigFromString(loggerConfigJSON, defaultLogConfig) - var logger = log.New() - - var err = initLogger(logger, loggerConfig) - - assert.Equal(t, errors.New("Unable initialize log formatter, error: time: invalid location name"), err) -} +func TestInitialize(t *testing.T) { + // Setup default configuration once + setupConfig() + + testCases := []configTestCase{ + { + name: "Valid config", + config: map[string]any{ + "log.level": "info", + "log.timezone": "UTC", + "log.formatter.type": "json", + "log.formatter.timestamp_format": "UTC", + "log.output.type": []string{"file", "stdout"}, + "log.output.file_pattern": "/tmp/snet-daemon.%Y%m%d.log", + "log.output.current_link": "/tmp/snet-daemon.log", + "log.output.max_size_in_mb": 86400, + "log.output.max_age_in_days": 604800, + "log.output.rotation_count": 0, + }, + expectPanic: false, + expectedLog: zap.L(), + }, + { + name: "Invalid config - invalid level", + config: map[string]any{ + "log.level": "INVALID", + "log.timezone": "UTC", + "log.formatter.type": "json", + "log.formatter.timestamp_format": "UTC", + "log.output.type": "file", + "log.output.file_pattern": "/tmp/snet-daemon.%Y%m%d.log", + "log.output.current_link": "/tmp/snet-daemon.log", + "log.output.max_size_in_mb": 86400, + "log.output.max_age_in_days": 604800, + "log.output.rotation_count": 0, + }, + expectPanic: true, + }, + { + name: "Invalid config - invalid formatter type", + config: map[string]any{ + "log.level": "info", + "log.timezone": "UTC", + "log.formatter.type": "INVALID", + "log.formatter.timestamp_format": "UTC", + "log.output.type": "file", + "log.output.file_pattern": "/tmp/snet-daemon.%Y%m%d.log", + "log.output.current_link": "/tmp/snet-daemon.log", + "log.output.max_size_in_mb": 86400, + "log.output.max_age_in_days": 604800, + "log.output.rotation_count": 0, + }, + expectPanic: true, + }, + { + name: "Invalid config - invalid output type", + config: map[string]any{ + "log.level": "info", + "log.timezone": "UTC", + "log.formatter.type": "json", + "log.formatter.timestamp_format": "UTC", + "log.output.type": []string{"INVALID"}, + "log.output.file_pattern": "/tmp/snet-daemon.%Y%m%d.log", + "log.output.current_link": "/tmp/snet-daemon.log", + "log.output.max_size_in_mb": 86400, + "log.output.max_age_in_days": 604800, + "log.output.rotation_count": 0, + }, + expectPanic: true, + }, + } -func TestLogRotation(t *testing.T) { - var err error - var logFileInfo os.FileInfo - var startTime time.Time - - var clockMock = clockwork.NewFakeClockAt( - time.Date(2018, time.September, 26, 13, 0, 0, 0, time.UTC)) - var logWriter, _ = rotatelogs.New( - "/tmp/file-rotatelogs-test.%Y%m%d.log", - rotatelogs.WithClock(clockMock), - rotatelogs.WithRotationTime(24*time.Hour), - rotatelogs.WithMaxAge(7*24*time.Hour), - ) - var logger = log.New() - logger.SetOutput(logWriter) - - // without Add(-time.Second) testStart time is surprisingly after log file - // modification date. Difference is about few milliseconds - startTime = time.Now().Add(-time.Second) - logger.Info("mockedTime: ", clockMock.Now(), " realTime: ", time.Now()) - logFileInfo, err = os.Stat("/tmp/file-rotatelogs-test.20180926.log") - assert.Nil(t, err, "Cannot read log file info") - assert.Truef(t, logFileInfo.ModTime().After(startTime), "Log was not updated, test started at: %v, file updated at: %v", startTime, logFileInfo.ModTime()) - - startTime = time.Now().Add(-time.Second) - clockMock.Advance(10 * time.Hour) - logger.Info("mockedTime: ", clockMock.Now(), " realTime: ", time.Now()) - logFileInfo, err = os.Stat("/tmp/file-rotatelogs-test.20180927.log") - assert.NotNil(t, err, "Log was rotated before correct time") - - startTime = time.Now().Add(-time.Second) - clockMock.Advance(1*time.Hour + 1*time.Second) - logger.Info("mockedTime: ", clockMock.Now(), " realTime: ", time.Now()) - logFileInfo, err = os.Stat("/tmp/file-rotatelogs-test.20180927.log") - assert.Nil(t, err, "Cannot read log file info") - assert.Truef(t, logFileInfo.ModTime().After(startTime), "Log was not updated, test started at: %v, file updated at: %v", startTime, logFileInfo.ModTime()) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Set up the configuration for each test case + for key, value := range tc.config { + vip.Set(key, value) + } + + if tc.expectPanic { + assert.Panics(t, func() { + Initialize() + }, "expected panic but did not get one") + } else { + Initialize() + assert.NotNil(t, zap.L(), "Logger should not be nil") + } + }) + } } diff --git a/metrics/clients.go b/metrics/clients.go index 5c193095..61ee8caf 100644 --- a/metrics/clients.go +++ b/metrics/clients.go @@ -9,13 +9,14 @@ import ( "bytes" "context" "errors" - "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" - "google.golang.org/grpc" - "google.golang.org/grpc/health/grpc_health_v1" "io" "net/http" "time" + + "github.com/singnet/snet-daemon/config" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/health/grpc_health_v1" ) type Response struct { @@ -28,7 +29,7 @@ func callgRPCServiceHeartbeat(serviceUrl string) (grpc_health_v1.HealthCheckResp // Set up a connection to the server. conn, err := grpc.Dial(serviceUrl, grpc.WithInsecure()) if err != nil { - log.WithError(err).Warningf("unable to connect to grpc endpoint: %v", err) + zap.L().Warn("unable to connect to grpc endpoint", zap.Error(err)) return grpc_health_v1.HealthCheckResponse_NOT_SERVING, err } defer conn.Close() @@ -40,7 +41,7 @@ func callgRPCServiceHeartbeat(serviceUrl string) (grpc_health_v1.HealthCheckResp req := grpc_health_v1.HealthCheckRequest{Service: config.GetString(config.ServiceId)} resp, err := client.Check(ctx, &req) if err != nil { - log.WithError(err).Warningf("error in calling the heartbeat service : %v", err) + zap.L().Warn("error in calling the heartbeat service", zap.Error(err)) return grpc_health_v1.HealthCheckResponse_UNKNOWN, err } return resp.Status, nil @@ -50,11 +51,11 @@ func callgRPCServiceHeartbeat(serviceUrl string) (grpc_health_v1.HealthCheckResp func callHTTPServiceHeartbeat(serviceURL string) ([]byte, error) { response, err := http.Get(serviceURL) if err != nil { - log.WithError(err).Infof("the service request failed with an error: %v", err) + zap.L().Info("the service request failed with an error", zap.Error(err)) return nil, err } if response.StatusCode != http.StatusOK { - log.Warningf("wrong status code: %d", response.StatusCode) + zap.L().Warn("wrong status code", zap.Int("StatusCode", response.StatusCode)) return nil, errors.New("unexpected error with the service") } // Read the response @@ -63,7 +64,7 @@ func callHTTPServiceHeartbeat(serviceURL string) ([]byte, error) { if string(serviceHeartbeat) == "" { return nil, errors.New("empty service response") } - log.Infof("response received : %v", serviceHeartbeat) + zap.L().Info("response received", zap.Any("response", serviceHeartbeat)) return serviceHeartbeat, nil } @@ -72,7 +73,7 @@ func callRegisterService(daemonID string, serviceURL string) (status bool) { //Send the Daemon ID and the Network ID to register the Daemon req, err := http.NewRequest("POST", serviceURL, bytes.NewBuffer(buildPayLoadForServiceRegistration())) if err != nil { - log.WithError(err).Infof("unable to create register service request : %v", err) + zap.L().Info("unable to create register service request", zap.Error(err)) return false } req.Header.Set("Content-Type", "application/json") @@ -82,18 +83,18 @@ func callRegisterService(daemonID string, serviceURL string) (status bool) { client := &http.Client{} response, err := client.Do(req) if err != nil { - log.WithError(err).Infof("unable to reach registration service : %v", err) + zap.L().Info("unable to reach registration service", zap.Error(err)) return false } // process the response and set the Authorization token daemonAuthorizationToken, status = getTokenFromResponse(response) - log.Debugf("daemonAuthorizationToken %v", daemonAuthorizationToken) + zap.L().Debug("daemon authorization token", zap.Any("value", daemonAuthorizationToken)) return } func buildPayLoadForServiceRegistration() []byte { payload := &RegisterDaemonPayload{DaemonID: GetDaemonID()} body, _ := ConvertStructToJSON(payload) - log.Debugf("buildPayLoadForServiceRegistration() %v", string(body)) + zap.L().Debug("build payload for service registration", zap.Binary("body", body)) return body } diff --git a/metrics/heartbeat.go b/metrics/heartbeat.go index be2e3843..fbbbbaef 100644 --- a/metrics/heartbeat.go +++ b/metrics/heartbeat.go @@ -11,14 +11,17 @@ import ( "encoding/json" "errors" "fmt" + "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" - "golang.org/x/net/context" - "google.golang.org/grpc/health/grpc_health_v1" + "go.uber.org/zap" + "net/http" "strconv" "strings" "time" + + "golang.org/x/net/context" + "google.golang.org/grpc/health/grpc_health_v1" ) // status enum @@ -91,29 +94,26 @@ func ValidateHeartbeatConfig() error { } func getStorageCertificateDetails() (cert StorageClientCert) { cert = StorageClientCert{} - log.Debug("enabling SSL support via X509 keypair") + zap.L().Debug("enabling SSL support via X509 keypair") certificate, err := tls.LoadX509KeyPair(config.GetString(config.PaymentChannelCertPath), config.GetString(config.PaymentChannelKeyPath)) if err != nil { - log.WithError(fmt.Errorf("unable to load specific SSL X509 keypair for storage certificate %v", err)) + zap.L().Error("unable to load specific SSL X509 keypair for storage certificate", zap.Error(err)) return } if len(certificate.Certificate) > 0 { parseCertificate, err := x509.ParseCertificate(certificate.Certificate[0]) if err != nil { - log.WithError(fmt.Errorf("unable to get certificate infor %v", err)) + zap.L().Error("unable to get certificate infor", zap.Error(err)) return } cert.ValidFrom = fmt.Sprintf("Valid Since: %+v days", parseCertificate.NotBefore.String()) cert.ValidTill = fmt.Sprintf("Valid Till: %+v days", parseCertificate.NotAfter.String()) } - if err != nil { - log.WithError(fmt.Errorf("unable to load specific SSL X509 keypair for storage certificate")) - } return } // prepares the heartbeat, which includes calling to underlying service DAemon is serving -func GetHeartbeat(serviceURL string, serviceType string, serviceID string) (heartbeat DaemonHeartbeat, err error) { +func GetHeartbeat(serviceURL string, serviceType string, serviceID string, trainingInProto bool) (heartbeat DaemonHeartbeat, err error) { heartbeat = DaemonHeartbeat{ GetDaemonID(), strconv.FormatInt(getEpochTime(), 10), @@ -121,7 +121,7 @@ func GetHeartbeat(serviceURL string, serviceType string, serviceID string) (hear "{}", config.GetVersionTag(), config.GetBool(config.ModelTrainingEnabled), - false, // TODO + trainingInProto, config.GetBool(config.BlockchainEnabledKey), config.GetString(config.BlockChainNetworkSelected), getStorageCertificateDetails()} @@ -130,14 +130,14 @@ func GetHeartbeat(serviceURL string, serviceType string, serviceID string) (hear if serviceType == "none" || serviceType == "" || isNoHeartbeatURL { curResp = `{"serviceID":"` + serviceID + `","status":"SERVING"}` } else { - var svcHeartbeat []byte + var serviceHeartbeat []byte if serviceType == "grpc" { var response grpc_health_v1.HealthCheckResponse_ServingStatus response, err = callgRPCServiceHeartbeat(serviceURL) //Standardize this as well on the response being sent heartbeat.Status = response.String() } else if serviceType == "http" || serviceType == "https" { - svcHeartbeat, err = callHTTPServiceHeartbeat(serviceURL) + serviceHeartbeat, err = callHTTPServiceHeartbeat(serviceURL) } if err != nil { heartbeat.Status = Warning.String() @@ -153,8 +153,8 @@ func GetHeartbeat(serviceURL string, serviceType string, serviceID string) (hear } notification.Send() } else { - log.Debugf("Service %s status : %s", serviceURL, svcHeartbeat) - curResp = string(svcHeartbeat) + zap.L().Debug("Get herbeat", zap.String("ServiceUrl", serviceURL), zap.String("Service", string(serviceHeartbeat))) + curResp = string(serviceHeartbeat) } } heartbeat.ServiceHeartbeat = curResp @@ -163,15 +163,15 @@ func GetHeartbeat(serviceURL string, serviceType string, serviceID string) (hear // Heartbeat request handler function : upon request it will hit the service for status and // wraps the results in daemons heartbeat -func HeartbeatHandler(rw http.ResponseWriter, r *http.Request) { +func HeartbeatHandler(rw http.ResponseWriter, trainingInProto bool) { // read the heartbeat service type and corresponding URL serviceType := config.GetString(config.ServiceHeartbeatType) serviceURL := config.GetString(config.HeartbeatServiceEndpoint) serviceID := config.GetString(config.ServiceId) - heartbeat, _ := GetHeartbeat(serviceURL, serviceType, serviceID) + heartbeat, _ := GetHeartbeat(serviceURL, serviceType, serviceID, trainingInProto) err := json.NewEncoder(rw).Encode(heartbeat) if err != nil { - log.WithError(err).Infof("Failed to write heartbeat message.") + zap.L().Info("Failed to write heartbeat message.", zap.Error(err)) } } @@ -179,7 +179,7 @@ func HeartbeatHandler(rw http.ResponseWriter, r *http.Request) { func (service *DaemonHeartbeat) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { heartbeat, err := GetHeartbeat(config.GetString(config.HeartbeatServiceEndpoint), config.GetString(config.ServiceHeartbeatType), - config.GetString(config.ServiceId)) + config.GetString(config.ServiceId), service.TrainingInProto) if strings.Compare(heartbeat.Status, Online.String()) == 0 { return &grpc_health_v1.HealthCheckResponse{Status: grpc_health_v1.HealthCheckResponse_SERVING}, nil diff --git a/metrics/heartbeat_test.go b/metrics/heartbeat_test.go index b76e1b05..96cca508 100644 --- a/metrics/heartbeat_test.go +++ b/metrics/heartbeat_test.go @@ -97,18 +97,22 @@ func (suite *HeartBeatTestSuite) TestHeartbeatHandler() { // Creating a ResponseRecorder to record the response. response := httptest.NewRecorder() - handler := http.HandlerFunc(HeartbeatHandler) + handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + HeartbeatHandler(writer, true) + }) // Since it is basic http handler, we can call ServeHTTP method directly and pass request and response. handler.ServeHTTP(response, request) - //test the responses + // test the responses assert.Equal(suite.T(), http.StatusOK, response.Code, "handler returned wrong status code") - heartbeat, _ := io.ReadAll(response.Body) + heartbeat, err := io.ReadAll(response.Body) + assert.Nil(suite.T(), err) var dHeartbeat DaemonHeartbeat err = json.Unmarshal(heartbeat, &dHeartbeat) assert.False(suite.T(), err != nil) + assert.True(suite.T(), dHeartbeat.TrainingInProto) assert.NotNil(suite.T(), dHeartbeat, "heartbeat must not be nil") assert.Equal(suite.T(), dHeartbeat.Status, Warning.String(), "Invalid State") @@ -127,7 +131,7 @@ func (suite *HeartBeatTestSuite) Test_GetHeartbeat() { serviceType := "http" serviveID := "SERVICE001" - dHeartbeat, _ := GetHeartbeat(serviceURL, serviceType, serviveID) + dHeartbeat, _ := GetHeartbeat(serviceURL, serviceType, serviveID, false) assert.NotNil(suite.T(), dHeartbeat, "heartbeat must not be nil") assert.Equal(suite.T(), dHeartbeat.Status, Online.String(), "Invalid State") @@ -148,7 +152,7 @@ func (suite *HeartBeatTestSuite) Test_GetHeartbeat() { // check with some timeout URL serviceURL = "http://localhost:1234" SetNoHeartbeatURLState(false) - dHeartbeat2, _ := GetHeartbeat(serviceURL, serviceType, serviveID) + dHeartbeat2, _ := GetHeartbeat(serviceURL, serviceType, serviveID, false) assert.NotNil(suite.T(), dHeartbeat2, "heartbeat must not be nil") assert.Equal(suite.T(), dHeartbeat2.Status, Warning.String(), "Invalid State") diff --git a/metrics/Notifications.go b/metrics/notifications.go similarity index 87% rename from metrics/Notifications.go rename to metrics/notifications.go index 2e649fd6..5b294eef 100644 --- a/metrics/Notifications.go +++ b/metrics/notifications.go @@ -7,8 +7,9 @@ package metrics import ( "errors" + "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" ) // state of alerts configuration @@ -29,21 +30,21 @@ type Notification struct { // function for sending an alert to a given endpoint func (alert *Notification) Send() bool { if isNoAlertsConfig { - log.Warningf("notifications not configured") + zap.L().Warn("notifications not configured") return false } serviceURL := config.GetString(config.NotificationServiceEndpoint) // convert the notification struct to json jsonAlert, err := ConvertStructToJSON(alert) - log.Infof("notification : %v", string(jsonAlert)) + zap.L().Info("send notifiction", zap.Any("json", jsonAlert)) if err != nil { - log.WithError(err).Warningf("json conversion error : %v", err) + zap.L().Warn("json conversion error", zap.Error(err)) return false } else { // based on the notification success/failure - status := Publish(jsonAlert, serviceURL,&CommonStats{}) + status := Publish(jsonAlert, serviceURL, &CommonStats{}) if !status { - log.Infof("unable to send notifications") + zap.L().Info("unable to send notifications") return false } } diff --git a/metrics/Notifications_test.go b/metrics/notifications_test.go similarity index 100% rename from metrics/Notifications_test.go rename to metrics/notifications_test.go diff --git a/metrics/register.go b/metrics/register.go index 82bae301..1b998ffd 100644 --- a/metrics/register.go +++ b/metrics/register.go @@ -8,8 +8,9 @@ package metrics import ( "crypto/sha256" "encoding/hex" + "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" ) /* @@ -20,7 +21,7 @@ Post beta, this ID will be used to enable Token based authentication for accessi // generates DaemonID nad returns i.e. DaemonID = HASH (Org Name, Service Name, daemon endpoint) func GetDaemonID() string { - rawID := config.GetString(config.OrganizationId) + config.GetString(config.ServiceId) + daemonGroupId + config.GetRegistryAddress() + rawID := config.GetString(config.OrganizationId) + config.GetString(config.ServiceId) + daemonGroupId + config.GetRegistryAddress() //get hash of the string id combination hasher := sha256.New() hasher.Write([]byte(rawID)) @@ -55,9 +56,9 @@ func RegisterDaemon(serviceURL string) bool { // call the service and get the result status = callRegisterService(daemonID, serviceURL) if !status { - log.Infof("Daemon unable to register with the monitoring service. ") + zap.L().Info("Daemon unable to register with the monitoring service.") } else { - log.Infof("Daemon successfully registered with the monitoring service. ") + zap.L().Info("Daemon successfully registered with the monitoring service.") } return status } diff --git a/metrics/utils.go b/metrics/utils.go index a5a8e27d..f69c5b39 100644 --- a/metrics/utils.go +++ b/metrics/utils.go @@ -6,23 +6,25 @@ import ( b64 "encoding/base64" "encoding/json" "errors" + "io" + "math/big" + "net/http" + "time" + + "github.com/singnet/snet-daemon/authutils" + "github.com/singnet/snet-daemon/config" + "github.com/OneOfOne/go-utils/memory" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/rs/xid" - "github.com/singnet/snet-daemon/authutils" - "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" "google.golang.org/grpc/metadata" - "io/ioutil" - "math/big" - "net/http" - "time" ) const MeteringPrefix = "_usage" -//Get the value of the first Pair +// Get the value of the first Pair func GetValue(md metadata.MD, key string) string { array := md.Get(key) if len(array) == 0 { @@ -31,36 +33,36 @@ func GetValue(md metadata.MD, key string) string { return array[0] } -//convert the given struct to its corresponding json. -func ConvertStructToJSON(payLoad interface{}) ([]byte, error) { - if payLoad == nil { +// convert the given struct to its corresponding json. +func ConvertStructToJSON(payload any) ([]byte, error) { + if payload == nil { return nil, errors.New("empty payload passed") } - b, err := json.Marshal(&payLoad) + b, err := json.Marshal(&payload) if err != nil { - log.WithError(err).Warningf("Json conversion error.") - log.WithField("payLoad", payLoad).Warningf("Unable to derive json from structure passed") + zap.L().Warn("json conversion error.", zap.Error(err)) + zap.L().Warn("unable to derive json from structure passed", zap.Any("payload", payload)) return nil, err } - log.WithField("payload", string(b)).Debug("payload") + zap.L().Debug("success json conversion", zap.Any("payload", payload)) return b, nil } -//Generate a unique global Id +// Generate a unique global Id func GenXid() string { id := xid.New() return id.String() } -//convert the payload to JSON and publish it to the serviceUrl passed -func Publish(payload interface{}, serviceUrl string, commonStats *CommonStats) bool { +// convert the payload to JSON and publish it to the serviceUrl passed +func Publish(payload any, serviceUrl string, commonStats *CommonStats) bool { jsonBytes, err := ConvertStructToJSON(payload) if err != nil { return false } status := publishJson(jsonBytes, serviceUrl, true, commonStats) if !status { - log.WithField("payload", string(jsonBytes)).WithField("url", serviceUrl).Warning("Unable to publish metrics") + zap.L().Warn("Unable to publish metrics", zap.Any("payload", jsonBytes), zap.Any("url", serviceUrl)) } return status } @@ -69,7 +71,7 @@ func Publish(payload interface{}, serviceUrl string, commonStats *CommonStats) b func publishJson(json []byte, serviceURL string, reTry bool, commonStats *CommonStats) bool { response, err := sendRequest(json, serviceURL, commonStats) if err != nil { - log.WithError(err) + zap.L().Error(err.Error()) } else { status, reRegister := checkForSuccessfulResponse(response) if reRegister && reTry { @@ -81,11 +83,11 @@ func publishJson(json []byte, serviceURL string, reTry bool, commonStats *Common return false } -//Set all the headers before publishing +// Set all the headers before publishing func sendRequest(json []byte, serviceURL string, commonStats *CommonStats) (*http.Response, error) { req, err := http.NewRequest("POST", serviceURL, bytes.NewBuffer(json)) if err != nil { - log.WithField("serviceURL", serviceURL).WithError(err).Warningf("Unable to create service request to publish stats") + zap.L().Warn("Unable to create service request to publish stats", zap.Any("serviceURL", serviceURL)) return nil, err } // sending the post request @@ -106,12 +108,12 @@ func SignMessageForMetering(req *http.Request, commonStats *CommonStats) { privateKey, err := getPrivateKeyForMetering() if err != nil { - log.Error(err) + zap.L().Error(err.Error()) return } currentBlock, err := authutils.CurrentBlock() if err != nil { - log.Error(err) + zap.L().Error(err.Error()) return } @@ -132,7 +134,7 @@ func getPrivateKeyForMetering() (privateKey *ecdsa.PrivateKey, err error) { if err != nil { return nil, err } - log.WithField("public key", crypto.PubkeyToAddress(privateKey.PublicKey).String()) + zap.L().Info("Get public key for matering", zap.String("public key", crypto.PubkeyToAddress(privateKey.PublicKey).String())) } return @@ -152,37 +154,37 @@ func signForMeteringValidation(privateKey *ecdsa.PrivateKey, currentBlock *big.I return authutils.GetSignature(message, privateKey) } -//Check if the response received was proper +// Check if the response received was proper func checkForSuccessfulResponse(response *http.Response) (status bool, retry bool) { if response == nil { - log.Warningf("Empty response received.") + zap.L().Warn("Empty response received.") return false, false } if response.StatusCode != http.StatusOK { - log.Warningf("Service call failed with status code : %d ", response.StatusCode) + zap.L().Warn("Service call failed", zap.Int("StatusCode", response.StatusCode)) //if response returned was forbidden error , then re register Daemon with fresh token and submit the request / response //again ONLY if the Daemon was registered successfully return false, false } //close the body - log.Debugf("Metrics posted successfully with status code : %d ", response.StatusCode) + zap.L().Debug("Metrics posted successfully", zap.Int("StatusCode", response.StatusCode)) defer response.Body.Close() return true, false } -//Check if the response received was proper +// Check if the response received was proper func getTokenFromResponse(response *http.Response) (string, bool) { if response == nil { - log.Warningf("Empty response received.") + zap.L().Warn("Empty response received.") return "", false } if response.StatusCode != http.StatusOK { - log.Warningf("Service call failed with status code : %d ", response.StatusCode) + zap.L().Warn("Service call failed", zap.Int("StatusCode", response.StatusCode)) return "", false } - body, err := ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if err != nil { - log.Infof("Unable to retrieve Token from Body , : %s ", err.Error()) + zap.L().Info("Unable to retrieve Token from Body", zap.Error(err)) return "", false } var data TokenGenerated @@ -192,8 +194,8 @@ func getTokenFromResponse(response *http.Response) (string, bool) { return data.Data.Token, true } -//Generic utility to determine the size of the srtuct passed -func GetSize(v interface{}) uint64 { +// Generic utility to determine the size of the srtuct passed +func GetSize(v any) uint64 { return memory.Sizeof(v) } diff --git a/pricing/dynamic_method_pricing.go b/pricing/dynamic_method_pricing.go index 27008563..452673e6 100644 --- a/pricing/dynamic_method_pricing.go +++ b/pricing/dynamic_method_pricing.go @@ -3,19 +3,21 @@ package pricing import ( "fmt" + "math/big" + "net/url" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/codec" "github.com/singnet/snet-daemon/config" "github.com/singnet/snet-daemon/handler" - log "github.com/sirupsen/logrus" + + "go.uber.org/zap" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" - "math/big" - "net/url" ) type DynamicMethodPrice struct { @@ -35,14 +37,14 @@ func (priceType *DynamicMethodPrice) checkForDynamicPricing( derivedContext *handler.GrpcStreamContext) (price *big.Int, e error) { method, ok := grpc.MethodFromServerStream(derivedContext.InStream) - log.WithField("methodNameRetrieved", method) + methodNameField := zap.Any("methodNameRetrieved", method) if !ok { return nil, fmt.Errorf("Unable to get the method Name from the incoming request") } - //todo, get grpc options standardized rather than doing then everytime + //[TODO]: get grpc options standardized rather than doing then everytime passThroughURL, err := url.Parse(config.GetString(config.PassthroughEndpointKey)) if err != nil { - log.WithError(err) + zap.L().Error(err.Error(), methodNameField) return nil, err } options := grpc.WithDefaultCallOptions( @@ -81,11 +83,11 @@ func (priceType *DynamicMethodPrice) getPriceFromPricingMethod(ss grpc.ServerStr if err != nil { return nil, err } - pp := &PriceInCogs{} + priceInCogs := &PriceInCogs{} - if err := proto.Unmarshal(responseMessage.Data, pp); err != nil { + if err := proto.Unmarshal(responseMessage.Data, priceInCogs); err != nil { return nil, err } - log.WithField("dynamic price received", pp.Price) - return big.NewInt(0).SetUint64(pp.Price), nil + zap.L().Info("dynamic price received", zap.Uint64("Price", priceInCogs.Price)) + return big.NewInt(0).SetUint64(priceInCogs.Price), nil } diff --git a/pricing/PriceType.go b/pricing/price_type.go similarity index 100% rename from pricing/PriceType.go rename to pricing/price_type.go diff --git a/pricing/PricingStrategy.go b/pricing/pricing_strategy.go similarity index 82% rename from pricing/PricingStrategy.go rename to pricing/pricing_strategy.go index aea8ee6f..ec593b32 100644 --- a/pricing/PricingStrategy.go +++ b/pricing/pricing_strategy.go @@ -2,12 +2,14 @@ package pricing import ( "fmt" + "math/big" + "strings" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" "github.com/singnet/snet-daemon/handler" - log "github.com/sirupsen/logrus" - "math/big" - "strings" + + "go.uber.org/zap" ) type PricingStrategy struct { @@ -16,18 +18,17 @@ type PricingStrategy struct { serviceMetaData *blockchain.ServiceMetadata } -//Figure out which price type is to be used +// Figure out which price type is to be used func (pricing PricingStrategy) determinePricingApplicable(context *handler.GrpcStreamContext) (priceType PriceType, err error) { - //For future , there could be multiple pricingTypes to select from and this method will help decide which pricing to pick - //but for now , we just have one pricing Type ( either Fixed Price or Fixed price per Method) + //For future, there could be multiple pricingTypes to select from and this method will help decide which pricing to pick + //but for now, we just have one pricing Type ( either Fixed Price or Fixed price per Method) if config.GetBool(config.EnableDynamicPricing) { //Use Dynamic pricing ONLY when you find the mapped price method to be called. if _, ok := pricing.serviceMetaData.GetDynamicPricingMethodAssociated(context.Info.FullMethod); ok { return pricing.pricingTypes[DYNAMIC_PRICING], nil } else { - log.Infof("No Dynamic Price method defined in service proto for the method %v", - context.Info.FullMethod) + zap.L().Info("No Dynamic Price method defined in service proto", zap.String("Method", context.Info.FullMethod)) } } @@ -35,12 +36,12 @@ func (pricing PricingStrategy) determinePricingApplicable(context *handler.GrpcS return pricing.pricingTypes[pricing.serviceMetaData.GetDefaultPricing().PriceModel], nil } -//Initialize all the pricing types +// Initialize all the pricing types func InitPricingStrategy(metadata *blockchain.ServiceMetadata) (*PricingStrategy, error) { pricing := &PricingStrategy{serviceMetaData: metadata} if err := pricing.initFromMetaData(metadata); err != nil { - log.WithError(err) + zap.L().Error(err.Error()) return nil, err } return pricing, nil @@ -62,7 +63,7 @@ func (pricing PricingStrategy) GetPrice(GrpcContext *handler.GrpcStreamContext) } } -//Set all the PricingStrategy Types in this method. +// Set all the PricingStrategy Types in this method. func (pricing *PricingStrategy) initFromMetaData(metadata *blockchain.ServiceMetadata) (err error) { var priceType PriceType @@ -82,7 +83,7 @@ func (pricing *PricingStrategy) initFromMetaData(metadata *blockchain.ServiceMet } if priceType == nil { err = fmt.Errorf("No PricingStrategy strategy defined in Metadata ") - log.WithError(err) + zap.L().Error(err.Error()) } return err diff --git a/pricing/PricingStrategy_test.go b/pricing/pricing_strategy_test.go similarity index 98% rename from pricing/PricingStrategy_test.go rename to pricing/pricing_strategy_test.go index 251e045a..c3d38f59 100644 --- a/pricing/PricingStrategy_test.go +++ b/pricing/pricing_strategy_test.go @@ -7,16 +7,13 @@ import ( "testing" ) - var testJsonData = "{ \"version\": 1, \"display_name\": \"Example1\", \"encoding\": \"grpc\", \"service_type\": \"grpc\", \"payment_expiration_threshold\": 40320, \"model_ipfs_hash\": \"Qmdiq8Hu6dYiwp712GtnbBxagyfYyvUY1HYqkH7iN76UCc\", \"mpe_address\": \"0x7E6366Fbe3bdfCE3C906667911FC5237Cc96BD08\", \"groups\": [ { \"endpoints\": [\"http://34.344.33.1:2379\",\"http://34.344.33.1:2389\"], \"group_id\": \"88ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=\",\"group_name\": \"default_group\", \"pricing\": [ { \"price_model\": \"fixed_price\", \"default\":true, \"price_in_cogs\": 2 }, { \"package_name\": \"example_service\", \"price_model\": \"fixed_price_per_method\", \"details\": [ { \"service_name\": \"Calculator\", \"method_pricing\": [ { \"method_name\": \"add\", \"price_in_cogs\": 2 }, { \"method_name\": \"sub\", \"price_in_cogs\": 1 }, { \"method_name\": \"div\", \"price_in_cogs\": 2 }, { \"method_name\": \"mul\", \"price_in_cogs\": 3 } ] }, { \"service_name\": \"Calculator2\", \"method_pricing\": [ { \"method_name\": \"add\", \"price_in_cogs\": 2 }, { \"method_name\": \"sub\", \"price_in_cogs\": 1 }, { \"method_name\": \"div\", \"price_in_cogs\": 3 }, { \"method_name\": \"mul\", \"price_in_cogs\": 2 } ] } ] }] }, { \"endpoints\": [\"http://97.344.33.1:2379\",\"http://67.344.33.1:2389\"], \"group_name\": \"99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=\", \"group_id\": \"99ybRIg2wAx55mqVsA6sB4S7WxPQHNKqa4BPu/bhj+U=\", \"pricing\": [ { \"package_name\": \"example_service\", \"price_model\": \"fixed_price_per_method\", \"details\": [ { \"service_name\": \"Calculator\", \"method_pricing\": [ { \"method_name\": \"add\", \"price_in_cogs\": 2 }, { \"method_name\": \"sub\", \"price_in_cogs\": 1 }, { \"method_name\": \"div\", \"price_in_cogs\": 2 }, { \"method_name\": \"mul\", \"price_in_cogs\": 3 } ] }, { \"service_name\": \"Calculator2\", \"method_pricing\": [ { \"method_name\": \"add\", \"price_in_cogs\": 2 }, { \"method_name\": \"sub\", \"price_in_cogs\": 1 }, { \"method_name\": \"div\", \"price_in_cogs\": 3 }, { \"method_name\": \"mul\", \"price_in_cogs\": 2 } ] } ] }] } ] } " - func TestPricing_GetPrice(t *testing.T) { metadata, _ := blockchain.InitServiceMetaDataFromJson(testJsonData) - - pricing,err := InitPricingStrategy(metadata); - if pricing != nil { + pricing, err := InitPricingStrategy(metadata) + if pricing != nil { price, err := pricing.GetPrice(nil) assert.Equal(t, price, big.NewInt(2)) @@ -29,5 +26,3 @@ func TestPricing_GetPrice(t *testing.T) { assert.Nil(t,pricing)*/ } - - diff --git a/scripts/build b/scripts/build index dd850302..0ee7f13c 100755 --- a/scripts/build +++ b/scripts/build @@ -6,7 +6,7 @@ PARENT_PATH=$(dirname $(cd $(dirname $0); pwd -P)) if [ $# -lt 3 ] then - echo "arguments expected are of the form and for the build script , as an example: '/scripts/build linux amd64 v.0.1.8'" + echo "arguments expected are of the form and for the build script , as an example: '/scripts/build linux amd64 v5.1.5'" exit 1 fi pushd $PARENT_PATH diff --git a/snetd/cmd/channel.go b/snetd/cmd/channel.go index 99e755b4..e28e9e82 100644 --- a/snetd/cmd/channel.go +++ b/snetd/cmd/channel.go @@ -2,10 +2,11 @@ package cmd import ( "fmt" + "math/big" + "github.com/singnet/snet-daemon/escrow" "github.com/singnet/snet-daemon/storage" "github.com/spf13/cobra" - "math/big" ) // ListChannelsCmd shows list of channels from shared storage @@ -19,7 +20,7 @@ var ChannelCmd = &cobra.Command{ }, } -//Channel command type +// Channel command type type channelCommand struct { storage storage.PrefixedAtomicStorage paymentChannelId *big.Int diff --git a/snetd/cmd/components.go b/snetd/cmd/components.go index ca023a38..393d91bc 100644 --- a/snetd/cmd/components.go +++ b/snetd/cmd/components.go @@ -4,18 +4,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/ethereum/go-ethereum/crypto" - "github.com/grpc-ecosystem/go-grpc-middleware" - "github.com/singnet/snet-daemon/configuration_service" - "github.com/singnet/snet-daemon/metrics" - "github.com/singnet/snet-daemon/pricing" - "github.com/singnet/snet-daemon/storage" - "github.com/singnet/snet-daemon/token" - "github.com/singnet/snet-daemon/training" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "google.golang.org/grpc" "io" "net/http" "os" @@ -23,9 +11,22 @@ import ( "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" + "github.com/singnet/snet-daemon/configuration_service" "github.com/singnet/snet-daemon/escrow" "github.com/singnet/snet-daemon/etcddb" "github.com/singnet/snet-daemon/handler" + "github.com/singnet/snet-daemon/metrics" + "github.com/singnet/snet-daemon/pricing" + "github.com/singnet/snet-daemon/storage" + "github.com/singnet/snet-daemon/token" + "github.com/singnet/snet-daemon/training" + + "github.com/ethereum/go-ethereum/crypto" + grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "go.uber.org/zap" + "google.golang.org/grpc" ) type Components struct { @@ -86,11 +87,11 @@ func loadConfigFileFromCommandLine(configFlag *pflag.Flag) { if configFlag.Changed || isFileExist(configFile) { err := config.LoadConfig(configFile) if err != nil { - log.WithError(err).WithField("configFile", configFile).Panic("Error reading configuration file") + panic(fmt.Errorf("[CONFIG] Error reading configuration file: %v", err)) } - log.WithField("configFile", configFile).Info("Using configuration file") + fmt.Println("[CONFIG] Using custom configuration file") } else { - log.Info("Configuration file is not set, using default configuration") + fmt.Println("[CONFIG] Configuration file is not set, using default configuration") } } @@ -118,7 +119,7 @@ func (components *Components) Blockchain() *blockchain.Processor { processor, err := blockchain.NewProcessor(components.ServiceMetaData()) if err != nil { - log.WithError(err).Panic("unable to initialize blockchain processor") + zap.L().Panic("unable to initialize blockchain processor", zap.Error(err)) } components.blockchain = &processor @@ -148,7 +149,7 @@ func (components *Components) EtcdServer() *etcddb.EtcdServer { enabled, err := etcddb.IsEtcdServerEnabled() if err != nil { - log.WithError(err).Panic("error during etcd config parsing") + zap.L().Panic("error during etcd config parsing", zap.Error(err)) } if !enabled { return nil @@ -156,12 +157,12 @@ func (components *Components) EtcdServer() *etcddb.EtcdServer { server, err := etcddb.GetEtcdServer() if err != nil { - log.WithError(err).Panic("error during etcd config parsing") + zap.L().Panic("error during etcd config parsing", zap.Error(err)) } err = server.Start() if err != nil { - log.WithError(err).Panic("error during etcd server starting") + zap.L().Panic("error during etcd server starting", zap.Error(err)) } components.etcdServer = server @@ -175,7 +176,7 @@ func (components *Components) EtcdClient() *etcddb.EtcdClient { client, err := etcddb.NewEtcdClient(components.OrganizationMetaData()) if err != nil { - log.WithError(err).Panic("unable to create etcd client") + zap.L().Panic("unable to create etcd client", zap.Error(err)) } components.etcdClient = client @@ -360,16 +361,15 @@ func (components *Components) GrpcInterceptor() grpc.StreamServerInterceptor { if components.grpcInterceptor != nil { return components.grpcInterceptor } - //Metering is now mandatory in Daemon + // Metering is now mandatory in Daemon metrics.SetDaemonGrpId(components.OrganizationMetaData().GetGroupIdString()) if components.Blockchain().Enabled() && config.GetBool(config.MeteringEnabled) { meteringUrl := config.GetString(config.MeteringEndPoint) + "/metering/verify" if ok, err := components.verifyAuthenticationSetUpForFreeCall(meteringUrl, components.OrganizationMetaData().GetGroupIdString()); !ok { - log.Error(err) - log.WithError(err).Panic("Metering authentication failed.Please verify the configuration" + - " as part of service publication process") + zap.L().Panic("Metering authentication failed.Please verify the configuration"+ + " as part of service publication process", zap.Error(err)) } components.grpcInterceptor = grpc_middleware.ChainStreamServer( @@ -391,7 +391,7 @@ func (components *Components) verifyAuthenticationSetUpForFreeCall(serviceURL st req, err := http.NewRequest("GET", serviceURL, nil) if err != nil { - log.WithField("serviceURL", serviceURL).WithError(err).Warningf("Unable to create service request to publish stats") + zap.L().Warn("Unable to create service request to publish stats", zap.Any("serviceURL", serviceURL)) return false, err } @@ -406,26 +406,25 @@ func (components *Components) verifyAuthenticationSetUpForFreeCall(serviceURL st response, err := client.Do(req) if err != nil { - log.Error(err) + zap.L().Error(err.Error()) return false, err } return checkResponse(response) - } // Check if the response received was proper func checkResponse(response *http.Response) (allowed bool, err error) { if response == nil { - log.Error("Empty response received.") + zap.L().Error("Empty response received.") return false, fmt.Errorf("Empty response received.") } if response.StatusCode != http.StatusOK { - log.Errorf("Service call failed with status code : %d ", response.StatusCode) + zap.L().Error("Service call failed", zap.Int("StatusCode", response.StatusCode)) return false, fmt.Errorf("Service call failed with status code : %d ", response.StatusCode) } body, err := io.ReadAll(response.Body) if err != nil { - log.Infof("Unable to retrieve calls allowed from Body , : %s ", err.Error()) + zap.L().Info("Unable to retrieve calls allowed from Body", zap.Error(err)) return false, err } var responseBody VerifyMeteringResponse @@ -451,14 +450,14 @@ type VerifyMeteringResponse struct { func (components *Components) GrpcPaymentValidationInterceptor() grpc.StreamServerInterceptor { if !components.Blockchain().Enabled() { if config.GetBool(config.AllowedUserFlag) { - log.Info("Blockchain is disabled And AllowedUserFlag is enabled") + zap.L().Info("Blockchain is disabled And AllowedUserFlag is enabled") return handler.GrpcPaymentValidationInterceptor(components.ServiceMetaData(), components.AllowedUserPaymentHandler()) } - log.Info("Blockchain is disabled: no payment validation") + zap.L().Info("Blockchain is disabled: no payment validation") return handler.NoOpInterceptor } else { - log.Info("Blockchain is enabled: instantiate payment validation interceptor") + zap.L().Info("Blockchain is enabled: instantiate payment validation interceptor") return handler.GrpcPaymentValidationInterceptor(components.ServiceMetaData(), components.EscrowPaymentHandler(), components.FreeCallPaymentHandler(), components.PrePaidPaymentHandler()) } @@ -517,8 +516,15 @@ func (components *Components) DaemonHeartBeat() (service *metrics.DaemonHeartbea if components.daemonHeartbeat != nil { return components.daemonHeartbeat } + metrics.SetDaemonGrpId(components.OrganizationMetaData().GetGroupIdString()) - components.daemonHeartbeat = &metrics.DaemonHeartbeat{DaemonID: metrics.GetDaemonID(), DaemonVersion: config.GetVersionTag()} + + components.daemonHeartbeat = &metrics.DaemonHeartbeat{ + TrainingInProto: len(components.ServiceMetaData().TrainingMethods) > 0, + DaemonID: metrics.GetDaemonID(), + DaemonVersion: config.GetVersionTag(), + } + return components.daemonHeartbeat } diff --git a/snetd/cmd/flags.go b/snetd/cmd/flags.go index 5d88ae19..5d7dd0de 100644 --- a/snetd/cmd/flags.go +++ b/snetd/cmd/flags.go @@ -2,9 +2,8 @@ package cmd import ( "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "os" + "go.uber.org/zap" ) // Command is an CLI command abstraction @@ -121,10 +120,6 @@ func init() { vip.BindPFlag(config.SSLKeyPathKey, serveCmdFlags.Lookup("ssl-key")) cobra.OnInitialize(func() { - - log.SetOutput(os.Stdout) - log.SetLevel(log.InfoLevel) - - log.Info("Cobra initialized") + zap.L().Info("Cobra initialized") }) } diff --git a/snetd/cmd/free_call_users.go b/snetd/cmd/free_call_users.go index 2a1e9326..093c01b6 100644 --- a/snetd/cmd/free_call_users.go +++ b/snetd/cmd/free_call_users.go @@ -28,14 +28,14 @@ var FreeCallUserResetCmd = &cobra.Command{ }, } -//Free call user unlock command +// Free call user unlock command type freeCallUserUnLockCommand struct { lockStorage *storage.PrefixedAtomicStorage userId string orgMetadata *blockchain.OrganizationMetaData } -//Free call user unlock command +// Free call user unlock command type freeCallUserResetCountCommand struct { lockStorage *storage.PrefixedAtomicStorage userStorage *escrow.FreeCallUserStorage diff --git a/snetd/cmd/init.go b/snetd/cmd/init.go index b559e2b3..ef38eb3e 100644 --- a/snetd/cmd/init.go +++ b/snetd/cmd/init.go @@ -1,10 +1,11 @@ package cmd import ( + "fmt" + "os" + "github.com/singnet/snet-daemon/config" - log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "os" ) var InitCmd = &cobra.Command{ @@ -15,16 +16,17 @@ var InitCmd = &cobra.Command{ var err error var configFile = cmd.Flags().Lookup("config").Value.String() - log.WithField("configFile", configFile).Info("Writing default configuration to the file") - if isFileExist(configFile) { - log.WithField("configFile", configFile).Fatal("such configFile already exists, please remove file first or rename file") + fmt.Println("ERROR: such configFile already exists, please remove file first or rename file:", configFile) + os.Exit(-1) } err = os.WriteFile(configFile, []byte(config.MinimumConfigJson), 0666) if err != nil { - log.WithError(err).WithField("configFile", configFile).Fatal("Cannot write configuration") + fmt.Println("ERROR: Cannot write configuration rename file:", configFile) + os.Exit(-1) } + fmt.Println("Writing basic configuration to the file:", configFile) }, } @@ -36,15 +38,17 @@ var InitFullCmd = &cobra.Command{ var err error var configFile = cmd.Flags().Lookup("config").Value.String() - log.WithField("configFile", configFile).Info("Writing full configuration to the file") - if isFileExist(configFile) { - log.WithField("configFile", configFile).Fatal("such configFile already exists, please remove file first or rename file") + fmt.Println("ERROR: such configFile already exists, please remove file first or rename file:", configFile) + os.Exit(-1) } err = config.WriteConfig(configFile) if err != nil { - log.WithError(err).WithField("configFile", configFile).Fatal("Cannot write full configuration") + fmt.Println("ERROR: Cannot write full configuration to file:", configFile) + os.Exit(-1) } + + fmt.Println("Writing full default configuration to the file:", configFile) }, } diff --git a/snetd/cmd/serve.go b/snetd/cmd/serve.go index 971df2d2..e51ddeb4 100644 --- a/snetd/cmd/serve.go +++ b/snetd/cmd/serve.go @@ -3,6 +3,13 @@ package cmd import ( "crypto/tls" "fmt" + "net" + "net/http" + "os" + "os/signal" + "strings" + "syscall" + "github.com/gorilla/handlers" "github.com/improbable-eng/grpc-web/go/grpcweb" "github.com/pkg/errors" @@ -16,19 +23,13 @@ import ( "github.com/singnet/snet-daemon/logger" "github.com/singnet/snet-daemon/metrics" "github.com/singnet/snet-daemon/training" - log "github.com/sirupsen/logrus" "github.com/soheilhy/cmux" "github.com/spf13/cobra" + "go.uber.org/zap" "golang.org/x/crypto/acme/autocert" "golang.org/x/net/http2" "google.golang.org/grpc" "google.golang.org/grpc/health/grpc_health_v1" - "net" - "net/http" - "os" - "os/signal" - "strings" - "syscall" ) var corsOptions = []handlers.CORSOption{ @@ -44,21 +45,19 @@ var ServeCmd = &cobra.Command{ components := InitComponents(cmd) defer components.Close() + logger.Initialize() + config.LogConfig() + etcdServer := components.EtcdServer() - if etcdServer == nil { - log.Info("Etcd server is disabled in the config file.") - } - err = logger.InitLogger(config.SubWithDefault(config.Vip(), config.LogKey)) - if err != nil { - log.WithError(err).Fatal("Unable to initialize logger") + if etcdServer == nil { + zap.L().Info("Etcd server is disabled in the config file.") } - config.LogConfig() var d daemon d, err = newDaemon(components) if err != nil { - log.WithError(err).Fatal("Unable to initialize daemon") + zap.L().Fatal("Unable to initialize daemon", zap.Error(err)) } d.start() @@ -68,7 +67,7 @@ var ServeCmd = &cobra.Command{ signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) <-sigChan - log.Debug("exiting") + zap.L().Debug("Exiting") }, } @@ -135,7 +134,7 @@ func (d *daemon) start() { var tlsConfig *tls.Config if d.autoSSLDomain != "" { - log.Debug("enabling automatic SSL support") + zap.L().Debug("enabling automatic SSL support") certMgr := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(d.autoSSLDomain), @@ -152,13 +151,13 @@ func (d *daemon) start() { GetCertificate: func(c *tls.ClientHelloInfo) (*tls.Certificate, error) { crt, err := certMgr.GetCertificate(c) if err != nil { - log.WithError(err).Error("unable to fetch certificate") + zap.L().Error("unable to fetch certificate", zap.Error(err)) } return crt, err }, } } else if d.sslCert != nil { - log.Debug("enabling SSL support via X509 keypair") + zap.L().Debug("enabling SSL support via X509 keypair") tlsConfig = &tls.Config{ Certificates: []tls.Certificate{*d.sslCert}, } @@ -197,38 +196,34 @@ func (d *daemon) start() { grpcWebServer := grpcweb.WrapServer(d.grpcServer, grpcweb.WithCorsForRegisteredEndpointsOnly(false), grpcweb.WithOriginFunc(func(origin string) bool { return true })) - httpHandler := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - log.Println("httpHandler path: ", req.URL.Path) - log.Printf("input request %#v \n", req) + zap.L().Info("httpHandler path: ", zap.String("path", req.URL.Path)) + zap.L().Info("input request", zap.Any("request", req)) resp.Header().Set("Access-Control-Allow-Origin", "*") if grpcWebServer.IsGrpcWebRequest(req) || grpcWebServer.IsAcceptableGrpcCorsRequest(req) { grpcWebServer.ServeHTTP(resp, req) - log.Println("IsGrpcWebRequest/IsAcceptableGrpcCorsRequest") + zap.L().Info("IsGrpcWebRequest/IsAcceptableGrpcCorsRequest") resp.Header().Set("Access-Control-Allow-Origin", "*") } else { - if strings.Split(req.URL.Path, "/")[1] == "encoding" { - resp.Header().Set("Access-Control-Allow-Origin", "*") + switch strings.Split(req.URL.Path, "/")[1] { + case "encoding": fmt.Fprintln(resp, d.components.ServiceMetaData().GetWireEncoding()) - } else if strings.Split(req.URL.Path, "/")[1] == "heartbeat" { - resp.Header().Set("Access-Control-Allow-Origin", "*") - metrics.HeartbeatHandler(resp, req) - } else { + case "heartbeat": + metrics.HeartbeatHandler(resp, d.components.DaemonHeartBeat().TrainingInProto) + default: http.NotFound(resp, req) } } - log.Println("output headers:") - for key, value := range resp.Header() { - fmt.Printf("%s value is %v\n", key, value) + zap.L().Info("output headers:") + for key, values := range resp.Header() { + zap.L().Info("header", zap.String("key", key), zap.Strings("value", values)) } }) - log.Debug("starting daemon") - corsOpts := cors.New(cors.Options{ - AllowedOrigins: []string{"*"}, //you service is available and allowed for this base url + AllowedOrigins: []string{"*"}, AllowedMethods: []string{ - http.MethodGet, //http methods for your app + http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, @@ -269,10 +264,11 @@ func (d *daemon) start() { go http.Serve(httpL, corsOpts.Handler(httpHandler)) go mux.Serve() } else { - log.Debug("starting simple HTTP daemon") + zap.L().Debug("starting simple HTTP daemon") go http.Serve(d.lis, handlers.CORS(corsOptions...)(httphandler.NewHTTPHandler(d.blockProc))) } + zap.L().Info("✅ Daemon successfully started and ready to accept requests") } func (d *daemon) stop() { diff --git a/snetd/cmd/serve_test.go b/snetd/cmd/serve_test.go index 3ef290dd..55e88974 100644 --- a/snetd/cmd/serve_test.go +++ b/snetd/cmd/serve_test.go @@ -1,11 +1,14 @@ package cmd import ( + "testing" + "github.com/singnet/snet-daemon/config" + _ "github.com/singnet/snet-daemon/fix-proto" "github.com/stretchr/testify/assert" - "testing" ) -//todo + +// TODO func TestDaemonPort(t *testing.T) { -assert.Equal(t,config.GetString(config.DaemonEndPoint),"127.0.0.1:8080") + assert.Equal(t, config.GetString(config.DaemonEndPoint), "127.0.0.1:8080") } diff --git a/snetd/main.go b/snetd/main.go index 3e0ec48e..a770e19a 100644 --- a/snetd/main.go +++ b/snetd/main.go @@ -3,11 +3,11 @@ package main import ( _ "github.com/singnet/snet-daemon/fix-proto" "github.com/singnet/snet-daemon/snetd/cmd" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" ) func main() { if err := cmd.RootCmd.Execute(); err != nil { - log.WithError(err).Fatal("Unable to run application") + zap.L().Fatal("Unable to run application", zap.Error(err)) } } diff --git a/storage/atomic_storage.go b/storage/atomic_storage.go index f535bbdd..e72dc9dc 100644 --- a/storage/atomic_storage.go +++ b/storage/atomic_storage.go @@ -35,7 +35,7 @@ type Transaction interface { GetConditionValues() ([]KeyValueData, error) } -//Best to change this to KeyValueData , will do this in the next commit +// Best to change this to KeyValueData , will do this in the next commit type UpdateFunc func(conditionValues []KeyValueData) (update []KeyValueData, ok bool, err error) type CASRequest struct { @@ -57,7 +57,7 @@ type PrefixedAtomicStorage struct { keyPrefix string } -//It is recommended to use this function to create a PrefixedAtomicStorage +// It is recommended to use this function to create a PrefixedAtomicStorage func NewPrefixedAtomicStorage(atomicStorage AtomicStorage, prefix string) *PrefixedAtomicStorage { return &PrefixedAtomicStorage{ delegate: atomicStorage, @@ -169,18 +169,18 @@ func (storage *PrefixedAtomicStorage) ExecuteTransaction(request CASRequest) (ok // serializes/deserializes values and keys type TypedAtomicStorage interface { // Get returns value by key - Get(key interface{}) (value interface{}, ok bool, err error) + Get(key any) (value any, ok bool, err error) // GetAll returns an array which contains all values from storage - GetAll() (array interface{}, err error) + GetAll() (array any, err error) // Put puts value by key unconditionally - Put(key interface{}, value interface{}) (err error) + Put(key any, value any) (err error) // PutIfAbsent puts value by key if and only if key is absent in storage - PutIfAbsent(key interface{}, value interface{}) (ok bool, err error) + PutIfAbsent(key any, value any) (ok bool, err error) // CompareAndSwap puts newValue by key if and only if previous value is equal // to prevValue - CompareAndSwap(key interface{}, prevValue interface{}, newValue interface{}) (ok bool, err error) + CompareAndSwap(key any, prevValue any, newValue any) (ok bool, err error) // Delete removes value by key - Delete(key interface{}) (err error) + Delete(key any) (err error) ExecuteTransaction(request TypedCASRequest) (ok bool, err error) } @@ -188,34 +188,34 @@ type TypedTransaction interface { GetConditionValues() ([]TypedKeyValueData, error) } -//Best to change this to KeyValueData , will do this in the next commit +// Best to change this to KeyValueData , will do this in the next commit type TypedUpdateFunc func(conditionValues []TypedKeyValueData) (update []TypedKeyValueData, ok bool, err error) type TypedCASRequest struct { RetryTillSuccessOrError bool Update TypedUpdateFunc - ConditionKeys []interface{} //Typed Keys + ConditionKeys []any //Typed Keys } type TypedKeyValueData struct { - Key interface{} - Value interface{} + Key any + Value any Present bool } // TypedAtomicStorageImpl is an implementation of TypedAtomicStorage interface type TypedAtomicStorageImpl struct { atomicStorage AtomicStorage - keySerializer func(key interface{}) (serialized string, err error) + keySerializer func(key any) (serialized string, err error) keyType reflect.Type - valueSerializer func(value interface{}) (serialized string, err error) - valueDeserializer func(serialized string, value interface{}) (err error) + valueSerializer func(value any) (serialized string, err error) + valueDeserializer func(serialized string, value any) (err error) valueType reflect.Type } -func NewTypedAtomicStorageImpl(storage AtomicStorage, keySerializer func(key interface{}) (serialized string, err error), - keyType reflect.Type, valueSerializer func(value interface{}) (serialized string, err error), - valueDeserializer func(serialized string, value interface{}) (err error), +func NewTypedAtomicStorageImpl(storage AtomicStorage, keySerializer func(key any) (serialized string, err error), + keyType reflect.Type, valueSerializer func(value any) (serialized string, err error), + valueDeserializer func(serialized string, value any) (err error), valueType reflect.Type) TypedAtomicStorage { return &TypedAtomicStorageImpl{ @@ -230,7 +230,7 @@ func NewTypedAtomicStorageImpl(storage AtomicStorage, keySerializer func(key int } // Get implements TypedAtomicStorage.Get -func (storage *TypedAtomicStorageImpl) Get(key interface{}) (value interface{}, ok bool, err error) { +func (storage *TypedAtomicStorageImpl) Get(key any) (value any, ok bool, err error) { keyString, err := storage.keySerializer(key) if err != nil { return @@ -252,7 +252,7 @@ func (storage *TypedAtomicStorageImpl) Get(key interface{}) (value interface{}, return value, true, nil } -func (storage *TypedAtomicStorageImpl) deserializeValue(valueString string) (value interface{}, err error) { +func (storage *TypedAtomicStorageImpl) deserializeValue(valueString string) (value any, err error) { value = reflect.New(storage.valueType).Interface() err = storage.valueDeserializer(valueString, value) if err != nil { @@ -261,7 +261,7 @@ func (storage *TypedAtomicStorageImpl) deserializeValue(valueString string) (val return value, err } -func (storage *TypedAtomicStorageImpl) GetAll() (array interface{}, err error) { +func (storage *TypedAtomicStorageImpl) GetAll() (array any, err error) { stringValues, err := storage.atomicStorage.GetByKeyPrefix("") if err != nil { return @@ -284,7 +284,7 @@ func (storage *TypedAtomicStorageImpl) GetAll() (array interface{}, err error) { } // Put implementor TypedAtomicStorage.Put -func (storage *TypedAtomicStorageImpl) Put(key interface{}, value interface{}) (err error) { +func (storage *TypedAtomicStorageImpl) Put(key any, value any) (err error) { keyString, err := storage.keySerializer(key) if err != nil { return @@ -299,7 +299,7 @@ func (storage *TypedAtomicStorageImpl) Put(key interface{}, value interface{}) ( } // PutIfAbsent implements TypedAtomicStorage.PutIfAbsent -func (storage *TypedAtomicStorageImpl) PutIfAbsent(key interface{}, value interface{}) (ok bool, err error) { +func (storage *TypedAtomicStorageImpl) PutIfAbsent(key any, value any) (ok bool, err error) { keyString, err := storage.keySerializer(key) if err != nil { return @@ -314,7 +314,7 @@ func (storage *TypedAtomicStorageImpl) PutIfAbsent(key interface{}, value interf } // CompareAndSwap implements TypedAtomicStorage.CompareAndSwap -func (storage *TypedAtomicStorageImpl) CompareAndSwap(key interface{}, prevValue interface{}, newValue interface{}) (ok bool, err error) { +func (storage *TypedAtomicStorageImpl) CompareAndSwap(key any, prevValue any, newValue any) (ok bool, err error) { keyString, err := storage.keySerializer(key) if err != nil { return @@ -333,7 +333,7 @@ func (storage *TypedAtomicStorageImpl) CompareAndSwap(key interface{}, prevValue return storage.atomicStorage.CompareAndSwap(keyString, prevValueString, newValueString) } -func (storage *TypedAtomicStorageImpl) Delete(key interface{}) (err error) { +func (storage *TypedAtomicStorageImpl) Delete(key any) (err error) { keyString, err := storage.keySerializer(key) if err != nil { return @@ -342,7 +342,7 @@ func (storage *TypedAtomicStorageImpl) Delete(key interface{}) (err error) { return storage.atomicStorage.Delete(keyString) } -func (storage *TypedAtomicStorageImpl) convertKeyValueDataToTyped(conditionKeys []interface{}, keyValueData []KeyValueData) (result []TypedKeyValueData, err error) { +func (storage *TypedAtomicStorageImpl) convertKeyValueDataToTyped(conditionKeys []any, keyValueData []KeyValueData) (result []TypedKeyValueData, err error) { result = make([]TypedKeyValueData, len(conditionKeys)) for i, conditionKey := range conditionKeys { conditionKeyString, err := storage.keySerializer(conditionKey) @@ -405,7 +405,7 @@ func (storage *TypedAtomicStorageImpl) ExecuteTransaction(request TypedCASReques return storage.atomicStorage.ExecuteTransaction(storageRequest) } -func (storage *TypedAtomicStorageImpl) convertTypedKeyToString(typedKeys []interface{}) (stringKeys []string, err error) { +func (storage *TypedAtomicStorageImpl) convertTypedKeyToString(typedKeys []any) (stringKeys []string, err error) { stringKeys = make([]string, len(typedKeys)) for i, key := range typedKeys { stringKeys[i], err = storage.keySerializer(key) diff --git a/token/jwttoken.go b/token/jwttoken.go index 7c2f0056..5a77d0af 100644 --- a/token/jwttoken.go +++ b/token/jwttoken.go @@ -36,7 +36,7 @@ func (service customJWTokenServiceImpl) CreateToken(payLoad PayLoad) (CustomToke func (service customJWTokenServiceImpl) VerifyToken(receivedToken CustomToken, payLoad PayLoad) (err error) { tokenString := fmt.Sprintf("%v", receivedToken) - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method : %v", token.Header["alg"]) } diff --git a/token/token_service_api.go b/token/token_service_api.go index f1fa68a4..c7d59622 100644 --- a/token/token_service_api.go +++ b/token/token_service_api.go @@ -1,7 +1,7 @@ package token -type PayLoad interface{} -type CustomToken interface{} +type PayLoad any +type CustomToken any // Token.Manager interface is an API for creating and verifying tokens type Manager interface { diff --git a/training/service.go b/training/service.go index 4600c76a..aabd8296 100644 --- a/training/service.go +++ b/training/service.go @@ -4,19 +4,21 @@ package training import ( "bytes" "fmt" - "github.com/ethereum/go-ethereum/common/math" + "math/big" + "net/url" + "strings" + "time" + "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" "github.com/singnet/snet-daemon/escrow" "github.com/singnet/snet-daemon/utils" - log "github.com/sirupsen/logrus" + + "github.com/ethereum/go-ethereum/common/math" + "go.uber.org/zap" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" - "math/big" - "net/url" - "strings" - "time" ) const ( @@ -75,7 +77,7 @@ func deferConnection(conn *grpc.ClientConn) { defer func(conn *grpc.ClientConn) { err := conn.Close() if err != nil { - log.WithError(err).Errorf("error in closing Client Connection") + zap.L().Error("error in closing Client Connection", zap.Error(err)) } }(conn) } @@ -86,19 +88,19 @@ func getConnection(endpoint string) (conn *grpc.ClientConn) { passthroughURL, err := url.Parse(endpoint) if err != nil { - log.WithError(err).Panic("error parsing passthrough endpoint") + zap.L().Panic("error parsing passthrough endpoint", zap.Error(err)) } if strings.Compare(passthroughURL.Scheme, "https") == 0 { conn, err = grpc.Dial(passthroughURL.Host, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")), options) if err != nil { - log.WithError(err).Panic("error dialing service") + zap.L().Panic("error dialing service", zap.Error(err)) } } else { conn, err = grpc.Dial(passthroughURL.Host, grpc.WithInsecure(), options) if err != nil { - log.WithError(err).Panic("error dialing service") + zap.L().Panic("error dialing service", zap.Error(err)) } } return @@ -115,9 +117,9 @@ func (service ModelService) createModelDetails(request *CreateModelRequest, resp data = service.getModelDataToCreate(request, response) //store the model details in etcd err = service.storage.Put(key, data) - log.Debug("Putting Model Data....") + zap.L().Debug("Putting Model Data....") if err != nil { - log.WithError(err) + zap.L().Error(err.Error()) return } //for every accessible address in the list , store the user address and all the model Ids associated with it @@ -126,12 +128,12 @@ func (service ModelService) createModelDetails(request *CreateModelRequest, resp userData := service.getModelUserData(key, address) err = service.userStorage.Put(userKey, userData) if err != nil { - log.WithError(err) + zap.L().Error(err.Error()) return } - log.Debug("Putting USER Model Data....") - log.Debug(" USER Model key is:" + userKey.String()) - log.Debug(" USER Model Data is:" + userData.String()) + zap.L().Debug("Putting USER Model Data....") + zap.L().Debug(" USER Model key is:" + userKey.String()) + zap.L().Debug(" USER Model Data is:" + userData.String()) } return } @@ -150,7 +152,7 @@ func (service ModelService) getModelUserData(key *ModelKey, address string) *Mod //Check if there are any model Ids already associated with this user modelIds := make([]string, 0) userKey := getModelUserKey(key, address) - log.Debug(" USER Model key is:" + userKey.String()) + zap.L().Debug(" USER Model key is:" + userKey.String()) data, ok, err := service.userStorage.Get(userKey) if ok && err == nil && data != nil { modelIds = data.ModelIds @@ -242,6 +244,9 @@ func (service ModelService) updateModelDetails(request *UpdateModelRequest, resp data.Description = request.UpdateModelDetails.Description err = service.storage.Put(key, data) + if err != nil { + zap.L().Error("Error in putting data in user storage", zap.Error(err)) + } //get the difference of all the addresses b/w old and new updatedAddresses := difference(oldAddresses, latestAddresses) for _, address := range updatedAddresses { @@ -254,8 +259,9 @@ func (service ModelService) updateModelDetails(request *UpdateModelRequest, resp modelUserData.ModelIds = remove(modelUserData.ModelIds, request.UpdateModelDetails.ModelId) } err = service.userStorage.Put(modelUserKey, modelUserData) - log.WithError(err) - + if err != nil { + zap.L().Error("Error in putting data in storage", zap.Error(err)) + } } } @@ -328,7 +334,7 @@ func (service ModelService) updateModelDetailsWithLatestStatus(request *ModelDet data.Status = response.Status if err = service.storage.Put(key, data); err != nil { - log.WithError(fmt.Errorf("issue with retrieving model data from storage")) + zap.L().Error("issue with retrieving model data from storage") } } return @@ -363,7 +369,7 @@ func (service ModelService) getModelDataForUpdate(request *UpdateModelRequest) ( ok := false if data, ok, err = service.storage.Get(key); err != nil || !ok { - log.WithError(fmt.Errorf("unable to retrieve model %v data from storage", key.ModelId)) + zap.L().Warn("unable to retrieve model data from storage", zap.String("Model Id", key.ModelId), zap.Error(err)) } return } @@ -408,7 +414,11 @@ func (service ModelService) GetAllModels(c context.Context, request *AccessibleM } } } - log.Debugln("models: ", modelDetailsArray) + + for _, model := range modelDetailsArray { + zap.L().Debug("Model", zap.String("Name", model.ModelName)) + } + response = &AccessibleModelsResponse{ ListOfModels: modelDetailsArray, } @@ -452,12 +462,12 @@ func (service ModelService) CreateModel(c context.Context, request *CreateModelR fmt.Errorf("invalid request, no Authorization provided , %v", err) } if err = service.verifySignature(request.Authorization); err != nil { - log.WithError(err) + zap.L().Error(err.Error()) return &ModelDetailsResponse{Status: Status_ERRORED}, fmt.Errorf("unable to create Model: %v", err) } if request.GetModelDetails().GrpcServiceName == "" || request.GetModelDetails().GrpcMethodName == "" { - log.WithError(err) + zap.L().Error("Error in getting grpc service name", zap.Error(err)) return &ModelDetailsResponse{Status: Status_ERRORED}, fmt.Errorf("invalid request, no GrpcServiceName or GrpcMethodName provided , %v", err) } @@ -483,11 +493,11 @@ func (service ModelService) CreateModel(c context.Context, request *CreateModelR } //store the details in etcd - log.Infof("Creating model based on response from CreateModel of training service") + zap.L().Info("Creating model based on response from CreateModel of training service") data, err := service.createModelDetails(request, response) if err != nil { - log.Println(err) + zap.L().Error(err.Error()) return response, fmt.Errorf("issue with storing Model Id in the Daemon Storage %v", err) } response = BuildModelResponseFrom(data, response.Status) @@ -534,7 +544,7 @@ func (service ModelService) UpdateModelAccess(c context.Context, request *Update fmt.Errorf(" Invalid request , no UpdateModelDetails provided , %v", err) } - log.Infof("Updating model based on response from UpdateModel") + zap.L().Info("Updating model based on response from UpdateModel") if data, err := service.updateModelDetails(request, response); err == nil && data != nil { response = BuildModelResponseFrom(data, data.Status) @@ -569,7 +579,7 @@ func (service ModelService) DeleteModel(c context.Context, request *UpdateModelR defer cancel() if conn, client, err := service.getServiceClient(); err == nil { response, err = client.DeleteModel(ctx, request) - log.Infof("Deleting model based on response from DeleteModel") + zap.L().Info("Deleting model based on response from DeleteModel") if data, err := service.deleteModelDetails(request); err == nil && data != nil { response = BuildModelResponseFrom(data, response.Status) } else { @@ -608,13 +618,13 @@ func (service ModelService) GetModelStatus(c context.Context, request *ModelDeta if conn, client, err := service.getServiceClient(); err == nil { response, err = client.GetModelStatus(ctx, request) - log.Println("get model status: ", response) - log.Infof("Updating model status based on response from UpdateModel") + zap.L().Info("Get model status", zap.Any("response", response)) + zap.L().Info("Updating model status based on response from UpdateModel") if data, err := service.updateModelDetailsWithLatestStatus(request, response); err == nil && data != nil { response = BuildModelResponseFrom(data, response.Status) } else { - log.Println(err) + zap.L().Error(err.Error()) return response, fmt.Errorf("issue with storing Model Id in the Daemon Storage %v", err) } diff --git a/training/service_test.go b/training/service_test.go index dae9c26d..f6572213 100644 --- a/training/service_test.go +++ b/training/service_test.go @@ -4,21 +4,23 @@ import ( "bytes" "crypto/ecdsa" "fmt" + "math/big" + "net" + "testing" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/singnet/snet-daemon/blockchain" "github.com/singnet/snet-daemon/config" "github.com/singnet/snet-daemon/storage" - log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + "go.uber.org/zap" "golang.org/x/net/context" "google.golang.org/grpc" - "math/big" - "net" - "testing" - "time" ) var count int = 0 @@ -93,9 +95,9 @@ func (m MockServiceModelGRPCImpl) mustEmbedUnimplementedModelServer() { } func (m MockServiceModelGRPCImpl) CreateModel(context context.Context, request *CreateModelRequest) (*ModelDetailsResponse, error) { - println("In Service CreateModel") + zap.L().Info("In Service CreateModel") count = count + 1 - log.Debug(count) + zap.L().Debug("Count", zap.Int("value", count)) return &ModelDetailsResponse{Status: Status_CREATED, ModelDetails: &ModelDetails{ ModelId: fmt.Sprintf("%d", count), @@ -197,7 +199,7 @@ func (suite *ModelServiceTestSuite) TestModelService_CreateModel() { AddressList: []string{"A1", "A2", "A3"}, }, } - log.Debug(suite.senderAddress.String()) + zap.L().Debug("Sender address", zap.Any("value", suite.senderAddress.String())) ctx, cancel := context.WithTimeout(context.Background(), time.Second*2000) defer cancel() response, err = suite.service.CreateModel(ctx, request) @@ -252,7 +254,7 @@ func (suite *ModelServiceTestSuite) TestModelService_CreateModel() { IsPubliclyAccessible: false, }, } - log.Debug(suite.senderAddress.String()) + zap.L().Debug("Sender address", zap.Any("value", suite.senderAddress.String())) ctx, cancel = context.WithTimeout(context.Background(), time.Second*2000) defer cancel() response, err = suite.service.CreateModel(ctx, request2) @@ -295,7 +297,7 @@ func (suite *ModelServiceTestSuite) TestModelService_GetModelStatus() { CurrentBlock: 1200, }, } - log.Debug(suite.senderAddress.String()) + zap.L().Debug("Sender address", zap.Any("value", suite.senderAddress.String())) ctx, cancel := context.WithTimeout(context.Background(), time.Second*2000) defer cancel() response, err := suite.service.GetModelStatus(ctx, request) @@ -324,9 +326,9 @@ func (suite *ModelServiceTestSuite) TestModelService_UpdateModelAccess() { UserAddress: suite.senderAddress.String(), }) - modata, _, _ := suite.service.(*ModelService).userStorage.Get(userKey) + modelState, _, _ := suite.service.(*ModelService).userStorage.Get(userKey) - log.Debug(modata) + zap.L().Debug("Model state", zap.Any("value", modelState)) // assert.Equal(suite.T(), ok, true) assert.Nil(suite.T(), err) modelData := &ModelData{ @@ -366,7 +368,7 @@ func (suite *ModelServiceTestSuite) TestModelService_UpdateModelAccess() { ModelId: "1", }) - log.Debug(data) + zap.L().Debug("Model data", zap.Any("value", data)) request := &UpdateModelRequest{ UpdateModelDetails: &ModelDetails{ @@ -479,7 +481,7 @@ func (suite *ModelServiceTestSuite) TestModelService_UDeleteModel() { response, err = suite.service.DeleteModel(ctx, request) assert.NotNil(suite.T(), err) - log.Debug(suite.senderAddress.String()) + zap.L().Debug("Sender address", zap.Any("value", suite.senderAddress.String())) //valid signer request.Authorization.SignerAddress = suite.senderAddress.String() request.Authorization.Signature = suite.getSignature("__GetModelStatus", 1200, suite.senderPvtKy) diff --git a/training/storage.go b/training/storage.go index f04e2415..18cad925 100644 --- a/training/storage.go +++ b/training/storage.go @@ -104,7 +104,7 @@ type ModelData struct { UpdatedDate string } -func serializeModelKey(key interface{}) (serialized string, err error) { +func serializeModelKey(key any) (serialized string, err error) { myKey := key.(*ModelKey) return myKey.String(), nil } @@ -137,7 +137,7 @@ func (storage *ModelStorage) CompareAndSwap(key *ModelKey, prevState *ModelData, newState *ModelData) (ok bool, err error) { return storage.delegate.CompareAndSwap(key, prevState, newState) } -func serializeModelUserKey(key interface{}) (serialized string, err error) { +func serializeModelUserKey(key any) (serialized string, err error) { myKey := key.(*ModelUserKey) return myKey.String(), nil } diff --git a/utils/common.go b/utils/common.go index 1f3d68e1..a62c6e7d 100644 --- a/utils/common.go +++ b/utils/common.go @@ -3,13 +3,14 @@ package utils import ( "bytes" "encoding/gob" + "strings" + "github.com/ethereum/go-ethereum/common" "github.com/singnet/snet-daemon/authutils" - log "github.com/sirupsen/logrus" - "strings" + "go.uber.org/zap" ) -func Serialize(value interface{}) (slice string, err error) { +func Serialize(value any) (slice string, err error) { var b bytes.Buffer e := gob.NewEncoder(&b) err = e.Encode(value) @@ -21,16 +22,16 @@ func Serialize(value interface{}) (slice string, err error) { return } -func Deserialize(slice string, value interface{}) (err error) { +func Deserialize(slice string, value any) (err error) { b := bytes.NewBuffer([]byte(slice)) d := gob.NewDecoder(b) - err = d.Decode(value) - return + return d.Decode(value) } + func VerifySigner(message []byte, signature []byte, signer common.Address) error { derivedSigner, err := authutils.GetSignerAddressFromMessage(message, signature) if err != nil { - log.Error(err) + zap.L().Error(err.Error()) return err } if err = authutils.VerifyAddress(*derivedSigner, signer); err != nil {