Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expose train metadata & custom errs #605

Merged
merged 14 commits into from
Dec 27, 2024
Merged
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: download and install
uses: actions/setup-go@v5
with:
go-version: '1.23.1'
go-version: '1.23.4'

- name: install protoc (protobuf)
uses: arduino/setup-protoc@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: download and install
uses: actions/setup-go@v5
with:
go-version: '1.23.1'
go-version: '1.23.4'

- name: install protoc (protobuf)
uses: arduino/setup-protoc@v3
Expand Down
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ Precompiled binaries are published with each release,
download [from releases page](https://github.com/singnet/snet-daemon/releases) or use terminal:

```bash
curl -LJO https://github.com/singnet/snet-daemon/releases/download/v5.1.4/snetd-linux-amd64-v5.1.4
chmod +x snetd-linux-amd64-v5.1.4
curl -LJO https://github.com/singnet/snet-daemon/releases/download/v5.1.6/snetd-linux-amd64-v5.1.6
chmod +x snetd-linux-amd64-v5.1.6
```

#### Generate basic config file

For most users, a simple config is enough:

```bash
./snetd-linux-amd64-v5.1.4 init
./snetd-linux-amd64-v5.1.6 init
```

This command will generate a file `snetd.config.json` in which you will need to
Expand All @@ -49,19 +49,19 @@ change [some parameters](#main_properties).
#### Generate default full config file

```bash
./snetd-linux-amd64-v5.1.4 init-full
./snetd-linux-amd64-v5.1.6 init-full
```

#### Run Daemon

```bash
./snetd-linux-amd64-v5.1.4
./snetd-linux-amd64-v5.1.6
```

Specifying the path to the config using the '-c' argument:

```bash
./snetd-linux-amd64-v5.1.4 -c name_of_config.json
./snetd-linux-amd64-v5.1.6 -c name_of_config.json
```

## Configuration <a name="configuration"></a>
Expand Down Expand Up @@ -288,13 +288,13 @@ end [Example of MPE](https://github.com/singnet/wiki/tree/master/multiPartyEscro
At the moment treasurer server is a part of snet-daemon command line interface.

```bash
./snetd-linux-amd64-v5.1.4 claim --channel-id 0
./snetd-linux-amd64-v5.1.6 claim --channel-id 0
```

**Full list of commands, use --help to get more information:**

```bash
./snetd-linux-amd64-v5.1.4 --help
./snetd-linux-amd64-v5.1.6 --help

Usage:
snetd [flags]
Expand Down Expand Up @@ -363,13 +363,13 @@ part of the build. You need to pass the version as shown in the example below:
Bash:

```bash
./scripts/build linux amd64 v5.1.4
./scripts/build linux amd64 v5.1.6
```

Powershell:

```powershell
./scripts/build.ps1 linux amd64 v5.1.4
./scripts/build.ps1 linux amd64 v5.1.6
```

The final binaries will be in the `/build` folder.
Expand Down
5 changes: 2 additions & 3 deletions authutils/auth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,8 @@ func CurrentBlock() (*big.Int, error) {

// VerifyAddress Check if the payment address/signer passed matches to what is present in the metadata
func VerifyAddress(address common.Address, otherAddress common.Address) error {
isSameAddress := otherAddress == address
if !isSameAddress {
return fmt.Errorf("the Address: %s does not match to what has been expected / registered", blockchain.AddressToHex(&address))
if otherAddress != address {
return fmt.Errorf("the address: %s does not match to what has been expected / registered", blockchain.AddressToHex(&address))
}
return nil
}
Expand Down
7 changes: 7 additions & 0 deletions authutils/auth_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package authutils

import (
"github.com/ethereum/go-ethereum/common"
"math/big"
"testing"
"time"
Expand Down Expand Up @@ -34,3 +35,9 @@ func TestCheckAllowedBlockDifferenceForToken(t *testing.T) {
err = CheckIfTokenHasExpired(currentBlockNum.Add(currentBlockNum, big.NewInt(20)))
assert.Equal(t, nil, err)
}

func TestVerifyAddress(t *testing.T) {
var addr = common.Address(common.FromHex("0x7DF35C98f41F3AF0DF1DC4C7F7D4C19A71DD079F"))
var addrLowCase = common.Address(common.FromHex("0x7df35c98f41f3af0df1dc4c7f7d4c19a71Dd079f"))
assert.Nil(t, VerifyAddress(addr, addrLowCase))
}
2 changes: 2 additions & 0 deletions blockchain/ethereumClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package blockchain
import (
"context"
"encoding/base64"
"go.uber.org/zap"

"github.com/singnet/snet-daemon/v5/config"

Expand Down Expand Up @@ -42,6 +43,7 @@ func CreateHTTPEthereumClient() (*EthereumClient, error) {
config.GetBlockChainHTTPEndPoint(),
rpc.WithHeader("Authorization", "Basic "+basicAuth("", config.GetString(config.BlockchainProviderApiKey))))
if err != nil {
zap.L().Error("Error creating ethereum client", zap.Error(err), zap.String("endpoint", config.GetBlockChainHTTPEndPoint()))
return nil, errors.Wrap(err, "error creating RPC client")
}

Expand Down
67 changes: 31 additions & 36 deletions blockchain/serviceMetadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/singnet/snet-daemon/v5/errs"
"math/big"
"os"
"slices"
"strings"

"github.com/bufbuild/protocompile"
Expand Down Expand Up @@ -164,7 +166,7 @@ type ServiceMetadata struct {
freeCallSignerAddress common.Address
isfreeCallAllowed bool
freeCallsAllowed int
DynamicPriceMethodMapping map[string]string `json:"dynamicpricing"`
DynamicPriceMethodMapping map[string]string `json:"dynamic_pricing"`
TrainingMethods []string `json:"training_methods"`
ProtoFile protoreflect.FileDescriptor `json:"-"`
}
Expand Down Expand Up @@ -252,16 +254,22 @@ func (metaData ServiceMetadata) GetDefaultPricing() Pricing {
func ServiceMetaData() *ServiceMetadata {
var metadata *ServiceMetadata
var err error
if config.GetBool(config.BlockchainEnabledKey) {
ipfsHash := string(getServiceMetaDataUrifromRegistry())
metadata, err = GetServiceMetaDataFromIPFS(ipfsHash)
if err != nil {
zap.L().Panic("error on determining service metadata from file", zap.Error(err))
}
} else {
var ipfsHash []byte
if !config.GetBool(config.BlockchainEnabledKey) {
metadata = &ServiceMetadata{Encoding: "proto", ServiceType: "grpc"}
return metadata
}
ipfsHash, err = getServiceMetaDataURIfromRegistry()
if err != nil {
zap.L().Fatal("error retrieving contract details for the given organization and service ids"+errs.ErrDescURL(errs.InvalidConfig),
zap.String("OrganizationId", config.GetString(config.OrganizationId)),
zap.String("ServiceId", config.GetString(config.ServiceId)))
}
metadata, err = GetServiceMetaDataFromIPFS(string(ipfsHash))
if err != nil {
zap.L().Panic("error on determining service metadata from file"+errs.ErrDescURL(errs.InvalidMetadata), zap.Error(err))
}
zap.L().Debug("service_type: " + metadata.GetServiceType())
zap.L().Debug("service type: " + metadata.GetServiceType())
return metadata
}

Expand Down Expand Up @@ -300,20 +308,18 @@ func GetRegistryFilterer(ethWsClient *ethclient.Client) *RegistryFilterer {
return reg
}

func getServiceMetaDataUrifromRegistry() []byte {
func getServiceMetaDataURIfromRegistry() ([]byte, error) {
reg := getRegistryCaller()

orgId := StringToBytes32(config.GetString(config.OrganizationId))
serviceId := StringToBytes32(config.GetString(config.ServiceId))

serviceRegistration, err := reg.GetServiceRegistrationById(nil, orgId, serviceId)
if err != nil || !serviceRegistration.Found {
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 nil, fmt.Errorf("error retrieving contract details for the given organization and service ids")
}

return serviceRegistration.MetadataURI[:]
return serviceRegistration.MetadataURI[:], nil
}

func GetServiceMetaDataFromIPFS(hash string) (*ServiceMetadata, error) {
Expand Down Expand Up @@ -353,7 +359,7 @@ func InitServiceMetaDataFromJson(jsonData []byte) (*ServiceMetadata, error) {
zap.L().Error(err.Error())
}

zap.L().Debug("Training method", zap.String("json", string(trainingMethodsJson)))
zap.L().Debug("Training methods", zap.String("json", string(trainingMethodsJson)))

return metaData, err
}
Expand Down Expand Up @@ -408,7 +414,7 @@ func setFreeCallData(metaData *ServiceMetadata) error {
metaData.freeCallsAllowed = metaData.defaultGroup.FreeCalls
//If the signer address is not a valid address, then return back an error
if !common.IsHexAddress(metaData.defaultGroup.FreeCallSigner) {
return fmt.Errorf("MetaData does not have 'free_call_signer_address defined correctly")
return fmt.Errorf("MetaData does not have 'free_call_signer_address defined correctly" + errs.ErrDescURL(errs.InvalidMetadata))
}
metaData.freeCallSignerAddress = common.HexToAddress(ToChecksumAddress(metaData.defaultGroup.FreeCallSigner))
}
Expand Down Expand Up @@ -453,10 +459,10 @@ func (metaData *ServiceMetadata) GetLicenses() Licenses {

// methodFullName , ex "/example_service.Calculator/add"
func (metaData *ServiceMetadata) GetDynamicPricingMethodAssociated(methodFullName string) (pricingMethod string, isDynamicPricingEligible bool) {
//Check if Method Level Options are defined , for the given Service and method,
//If Defined check if its in the format supported , then return the full method Name
// Check if Method Level Options are defined, for the given Service and method,
// If Defined check if it's in the format supported, then return the full method Name
// i.e /package.service/method format , this will be directly fed in to the grpc called to made to
//determine dynamic pricing
// determine dynamic pricing
if !config.GetBool(config.EnableDynamicPricing) {
return
}
Expand All @@ -469,23 +475,12 @@ func (metaData *ServiceMetadata) GetDynamicPricingMethodAssociated(methodFullNam
return
}

// methodFullName , ex "/example_service.Calculator/add"
// IsModelTraining methodFullName , ex "/example_service.Calculator/add"
func (metaData *ServiceMetadata) IsModelTraining(methodFullName string) (useModelTrainingEndPoint bool) {

if !config.GetBool(config.ModelTrainingEnabled) {
return false
}
useModelTrainingEndPoint = isElementInArray(methodFullName, metaData.TrainingMethods)
return
}

func isElementInArray(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
return slices.Contains(metaData.TrainingMethods, methodFullName)
}

func setServiceProto(metaData *ServiceMetadata) (err error) {
Expand All @@ -495,7 +490,7 @@ func setServiceProto(metaData *ServiceMetadata) (err error) {

// for backwards compatibility
if metaData.ModelIpfsHash != "" {
rawFile, err = ipfsutils.GetIpfsFile(metaData.ServiceApiSource)
rawFile, err = ipfsutils.GetIpfsFile(metaData.ModelIpfsHash)
}

if metaData.ServiceApiSource != "" {
Expand All @@ -520,7 +515,7 @@ func setServiceProto(metaData *ServiceMetadata) (err error) {

// 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
if config.GetBool(config.EnableDynamicPricing) {
if config.GetBool(config.EnableDynamicPricing) || config.GetBool(config.ModelTrainingEnabled) {
if srvProto, err := parseServiceProto(file); err != nil {
return err
} else {
Expand Down Expand Up @@ -594,8 +589,8 @@ func getFileDescriptor(protoContent string) protoreflect.FileDescriptor {
SourceInfoMode: protocompile.SourceInfoStandard,
}
fds, err := compiler.Compile(context.Background(), serviceProto)
if err != nil {
zap.L().Error(err.Error())
if err != nil || fds == nil {
zap.L().Fatal("failed to analyze protofile"+errs.ErrDescURL(errs.InvalidProto), zap.Error(err))
}
return fds.FindFileByPath(serviceProto)
}
17 changes: 10 additions & 7 deletions blockchain/serviceMetadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package blockchain
import (
"fmt"
"math/big"
"slices"
"strings"
"testing"

Expand Down Expand Up @@ -32,7 +33,6 @@ func TestAllGetterMethods(t *testing.T) {
assert.True(t, metaData.IsFreeCallAllowed())
assert.Equal(t, 12, metaData.GetFreeCallsAllowed())
assert.Equal(t, metaData.GetLicenses().Subscriptions.Type, "Subscription")

}

func TestSubscription(t *testing.T) {
Expand All @@ -58,6 +58,7 @@ func TestTiers(t *testing.T) {
assert.Equal(t, metaData.GetLicenses().Tiers[0].Range[0].DiscountInPercentage,
1.0)
}

func TestInitServiceMetaDataFromJson(t *testing.T) {
//Parse Bad JSON
_, err := InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "{", "", 1)))
Expand All @@ -68,7 +69,7 @@ func TestInitServiceMetaDataFromJson(t *testing.T) {
//Parse Bad JSON
_, err = InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "0x7DF35C98f41F3Af0df1dc4c7F7D4C19a71Dd059F", "", 1)))
if err != nil {
assert.Equal(t, err.Error(), "MetaData does not have 'free_call_signer_address defined correctly")
assert.Contains(t, err.Error(), "MetaData does not have 'free_call_signer_address defined correctly")
}
_, err = InitServiceMetaDataFromJson([]byte(strings.Replace(testJsonData, "default_pricing", "dummy", 1)))
if err != nil {
Expand All @@ -84,11 +85,13 @@ func TestReadServiceMetaDataFromLocalFile(t *testing.T) {
}

func Test_getServiceMetaDataUrifromRegistry(t *testing.T) {
assert.Panics(t, func() { getServiceMetaDataUrifromRegistry() })
config.Vip().Set(config.BlockChainNetworkSelected, "sepolia")
config.Validate()
assert.Panics(t, func() { getServiceMetaDataUrifromRegistry() })

_, err := getServiceMetaDataURIfromRegistry()
assert.NotNil(t, err)
config.Vip().Set(config.ServiceId, "semyon_dev")
config.Vip().Set(config.OrganizationId, "semyon_dev")
_, err = getServiceMetaDataURIfromRegistry()
assert.Nil(t, err)
}

func Test_setDefaultPricing(t *testing.T) {
Expand All @@ -112,7 +115,7 @@ func TestServiceMetadata_parseServiceProto(t *testing.T) {
assert.NotNil(t, priceMethodMap)
assert.NotNil(t, trainingMethods)
dynamicPriceMethod, ok := priceMethodMap["/example_service.Calculator/add"]
isTrainingMethod := isElementInArray("/example_service.Calculator/train_add", trainingMethods)
isTrainingMethod := slices.Contains(trainingMethods, "/example_service.Calculator/train_add")
assert.Equal(t, dynamicPriceMethod, "/example_service.Calculator/dynamic_pricing_add")
assert.True(t, ok, "true")
assert.True(t, isTrainingMethod)
Expand Down
Loading
Loading