Skip to content

Commit

Permalink
Merge pull request #605 from singnet/dev
Browse files Browse the repository at this point in the history
expose train metadata & custom errs
  • Loading branch information
semyon-dev authored Dec 27, 2024
2 parents 325b601 + 9559c23 commit 9eb9cd0
Show file tree
Hide file tree
Showing 35 changed files with 759 additions and 411 deletions.
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

0 comments on commit 9eb9cd0

Please sign in to comment.