diff --git a/common/types/min_max.go b/common/types/min_max.go index 3be953121e..5393511967 100644 --- a/common/types/min_max.go +++ b/common/types/min_max.go @@ -31,3 +31,35 @@ func FindMax[T constraints.Ordered](s []T) T { } return m } + +func Intersection[T comparable](arrays ...[]T) []T { + // Create a map to store the elements and their occurrence count + elements := make(map[T]int) + + // Iterate through each array + for _, arr := range arrays { + // Create a map to store the elements of the current array + arrElements := make(map[T]bool) + + // Populate the map with elements from the current array + for _, elem := range arr { + arrElements[elem] = true + } + + // Increment the occurrence count for each element in the map + for elem := range arrElements { + elements[elem]++ + } + } + + var intersection []T + + // Check the occurrence count of each element + for elem, count := range elements { + if count == len(arrays) { + intersection = append(intersection, elem) + } + } + + return intersection +} diff --git a/cookbook/plans/default.json b/cookbook/plans/default.json index 61a1976a3e..d3cfb24750 100755 --- a/cookbook/plans/default.json +++ b/cookbook/plans/default.json @@ -39,7 +39,9 @@ "geolocation_profile": "18446744073709551615", "total_cu_limit": "1000000", "epoch_cu_limit": "100000", - "max_providers_to_pair": "3" + "max_providers_to_pair": "3", + "selected_providers_mode": "ALLOWED", + "selected_providers": [] } } ] diff --git a/cookbook/projects/example_policy.yml b/cookbook/projects/example_policy.yml index 6989f62ae9..4b5b8431c0 100644 --- a/cookbook/projects/example_policy.yml +++ b/cookbook/projects/example_policy.yml @@ -1,3 +1,9 @@ +# selected_providers_mode: +# ALLOWED = 0; // no providers restrictions +# MIXED = 1; // use the selected providers mixed with randomly chosen providers +# EXCLUSIVE = 2; // use only the selected providers +# DISABLED = 3; // selected providers feature is disabled + Policy: chain_policies: - chain_id: ETH1 @@ -9,4 +15,9 @@ Policy: geolocation_profile: 1 total_cu_limit: 1000 epoch_cu_limit: 100 - max_providers_to_pair: 3 + max_providers_to_pair: 2 + selected_providers_mode: EXCLUSIVE + selected_providers: + - lava@1kgd936x3tlz2er9untunk7texfanmaud8yp9kf + - lava@18puklmhr7u2f9g524tttm24ttf4ud842wtfcna + - lava@1hvfeuhp5x94wwf972mfyls8gl0lgxeluklr202 \ No newline at end of file diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index c4beba8810..00583a3cce 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -31678,9 +31678,6 @@ paths: type: array items: type: string - api_count: - type: string - format: uint64 default: description: An unexpected error response. schema: @@ -55116,8 +55113,6 @@ definitions: type: string moniker: type: string - badge_signer_address: - type: string lavanet.lava.pairing.Metadata: type: object properties: @@ -57021,9 +57016,6 @@ definitions: type: array items: type: string - api_count: - type: string - format: uint64 lavanet.lava.spec.QueryShowChainInfoResponse: type: object properties: @@ -57222,9 +57214,6 @@ definitions: type: array items: type: string - api_count: - type: string - format: uint64 lavanet.lava.spec.Spec: type: object properties: diff --git a/go.mod b/go.mod index 07b615621a..13c9939707 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ require ( github.com/stretchr/testify v1.8.1 github.com/tendermint/tendermint v0.34.23 github.com/tendermint/tm-db v0.6.7 - google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e // indirect - google.golang.org/grpc v1.55.0 + google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 + google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -36,7 +36,6 @@ require ( github.com/newrelic/go-agent/v3 v3.20.4 github.com/spf13/pflag v1.0.5 gonum.org/v1/gonum v0.13.0 - google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc ) require ( @@ -45,11 +44,11 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gogo/googleapis v1.4.0 // indirect - github.com/golang/glog v1.1.0 // indirect + github.com/golang/glog v1.0.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect golang.org/x/mod v0.9.0 // indirect golang.org/x/tools v0.7.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect ) require ( @@ -113,7 +112,7 @@ require ( github.com/gookit/color v1.5.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect @@ -189,11 +188,11 @@ require ( go.opencensus.io v0.23.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 - golang.org/x/net v0.10.0 + golang.org/x/net v0.8.0 golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/term v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce diff --git a/go.sum b/go.sum index ac1b390ad3..2ccb749e6a 100644 --- a/go.sum +++ b/go.sum @@ -641,8 +641,8 @@ github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -767,6 +767,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t 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.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= @@ -1619,8 +1621,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 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= @@ -1754,13 +1756,13 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1770,8 +1772,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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= @@ -1948,12 +1950,8 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e h1:Ao9GzfUMPH3zjVfzXG5rlWlk+Q8MXWKwWpwVQE1MXfw= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 h1:znp6mq/drrY+6khTAlJUDNFFcDGV2ENLYKpMq8SyCds= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1985,8 +1983,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= 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= diff --git a/proto/projects/project.proto b/proto/projects/project.proto index fbba982a52..835da6c081 100644 --- a/proto/projects/project.proto +++ b/proto/projects/project.proto @@ -32,6 +32,14 @@ message ProjectKey { uint32 kinds = 4; } +// the enum below determines the pairing algorithm's behaviour with the selected providers feature +enum SELECTED_PROVIDERS_MODE { + ALLOWED = 0; // no providers restrictions + MIXED = 1; // use the selected providers mixed with randomly chosen providers + EXCLUSIVE = 2; // use only the selected providers + DISABLED = 3; // selected providers feature is disabled +} + // protobuf expected in YAML format: used "moretags" to simplify parsing message Policy { repeated ChainPolicy chain_policies = 1 [(gogoproto.nullable) = false, (gogoproto.moretags) = "mapstructure:\"chain_policies\""]; @@ -39,6 +47,8 @@ message Policy { uint64 total_cu_limit = 3 [(gogoproto.moretags) = "mapstructure:\"total_cu_limit\"", (gogoproto.jsontag) = "total_cu_limit"]; uint64 epoch_cu_limit = 4 [(gogoproto.moretags) = "mapstructure:\"epoch_cu_limit\"", (gogoproto.jsontag) = "epoch_cu_limit"]; uint64 max_providers_to_pair = 5 [(gogoproto.jsontag) = "max_providers_to_pair", (gogoproto.moretags) = "mapstructure:\"max_providers_to_pair\""]; + SELECTED_PROVIDERS_MODE selected_providers_mode = 6 [(gogoproto.moretags) = "mapstructure:\"selected_providers_mode\"", (gogoproto.jsontag) = "selected_providers_mode"]; + repeated string selected_providers = 7 [(gogoproto.moretags) = "mapstructure:\"selected_providers\"", (gogoproto.jsontag) = "selected_providers"]; } message ChainPolicy { diff --git a/x/pairing/keeper/filters/filter.go b/x/pairing/keeper/filters/filter.go new file mode 100644 index 0000000000..ad67724db1 --- /dev/null +++ b/x/pairing/keeper/filters/filter.go @@ -0,0 +1,71 @@ +package filters + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/utils" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + projectstypes "github.com/lavanet/lava/x/projects/types" +) + +type Filter interface { + Filter(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, currentEpoch uint64) []bool + InitFilter(strictestPolicy projectstypes.Policy) bool // return if filter is usable (by the policy) +} + +func GetAllFilters() []Filter { + var selectedProvidersFilter SelectedProvidersFilter + var frozenProvidersFilter FrozenProvidersFilter + var geolocationFilter GeolocationFilter + + filters := []Filter{&selectedProvidersFilter, &frozenProvidersFilter, &geolocationFilter} + return filters +} + +func initFilters(filters []Filter, strictestPolicy projectstypes.Policy) []Filter { + activeFilters := []Filter{} + + for _, filter := range filters { + active := filter.InitFilter(strictestPolicy) + if active { + activeFilters = append(activeFilters, filter) + } + } + + return activeFilters +} + +func FilterProviders(ctx sdk.Context, filters []Filter, providers []epochstoragetypes.StakeEntry, strictestPolicy projectstypes.Policy, currentEpoch uint64) ([]epochstoragetypes.StakeEntry, error) { + filters = initFilters(filters, strictestPolicy) + + var filtersResult [][]bool + + for _, filter := range filters { + res := filter.Filter(ctx, providers, currentEpoch) + if len(res) != len(providers) { + return []epochstoragetypes.StakeEntry{}, utils.LavaFormatError("filter result length is not equal to providers list length", fmt.Errorf("filter failed"), + utils.Attribute{Key: "filter result length", Value: len(res)}, + utils.Attribute{Key: "providers length", Value: len(providers)}, + ) + } + filtersResult = append(filtersResult, res) + } + + filteredProviders := []epochstoragetypes.StakeEntry{} + for j := 0; j < len(providers); j++ { + result := true + for i := 0; i < len(filters); i++ { + result = result && filtersResult[i][j] + if !result { + break + } + } + + if result { + filteredProviders = append(filteredProviders, providers[j]) + } + } + + return filteredProviders, nil +} diff --git a/x/pairing/keeper/filters/frozen_providers_filter.go b/x/pairing/keeper/filters/frozen_providers_filter.go new file mode 100644 index 0000000000..1d2686a402 --- /dev/null +++ b/x/pairing/keeper/filters/frozen_providers_filter.go @@ -0,0 +1,29 @@ +package filters + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + projectstypes "github.com/lavanet/lava/x/projects/types" +) + +type FrozenProvidersFilter struct{} + +func (f *FrozenProvidersFilter) InitFilter(strictestPolicy projectstypes.Policy) bool { + // frozen providers (or providers that their stake is not applied yet) can't be part of the pairing - this filter is always active + return true +} + +func (f *FrozenProvidersFilter) Filter(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, currentEpoch uint64) []bool { + filterResult := make([]bool, len(providers)) + for i := range providers { + if !isProviderFrozen(ctx, providers[i], currentEpoch) { + filterResult[i] = true + } + } + + return filterResult +} + +func isProviderFrozen(ctx sdk.Context, stakeEntry epochstoragetypes.StakeEntry, currentEpoch uint64) bool { + return stakeEntry.StakeAppliedBlock > currentEpoch +} diff --git a/x/pairing/keeper/filters/geolocation_filter.go b/x/pairing/keeper/filters/geolocation_filter.go new file mode 100644 index 0000000000..9f9e783155 --- /dev/null +++ b/x/pairing/keeper/filters/geolocation_filter.go @@ -0,0 +1,37 @@ +package filters + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + projectstypes "github.com/lavanet/lava/x/projects/types" +) + +// TODO: This is a temp filter until the geolocation mechanism changes (this is not optimal) + +type GeolocationFilter struct { + geolocation uint64 +} + +func (f *GeolocationFilter) InitFilter(strictestPolicy projectstypes.Policy) bool { + if strictestPolicy.SelectedProvidersMode == projectstypes.SELECTED_PROVIDERS_MODE_DISABLED || + strictestPolicy.SelectedProvidersMode == projectstypes.SELECTED_PROVIDERS_MODE_ALLOWED { + f.geolocation = strictestPolicy.GeolocationProfile + return true + } + return false +} + +func (f *GeolocationFilter) Filter(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, currentEpoch uint64) []bool { + filterResult := make([]bool, len(providers)) + for i := range providers { + if isGeolocationSupported(f.geolocation, providers[i].Geolocation) { + filterResult[i] = true + } + } + + return filterResult +} + +func isGeolocationSupported(policyGeolocation uint64, providerGeolocation uint64) bool { + return policyGeolocation&providerGeolocation != 0 +} diff --git a/x/pairing/keeper/filters/selected_providers_filter.go b/x/pairing/keeper/filters/selected_providers_filter.go new file mode 100644 index 0000000000..3cb953d968 --- /dev/null +++ b/x/pairing/keeper/filters/selected_providers_filter.go @@ -0,0 +1,38 @@ +package filters + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + projectstypes "github.com/lavanet/lava/x/projects/types" +) + +type SelectedProvidersFilter struct { + selectedProviders []string +} + +func (f *SelectedProvidersFilter) InitFilter(strictestPolicy projectstypes.Policy) bool { + switch strictestPolicy.SelectedProvidersMode { + case projectstypes.SELECTED_PROVIDERS_MODE_EXCLUSIVE, projectstypes.SELECTED_PROVIDERS_MODE_MIXED: + f.selectedProviders = strictestPolicy.SelectedProviders + return true + } + return false +} + +func (f *SelectedProvidersFilter) Filter(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, currentEpoch uint64) []bool { + filterResult := make([]bool, len(providers)) + if len(f.selectedProviders) == 0 { + return filterResult + } + + selectedProvidersMap := map[string]struct{}{} + for _, selectedProviderAddr := range f.selectedProviders { + selectedProvidersMap[selectedProviderAddr] = struct{}{} + } + + for i := range providers { + _, filterResult[i] = selectedProvidersMap[providers[i].Address] + } + + return filterResult +} diff --git a/x/pairing/keeper/grpc_query_static_providers_list.go b/x/pairing/keeper/grpc_query_static_providers_list.go index 3e6608d731..6bad607eeb 100644 --- a/x/pairing/keeper/grpc_query_static_providers_list.go +++ b/x/pairing/keeper/grpc_query_static_providers_list.go @@ -5,8 +5,11 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/utils" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + pairingfilters "github.com/lavanet/lava/x/pairing/keeper/filters" "github.com/lavanet/lava/x/pairing/types" + projectstypes "github.com/lavanet/lava/x/projects/types" spectypes "github.com/lavanet/lava/x/spec/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -40,12 +43,27 @@ func (k Keeper) StaticProvidersList(goCtx context.Context, req *types.QueryStati } finalProviders := []epochstoragetypes.StakeEntry{} - geolocation := uint64(1) + var geolocationFilter pairingfilters.GeolocationFilter + policy := projectstypes.Policy{ + GeolocationProfile: uint64(1), + SelectedProvidersMode: projectstypes.SELECTED_PROVIDERS_MODE_DISABLED, + } + geoFilterActive := geolocationFilter.InitFilter(policy) + if !geoFilterActive { + return nil, utils.LavaFormatError("geolocation filter should be active according to the mode", fmt.Errorf("geo filter not active"), + utils.Attribute{Key: "selected_providers_mode", Value: policy.SelectedProvidersMode}, + utils.Attribute{Key: "geolocation_profile", Value: policy.GeolocationProfile}, + ) + } + for i := uint64(0); i < k.specKeeper.GeolocationCount(ctx); i++ { - validProviders := k.getGeolocationProviders(ctx, stakes, geolocation) + validProviders, err := pairingfilters.FilterProviders(ctx, []pairingfilters.Filter{&geolocationFilter}, stakes, policy, epoch) + if err != nil { + return nil, err + } validProviders = k.returnSubsetOfProvidersByHighestStake(ctx, validProviders, servicersToPairCount) finalProviders = append(finalProviders, validProviders...) - geolocation <<= 1 + policy.GeolocationProfile <<= 1 } return &types.QueryStaticProvidersListResponse{Providers: finalProviders}, nil diff --git a/x/pairing/keeper/msg_server_freeze.go b/x/pairing/keeper/msg_server_freeze.go index 9014b9e0eb..68d47632e7 100644 --- a/x/pairing/keeper/msg_server_freeze.go +++ b/x/pairing/keeper/msg_server_freeze.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "math" "strconv" "strings" @@ -12,8 +11,6 @@ import ( "github.com/lavanet/lava/x/pairing/types" ) -const FrozenBlock = math.MaxInt64 - func (k msgServer) FreezeProvider(goCtx context.Context, msg *types.MsgFreezeProvider) (*types.MsgFreezeProviderResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -35,7 +32,7 @@ func (k Keeper) FreezeProvider(ctx sdk.Context, provider string, chainIDs []stri } // freeze the provider by making the StakeAppliedBlock be max. This will remove the provider from the pairing list in the next epoch - stakeEntry.StakeAppliedBlock = FrozenBlock + stakeEntry.StakeAppliedBlock = types.FROZEN_BLOCK k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, epochstoragetypes.ProviderKey, chainId, stakeEntry, index) } diff --git a/x/pairing/keeper/pairing.go b/x/pairing/keeper/pairing.go index 0950f16cff..b23a770302 100644 --- a/x/pairing/keeper/pairing.go +++ b/x/pairing/keeper/pairing.go @@ -9,6 +9,7 @@ import ( commontypes "github.com/lavanet/lava/common/types" "github.com/lavanet/lava/utils" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + pairingfilters "github.com/lavanet/lava/x/pairing/keeper/filters" projectstypes "github.com/lavanet/lava/x/projects/types" spectypes "github.com/lavanet/lava/x/spec/types" tendermintcrypto "github.com/tendermint/tendermint/crypto" @@ -106,9 +107,8 @@ func (k Keeper) GetPairingForClient(ctx sdk.Context, chainID string, clientAddre // function used to get a new pairing from provider and client // first argument has all metadata, second argument is only the addresses func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, clientAddress sdk.AccAddress, block uint64) (providers []epochstoragetypes.StakeEntry, allowedCU uint64, legacyStake bool, errorRet error) { - var geolocation uint64 - var providersToPair uint64 var projectToPair string + var strictestPolicy projectstypes.Policy epoch, err := k.VerifyPairingData(ctx, chainID, clientAddress, block) if err != nil { @@ -118,10 +118,11 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, clientAddre project, err := k.GetProjectData(ctx, clientAddress, chainID, block) if err == nil { legacyStake = false - geolocation, providersToPair, projectToPair, allowedCU, err = k.getProjectStrictestPolicy(ctx, project, chainID) + strictestPolicy, allowedCU, err = k.getProjectStrictestPolicy(ctx, project, chainID) if err != nil { return nil, 0, false, fmt.Errorf("invalid user for pairing: %s", err.Error()) } + projectToPair = project.Index } else { // legacy staked client clientStakeEntry, err2 := k.VerifyClientStake(ctx, chainID, clientAddress, block, epoch) @@ -129,14 +130,14 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, clientAddre // user is not valid for pairing return nil, 0, false, fmt.Errorf("invalid user for pairing: 1) %s 2) %s", err.Error(), err2.Error()) } - geolocation = clientStakeEntry.Geolocation + strictestPolicy.GeolocationProfile = clientStakeEntry.Geolocation servicersToPairCount, err := k.ServicersToPairCount(ctx, block) if err != nil { return nil, 0, false, err } - providersToPair = servicersToPairCount + strictestPolicy.MaxProvidersToPair = servicersToPairCount projectToPair = clientAddress.String() allowedCU, err = k.ClientMaxCUProviderForBlock(ctx, block, clientStakeEntry) @@ -152,15 +153,23 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, clientAddre return nil, 0, false, fmt.Errorf("did not find providers for pairing: epoch:%d, chainID: %s", block, chainID) } - providers, err = k.calculatePairingForClient(ctx, possibleProviders, projectToPair, block, chainID, geolocation, epochHash, providersToPair) + filters := pairingfilters.GetAllFilters() + + possibleProviders, err = pairingfilters.FilterProviders(ctx, filters, possibleProviders, strictestPolicy, epoch) + if err != nil { + return nil, 0, false, err + } + + providers, err = k.calculatePairingForClient(ctx, possibleProviders, projectToPair, block, + chainID, epochHash, strictestPolicy.MaxProvidersToPair) return providers, allowedCU, legacyStake, err } -func (k Keeper) getProjectStrictestPolicy(ctx sdk.Context, project projectstypes.Project, chainID string) (uint64, uint64, string, uint64, error) { +func (k Keeper) getProjectStrictestPolicy(ctx sdk.Context, project projectstypes.Project, chainID string) (projectstypes.Policy, uint64, error) { plan, err := k.subscriptionKeeper.GetPlanFromSubscription(ctx, project.GetSubscription()) if err != nil { - return 0, 0, "", 0, err + return projectstypes.Policy{}, 0, err } planPolicy := plan.GetPlanPolicy() @@ -173,24 +182,50 @@ func (k Keeper) getProjectStrictestPolicy(ctx sdk.Context, project projectstypes } if !projectstypes.CheckChainIdExistsInPolicies(chainID, policies) { - return 0, 0, "", 0, fmt.Errorf("chain ID not found in any of the policies") + return projectstypes.Policy{}, 0, fmt.Errorf("chain ID not found in any of the policies") } geolocation := k.CalculateEffectiveGeolocationFromPolicies(policies) - providersToPair := k.CalculateEffectiveProvidersToPairFromPolicies(policies) - if providersToPair == uint64(math.MaxUint64) { - return 0, 0, "", 0, fmt.Errorf("could not calculate providersToPair value: all policies are nil") + providersToPair, err := k.CalculateEffectiveProvidersToPairFromPolicies(policies) + if err != nil { + return projectstypes.Policy{}, 0, err } sub, found := k.subscriptionKeeper.GetSubscription(ctx, project.GetSubscription()) if !found { - return 0, 0, "", 0, fmt.Errorf("could not find subscription with address %s", project.GetSubscription()) + return projectstypes.Policy{}, 0, fmt.Errorf("could not find subscription with address %s", project.GetSubscription()) } allowedCU := k.CalculateEffectiveAllowedCuPerEpochFromPolicies(policies, project.GetUsedCu(), sub.GetMonthCuLeft()) - projectToPair := project.Index - return geolocation, providersToPair, projectToPair, allowedCU, nil + selectedProvidersMode, selectedProvidersList := k.CalculateEffectiveSelectedProviders(policies) + + strictestPolicy := projectstypes.Policy{ + GeolocationProfile: geolocation, + MaxProvidersToPair: providersToPair, + SelectedProvidersMode: selectedProvidersMode, + SelectedProviders: selectedProvidersList, + } + + return strictestPolicy, allowedCU, nil +} + +func (k Keeper) CalculateEffectiveSelectedProviders(policies []*projectstypes.Policy) (projectstypes.SELECTED_PROVIDERS_MODE, []string) { + selectedProvidersModeList := []projectstypes.SELECTED_PROVIDERS_MODE{} + selectedProvidersList := [][]string{} + for _, p := range policies { + selectedProvidersModeList = append(selectedProvidersModeList, p.SelectedProvidersMode) + if p.SelectedProvidersMode == projectstypes.SELECTED_PROVIDERS_MODE_EXCLUSIVE || p.SelectedProvidersMode == projectstypes.SELECTED_PROVIDERS_MODE_MIXED { + if len(p.SelectedProviders) != 0 { + selectedProvidersList = append(selectedProvidersList, p.SelectedProviders) + } + } + } + + effectiveMode := commontypes.FindMax(selectedProvidersModeList) + effectiveSelectedProviders := commontypes.Intersection(selectedProvidersList...) + + return effectiveMode, effectiveSelectedProviders } func (k Keeper) CalculateEffectiveGeolocationFromPolicies(policies []*projectstypes.Policy) uint64 { @@ -206,7 +241,7 @@ func (k Keeper) CalculateEffectiveGeolocationFromPolicies(policies []*projectsty return geolocation } -func (k Keeper) CalculateEffectiveProvidersToPairFromPolicies(policies []*projectstypes.Policy) uint64 { +func (k Keeper) CalculateEffectiveProvidersToPairFromPolicies(policies []*projectstypes.Policy) (uint64, error) { providersToPair := uint64(math.MaxUint64) for _, policy := range policies { @@ -216,7 +251,11 @@ func (k Keeper) CalculateEffectiveProvidersToPairFromPolicies(policies []*projec } } - return providersToPair + if providersToPair == uint64(math.MaxUint64) { + return 0, fmt.Errorf("could not calculate providersToPair value: all policies are nil") + } + + return providersToPair, nil } func (k Keeper) CalculateEffectiveAllowedCuPerEpochFromPolicies(policies []*projectstypes.Policy, cuUsedInProject uint64, cuLeftInSubscription uint64) uint64 { @@ -262,7 +301,7 @@ func (k Keeper) ValidatePairingForClient(ctx sdk.Context, chainID string, client return false, allowedCU, 0, legacyStake, nil } -func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, developerAddress string, epochStartBlock uint64, chainID string, geolocation uint64, epochHash []byte, providersToPair uint64) (validProviders []epochstoragetypes.StakeEntry, err error) { +func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, developerAddress string, epochStartBlock uint64, chainID string, epochHash []byte, providersToPair uint64) (validProviders []epochstoragetypes.StakeEntry, err error) { if epochStartBlock > uint64(ctx.BlockHeight()) { k.Logger(ctx).Error("\ninvalid session start\n") panic(fmt.Sprintf("invalid session start saved in keeper %d, current block was %d", epochStartBlock, uint64(ctx.BlockHeight()))) @@ -273,37 +312,17 @@ func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstor return nil, fmt.Errorf("spec not found or not enabled") } - validProviders = k.getGeolocationProviders(ctx, providers, geolocation) - if spec.ProvidersTypes == spectypes.Spec_dynamic { // calculates a hash and randomly chooses the providers - validProviders = k.returnSubsetOfProvidersByStake(ctx, developerAddress, validProviders, providersToPair, epochStartBlock, chainID, epochHash) + validProviders = k.returnSubsetOfProvidersByStake(ctx, developerAddress, providers, providersToPair, epochStartBlock, chainID, epochHash) } else { - validProviders = k.returnSubsetOfProvidersByHighestStake(ctx, validProviders, providersToPair) + validProviders = k.returnSubsetOfProvidersByHighestStake(ctx, providers, providersToPair) } return validProviders, nil } -func (k Keeper) getGeolocationProviders(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, geolocation uint64) []epochstoragetypes.StakeEntry { - validProviders := []epochstoragetypes.StakeEntry{} - // create a list of valid providers (stakeAppliedBlock reached) - for _, stakeEntry := range providers { - if stakeEntry.StakeAppliedBlock > uint64(ctx.BlockHeight()) { - // provider stakeAppliedBlock wasn't reached yet - continue - } - geolocationSupported := stakeEntry.Geolocation & geolocation - if geolocationSupported == 0 { - // no match in geolocation bitmap - continue - } - validProviders = append(validProviders, stakeEntry) - } - return validProviders -} - // this function randomly chooses count providers by weight func (k Keeper) returnSubsetOfProvidersByStake(ctx sdk.Context, clientAddress string, providersMaps []epochstoragetypes.StakeEntry, count uint64, block uint64, chainID string, epochHash []byte) (returnedProviders []epochstoragetypes.StakeEntry) { stakeSum := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(0)) diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index 90716349d2..20709032cb 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -1,14 +1,19 @@ package keeper_test import ( + "math" "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/testutil/common" testkeeper "github.com/lavanet/lava/testutil/keeper" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" + planstypes "github.com/lavanet/lava/x/plans/types" + projectstypes "github.com/lavanet/lava/x/projects/types" spectypes "github.com/lavanet/lava/x/spec/types" + subscriptiontypes "github.com/lavanet/lava/x/subscription/types" "github.com/stretchr/testify/require" ) @@ -302,3 +307,276 @@ func TestPairingStatic(t *testing.T) { require.Equal(t, provider.Stake.Amount.Int64(), stake+int64(i)) } } + +func TestSelectedProvidersPairing(t *testing.T) { + ts := setupForPaymentTest(t) + _ctx := sdk.UnwrapSDKContext(ts.ctx) + + projPolicy := &projectstypes.Policy{ + GeolocationProfile: math.MaxUint64, + MaxProvidersToPair: 3, + } + + err := ts.addProvider(200) + require.Nil(t, err) + + allowed := projectstypes.SELECTED_PROVIDERS_MODE_ALLOWED + exclusive := projectstypes.SELECTED_PROVIDERS_MODE_EXCLUSIVE + disabled := projectstypes.SELECTED_PROVIDERS_MODE_DISABLED + + maxProvidersToPair, err := ts.keepers.Pairing.CalculateEffectiveProvidersToPairFromPolicies( + []*projectstypes.Policy{&ts.plan.PlanPolicy, projPolicy}, + ) + require.Nil(t, err) + + p1 := ts.providers[0].Addr.String() + p2 := ts.providers[1].Addr.String() + p3 := ts.providers[2].Addr.String() + p4 := ts.providers[3].Addr.String() + p5 := ts.providers[4].Addr.String() + + providerSets := []struct { + planProviders []string + subProviders []string + projProviders []string + }{ + {[]string{}, []string{}, []string{}}, // set #0 + {[]string{p1, p2, p3}, []string{}, []string{}}, // set #1 + {[]string{p1, p2}, []string{}, []string{}}, // set #2 + {[]string{p3, p4}, []string{}, []string{}}, // set #3 + {[]string{p1, p2, p3}, []string{p1, p2}, []string{}}, // set #4 + {[]string{p1, p2, p3}, []string{}, []string{p1, p3}}, // set #5 + {[]string{}, []string{p1, p2, p3}, []string{p1, p2}}, // set #6 + {[]string{p1}, []string{p1, p2, p3}, []string{p1, p2}}, // set #7 + {[]string{p1, p2, p3, p4, p5}, []string{p1, p2, p3, p4}, []string{}}, // set #8 + } + + expectedSelectedProviders := [][]string{ + {p1, p2, p3}, // expected providers for intersection of set #1 + {p1, p2}, // expected providers for intersection of set #2 + {p3, p4}, // expected providers for intersection of set #3 + {p1, p2}, // expected providers for intersection of set #4 + {p1, p3}, // expected providers for intersection of set #5 + {p1, p2}, // expected providers for intersection of set #6 + {p1}, // expected providers for intersection of set #7 + {p1, p2, p3, p4}, // expected providers for intersection of set #8 + } + + // TODO: add mixed mode test cases (once implemented) + templates := []struct { + name string + planMode projectstypes.SELECTED_PROVIDERS_MODE + subMode projectstypes.SELECTED_PROVIDERS_MODE + projMode projectstypes.SELECTED_PROVIDERS_MODE + providersSet int + expectedProviders int + }{ + // normal pairing cases + {"ALLOWED mode normal pairing", allowed, allowed, allowed, 0, 0}, + {"DISABLED mode normal pairing", disabled, allowed, allowed, 0, 0}, + + // basic pairing checks cases + {"EXCLUSIVE mode selected MaxProvidersToPair providers", exclusive, allowed, allowed, 1, 0}, + {"EXCLUSIVE mode selected less than MaxProvidersToPair providers", exclusive, allowed, allowed, 2, 1}, + {"EXCLUSIVE mode selected less than MaxProvidersToPair different providers", exclusive, allowed, allowed, 3, 2}, + + // intersection checks cases + {"EXCLUSIVE mode intersection between plan/sub policies", exclusive, exclusive, exclusive, 4, 3}, + {"EXCLUSIVE mode intersection between plan/proj policies", exclusive, exclusive, exclusive, 5, 4}, + {"EXCLUSIVE mode intersection between sub/proj policies", exclusive, exclusive, exclusive, 6, 5}, + {"EXCLUSIVE mode intersection between all policies", exclusive, exclusive, exclusive, 7, 6}, + + // selected providers more than MaxProvidersToPair + {"EXCLUSIVE mode selected more than MaxProvidersToPair providers", exclusive, exclusive, exclusive, 8, 7}, + + // provider unstake checks cases + {"EXCLUSIVE mode provider unstakes after first pairing", exclusive, exclusive, exclusive, 1, 0}, + {"EXCLUSIVE mode non-staked provider stakes after first pairing", exclusive, exclusive, exclusive, 1, 0}, + } + + expectedProvidersAfterUnstake := []string{} + for _, tt := range templates { + t.Run(tt.name, func(t *testing.T) { + // create plan, propose it and buy subscription + plan := common.CreateMockPlan() + subAddr := common.CreateNewAccount(ts.ctx, *ts.keepers, 10000).Addr.String() + providersSet := providerSets[tt.providersSet] + + plan.PlanPolicy.SelectedProvidersMode = tt.planMode + plan.PlanPolicy.SelectedProviders = providersSet.planProviders + + err := testkeeper.SimulatePlansAddProposal(_ctx, ts.keepers.Plans, []planstypes.Plan{plan}) + require.Nil(t, err) + + _, err = ts.servers.SubscriptionServer.Buy(ts.ctx, &subscriptiontypes.MsgBuy{ + Creator: subAddr, + Consumer: subAddr, + Index: plan.Index, + Duration: 1, + }) + require.Nil(t, err) + + // get the admin project and set its policies + subProjects, err := ts.keepers.Subscription.ListProjects(ts.ctx, &subscriptiontypes.QueryListProjectsRequest{ + Subscription: subAddr, + }) + require.Nil(t, err) + require.Equal(t, 1, len(subProjects.Projects)) + + adminProject, err := ts.keepers.Projects.GetProjectForBlock(_ctx, subProjects.Projects[0], uint64(_ctx.BlockHeight())) + require.Nil(t, err) + + projPolicy.SelectedProvidersMode = tt.projMode + projPolicy.SelectedProviders = providersSet.projProviders + + _, err = ts.servers.ProjectServer.SetPolicy(ts.ctx, &projectstypes.MsgSetPolicy{ + Creator: subAddr, + Project: adminProject.Index, + Policy: *projPolicy, + }) + require.Nil(t, err) + + // apply policy change + ts.ctx = testkeeper.AdvanceEpoch(ts.ctx, ts.keepers) + _ctx = sdk.UnwrapSDKContext(ts.ctx) + + projPolicy.SelectedProvidersMode = tt.subMode + projPolicy.SelectedProviders = providersSet.subProviders + + _, err = ts.servers.ProjectServer.SetSubscriptionPolicy(ts.ctx, &projectstypes.MsgSetSubscriptionPolicy{ + Creator: subAddr, + Projects: []string{adminProject.Index}, + Policy: *projPolicy, + }) + require.Nil(t, err) + + // apply policy change + ts.ctx = testkeeper.AdvanceEpoch(ts.ctx, ts.keepers) + _ctx = sdk.UnwrapSDKContext(ts.ctx) + + // get pairing of two consecutive epochs + ts.ctx = testkeeper.AdvanceEpoch(ts.ctx, ts.keepers) + _ctx = sdk.UnwrapSDKContext(ts.ctx) + + pairing, err := ts.keepers.Pairing.GetPairing(ts.ctx, &types.QueryGetPairingRequest{ + ChainID: ts.spec.Index, + Client: subAddr, + }) + require.Nil(t, err) + providerAddresses1 := []string{} + for _, provider := range pairing.Providers { + providerAddresses1 = append(providerAddresses1, provider.Address) + } + + if tt.name == "EXCLUSIVE mode provider unstakes after first pairing" { + _, err = ts.servers.PairingServer.UnstakeProvider(ts.ctx, &types.MsgUnstakeProvider{ + Creator: p1, + ChainID: ts.spec.Index, + }) + require.Nil(t, err) + expectedProvidersAfterUnstake = expectedSelectedProviders[tt.expectedProviders][1:] // remove p1 from expected providers + } else if tt.name == "EXCLUSIVE mode non-staked provider stakes after first pairing" { + endpoints := []epochstoragetypes.Endpoint{{ + IPPORT: "123", + UseType: ts.spec.GetApis()[0].ApiInterfaces[0].Interface, + Geolocation: uint64(1), + }} + _, err = ts.servers.PairingServer.StakeProvider(ts.ctx, &types.MsgStakeProvider{ + Creator: p1, + ChainID: ts.spec.Index, + Amount: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(10000000)), + Endpoints: endpoints, + Geolocation: uint64(1), + }) + require.Nil(t, err) + } + + ts.ctx = testkeeper.AdvanceEpoch(ts.ctx, ts.keepers) + _ctx = sdk.UnwrapSDKContext(ts.ctx) + + pairing, err = ts.keepers.Pairing.GetPairing(ts.ctx, &types.QueryGetPairingRequest{ + ChainID: ts.spec.Index, + Client: subAddr, + }) + require.Nil(t, err) + providerAddresses2 := []string{} + for _, provider := range pairing.Providers { + providerAddresses2 = append(providerAddresses2, provider.Address) + } + + // check pairings + switch tt.name { + case "ALLOWED mode normal pairing", "DISABLED mode normal pairing": + require.False(t, unorderedEqual(providerAddresses1, providerAddresses2)) + require.Equal(t, maxProvidersToPair, uint64(len(providerAddresses1))) + require.Equal(t, maxProvidersToPair, uint64(len(providerAddresses2))) + + case "EXCLUSIVE mode selected MaxProvidersToPair providers": + require.True(t, unorderedEqual(providerAddresses1, providerAddresses2)) + require.Equal(t, maxProvidersToPair, uint64(len(providerAddresses2))) + require.True(t, unorderedEqual(expectedSelectedProviders[tt.expectedProviders], providerAddresses1)) + + case "EXCLUSIVE mode selected less than MaxProvidersToPair providers", + "EXCLUSIVE mode selected less than MaxProvidersToPair different providers", + "EXCLUSIVE mode intersection between plan/sub policies", + "EXCLUSIVE mode intersection between plan/proj policies", + "EXCLUSIVE mode intersection between sub/proj policies", + "EXCLUSIVE mode intersection between all policies": + require.True(t, unorderedEqual(providerAddresses1, providerAddresses2)) + require.Less(t, uint64(len(providerAddresses1)), maxProvidersToPair) + require.True(t, unorderedEqual(expectedSelectedProviders[tt.expectedProviders], providerAddresses1)) + + case "EXCLUSIVE mode selected more than MaxProvidersToPair providers": + require.True(t, IsSubset(providerAddresses1, expectedSelectedProviders[tt.expectedProviders])) + require.True(t, IsSubset(providerAddresses2, expectedSelectedProviders[tt.expectedProviders])) + require.Equal(t, maxProvidersToPair, uint64(len(providerAddresses1))) + require.Equal(t, maxProvidersToPair, uint64(len(providerAddresses2))) + + case "EXCLUSIVE mode provider unstakes after first pairing": + require.False(t, unorderedEqual(providerAddresses1, providerAddresses2)) + require.True(t, unorderedEqual(expectedSelectedProviders[tt.expectedProviders], providerAddresses1)) + require.True(t, unorderedEqual(expectedProvidersAfterUnstake, providerAddresses2)) + + case "EXCLUSIVE mode non-staked provider stakes after first pairing": + require.False(t, unorderedEqual(providerAddresses1, providerAddresses2)) + require.True(t, unorderedEqual(expectedSelectedProviders[tt.expectedProviders], providerAddresses2)) + require.True(t, unorderedEqual(expectedProvidersAfterUnstake, providerAddresses1)) + } + }) + } +} + +func unorderedEqual(first, second []string) bool { + if len(first) != len(second) { + return false + } + exists := make(map[string]bool) + for _, value := range first { + exists[value] = true + } + for _, value := range second { + if !exists[value] { + return false + } + } + return true +} + +func IsSubset(subset, superset []string) bool { + // Create a map to store the elements of the superset + elements := make(map[string]bool) + + // Populate the map with elements from the superset + for _, elem := range superset { + elements[elem] = true + } + + // Check each element of the subset against the map + for _, elem := range subset { + if !elements[elem] { + return false + } + } + + return true +} diff --git a/x/pairing/types/types.go b/x/pairing/types/types.go index 86159ec9ba..b3e6a49b0e 100644 --- a/x/pairing/types/types.go +++ b/x/pairing/types/types.go @@ -1,5 +1,7 @@ package types +import math "math" + const ( ProviderStakeEventName = "stake_new_provider" ConsumerStakeEventName = "stake_new_consumer" @@ -32,6 +34,9 @@ const ( EPOCHS_NUM_TO_CHECK_FOR_COMPLAINERS uint64 = 2 // number of epochs to sum CU of complainers against the provider ) +// Frozen provider block const +const FROZEN_BLOCK = math.MaxInt64 + func StakeNewEventName(isProvider bool) string { if isProvider { return ProviderStakeEventName diff --git a/x/plans/types/plan.go b/x/plans/types/plan.go index 76685c53d5..75f01c9a39 100644 --- a/x/plans/types/plan.go +++ b/x/plans/types/plan.go @@ -23,16 +23,6 @@ func (p Plan) ValidatePlan() error { return sdkerrors.Wrap(ErrInvalidPlanOveruse, "plan can't forbid CU overuse and have a non-zero overuse rate") } - // check the compute units field are non-zero - if p.PlanPolicy.GetTotalCuLimit() == 0 || p.PlanPolicy.GetEpochCuLimit() == 0 { - return sdkerrors.Wrap(ErrInvalidPlanComputeUnits, "plan's compute units fields can't be zero") - } - - // check that the plan's servicersToPair is larger than 1 - if p.PlanPolicy.GetMaxProvidersToPair() <= 1 { - return sdkerrors.Wrap(ErrInvalidPlanServicersToPair, "plan's servicersToPair field can't be one or lower") - } - // check that the plan's description length is below the max length if len(p.GetDescription()) > MAX_LEN_PLAN_DESCRIPTION { return sdkerrors.Wrap(ErrInvalidPlanDescription, "plan's description is too long") @@ -48,5 +38,10 @@ func (p Plan) ValidatePlan() error { return sdkerrors.Wrap(ErrInvalidPlanAnnualDiscount, "plan's annual discount is invalid (not between 0-100 percent)") } + err := p.PlanPolicy.ValidateBasicPolicy(true) + if err != nil { + return err + } + return nil } diff --git a/x/projects/keeper/msg_server_set_admin_policy.go b/x/projects/keeper/msg_server_set_admin_policy.go index f6bff82742..1a2b170345 100644 --- a/x/projects/keeper/msg_server_set_admin_policy.go +++ b/x/projects/keeper/msg_server_set_admin_policy.go @@ -12,7 +12,7 @@ func (k msgServer) SetPolicy(goCtx context.Context, msg *types.MsgSetPolicy) (*t policy := msg.GetPolicy() - err := policy.ValidateBasicPolicy() + err := policy.ValidateBasicPolicy(false) if err != nil { return nil, err } diff --git a/x/projects/keeper/msg_server_set_subscription_policy.go b/x/projects/keeper/msg_server_set_subscription_policy.go index 9b316d2c2b..7a2b5d0413 100644 --- a/x/projects/keeper/msg_server_set_subscription_policy.go +++ b/x/projects/keeper/msg_server_set_subscription_policy.go @@ -12,7 +12,7 @@ func (k msgServer) SetSubscriptionPolicy(goCtx context.Context, msg *types.MsgSe policy := msg.GetPolicy() - err := policy.ValidateBasicPolicy() + err := policy.ValidateBasicPolicy(false) if err != nil { return nil, err } diff --git a/x/projects/keeper/project_test.go b/x/projects/keeper/project_test.go index 949cae3711..9b5e3a1d2d 100644 --- a/x/projects/keeper/project_test.go +++ b/x/projects/keeper/project_test.go @@ -10,6 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/testutil/common" testkeeper "github.com/lavanet/lava/testutil/keeper" + planstypes "github.com/lavanet/lava/x/plans/types" "github.com/lavanet/lava/x/projects/types" subscriptiontypes "github.com/lavanet/lava/x/subscription/types" "github.com/stretchr/testify/require" @@ -833,3 +834,124 @@ func TestAddDevKeyToDifferentProjectsInSameBlock(t *testing.T) { require.Equal(t, 2, len(proj1.ProjectKeys)) require.Equal(t, 1, len(proj2.ProjectKeys)) } + +func TestSetPolicySelectedProviders(t *testing.T) { + servers, keepers, _ctx := testkeeper.InitAllKeepers(t) + ctx := sdk.UnwrapSDKContext(_ctx) + + adm1Addr := common.CreateNewAccount(_ctx, *keepers, 10000).Addr.String() + projectData := types.ProjectData{ + Name: "name", + Enabled: true, + ProjectKeys: []types.ProjectKey{{Key: adm1Addr, Kinds: uint32(types.ProjectKey_ADMIN)}}, + Policy: &types.Policy{MaxProvidersToPair: 2, GeolocationProfile: math.MaxUint64}, + } + subAddr := projectData.ProjectKeys[0].Key + projPolicy := projectData.Policy + + allowed := types.SELECTED_PROVIDERS_MODE_ALLOWED + mixed := types.SELECTED_PROVIDERS_MODE_MIXED + exclusive := types.SELECTED_PROVIDERS_MODE_EXCLUSIVE + disabled := types.SELECTED_PROVIDERS_MODE_DISABLED + + providersSets := []struct { + planProviders []string + subProviders []string + projProviders []string + }{ + {[]string{}, []string{}, []string{}}, + {[]string{subAddr}, []string{subAddr}, []string{subAddr}}, + {[]string{subAddr}, []string{subAddr}, []string{}}, + {[]string{"lalala"}, []string{"lalala"}, []string{"lalala"}}, + {[]string{subAddr, subAddr}, []string{subAddr, subAddr}, []string{subAddr, subAddr}}, + {[]string{subAddr}, []string{}, []string{}}, + } + + templates := []struct { + name string + planMode types.SELECTED_PROVIDERS_MODE + subMode types.SELECTED_PROVIDERS_MODE + projMode types.SELECTED_PROVIDERS_MODE + providerSet int + planPolicyValid bool + subPolicyValid bool + projPolicyValid bool + }{ + {"ALLOWED mode happy flow", allowed, allowed, allowed, 0, true, true, true}, + {"ALLOWED mode non empty providers list", allowed, allowed, allowed, 1, false, false, false}, + + {"EXCLUSIVE mode happy flow", exclusive, exclusive, exclusive, 2, true, true, true}, + {"EXCLUSIVE mode invalid providers addresses", exclusive, exclusive, exclusive, 3, false, false, false}, + {"EXCLUSIVE mode providers addresses duplicates", exclusive, exclusive, exclusive, 4, false, false, false}, + + {"MIXED mode happy flow", mixed, mixed, mixed, 2, true, true, true}, + {"MIXED mode invalid providers addresses", mixed, mixed, mixed, 3, false, false, false}, + {"MIXED mode providers addresses duplicates", mixed, mixed, mixed, 4, false, false, false}, + + {"DISABLED mode happy flow", disabled, mixed, mixed, 0, true, true, true}, + {"DISABLED mode non empty providers list", disabled, mixed, mixed, 5, false, true, true}, + {"DISABLED mode configured to proj/sub policy", mixed, disabled, disabled, 2, true, false, false}, + } + + for _, tt := range templates { + t.Run(tt.name, func(t *testing.T) { + providersSet := providersSets[tt.providerSet] + plan := common.CreateMockPlan() + + plan.PlanPolicy.SelectedProvidersMode = tt.planMode + plan.PlanPolicy.SelectedProviders = providersSet.planProviders + + err := testkeeper.SimulatePlansAddProposal(ctx, keepers.Plans, []planstypes.Plan{plan}) + if tt.planPolicyValid { + require.Nil(t, err) + } else { + require.NotNil(t, err) + } + + _, err = servers.SubscriptionServer.Buy(_ctx, &subscriptiontypes.MsgBuy{ + Creator: subAddr, + Consumer: subAddr, + Index: plan.Index, + Duration: 1, + }) + require.Nil(t, err) + + subProjects, err := keepers.Subscription.ListProjects(_ctx, &subscriptiontypes.QueryListProjectsRequest{ + Subscription: subAddr, + }) + require.Nil(t, err) + require.Equal(t, 1, len(subProjects.Projects)) + + adminProject, err := keepers.Projects.GetProjectForBlock(ctx, subProjects.Projects[0], uint64(ctx.BlockHeight())) + require.Nil(t, err) + + projPolicy.SelectedProvidersMode = tt.projMode + projPolicy.SelectedProviders = providersSet.projProviders + + _, err = servers.ProjectServer.SetPolicy(_ctx, &types.MsgSetPolicy{ + Creator: subAddr, + Project: adminProject.Index, + Policy: *projPolicy, + }) + if tt.projPolicyValid { + require.Nil(t, err) + } else { + require.NotNil(t, err) + } + + projPolicy.SelectedProvidersMode = tt.subMode + projPolicy.SelectedProviders = providersSet.subProviders + + _, err = servers.ProjectServer.SetSubscriptionPolicy(_ctx, &types.MsgSetSubscriptionPolicy{ + Creator: subAddr, + Projects: []string{adminProject.Index}, + Policy: *projPolicy, + }) + if tt.subPolicyValid { + require.Nil(t, err) + } else { + require.NotNil(t, err) + } + }) + } +} diff --git a/x/projects/types/errors.go b/x/projects/types/errors.go index 116a1e31dc..3903b41ae4 100644 --- a/x/projects/types/errors.go +++ b/x/projects/types/errors.go @@ -13,4 +13,5 @@ var ( ErrInvalidPolicy = sdkerrors.Register(ModuleName, 1102, "Invalid policy") ErrPolicyBasicValidation = sdkerrors.Register(ModuleName, 1100, "invalid policy") ErrInvalidKeyType = sdkerrors.Register(ModuleName, 1103, "invalid project key type") + ErrInvalidSelectedProvidersConfig = sdkerrors.Register(ModuleName, 1104, "plan's selected providers config is invalid") ) diff --git a/x/projects/types/policy.go b/x/projects/types/policy.go index a7d276878a..a8f4fc90a5 100644 --- a/x/projects/types/policy.go +++ b/x/projects/types/policy.go @@ -1,6 +1,7 @@ package types import ( + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -18,15 +19,52 @@ func (policy *Policy) ContainsChainID(chainID string) bool { return false } -func (policy Policy) ValidateBasicPolicy() error { +func (policy Policy) ValidateBasicPolicy(isPlanPolicy bool) error { + // plan policy checks + if isPlanPolicy { + if policy.EpochCuLimit == 0 || policy.TotalCuLimit == 0 { + return sdkerrors.Wrapf(ErrInvalidPolicyCuFields, `plan's compute units fields can't be zero + (EpochCuLimit = %v, TotalCuLimit = %v)`, policy.EpochCuLimit, policy.TotalCuLimit) + } + + if policy.SelectedProvidersMode == 3 && len(policy.SelectedProviders) != 0 { + return sdkerrors.Wrap(ErrInvalidSelectedProvidersConfig, `cannot configure mode = 3 (selected + providers feature is disabled) and non-empty list of selected providers`) + } + + // non-plan policy checks + } else if policy.SelectedProvidersMode == 3 { + return sdkerrors.Wrap(ErrInvalidSelectedProvidersConfig, `cannot configure mode = 3 (selected + providers feature is disabled) for a policy that is not plan policy`) + } + + // general policy checks if policy.EpochCuLimit > policy.TotalCuLimit { - return sdkerrors.Wrapf(ErrInvalidPolicyCuFields, "invalid policy's CU fields (EpochCuLimit = %v, TotalCuLimit = %v)", policy.EpochCuLimit, policy.TotalCuLimit) + return sdkerrors.Wrapf(ErrInvalidPolicyCuFields, "EpochCuLimit can't be larger than TotalCuLimit (EpochCuLimit = %v, TotalCuLimit = %v)", policy.EpochCuLimit, policy.TotalCuLimit) } if policy.MaxProvidersToPair <= 1 { return sdkerrors.Wrapf(ErrInvalidPolicyMaxProvidersToPair, "invalid policy's MaxProvidersToPair fields (MaxProvidersToPair = %v)", policy.MaxProvidersToPair) } + if policy.SelectedProvidersMode == 0 && len(policy.SelectedProviders) != 0 { + return sdkerrors.Wrap(ErrInvalidSelectedProvidersConfig, `cannot configure mode = 0 (no + providers restrictions) and non-empty list of selected providers`) + } + + seen := map[string]bool{} + for _, addr := range policy.SelectedProviders { + _, err := sdk.AccAddressFromBech32(addr) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid selected provider address (%s)", err) + } + + if seen[addr] { + return sdkerrors.Wrapf(ErrInvalidSelectedProvidersConfig, "found duplicate provider address %s", addr) + } + seen[addr] = true + } + return nil } diff --git a/x/projects/types/project.pb.go b/x/projects/types/project.pb.go index 94a4b3d0db..c66f0e23aa 100644 --- a/x/projects/types/project.pb.go +++ b/x/projects/types/project.pb.go @@ -23,6 +23,38 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// the enum below determines the pairing algorithm's behaviour with the selected providers feature +type SELECTED_PROVIDERS_MODE int32 + +const ( + SELECTED_PROVIDERS_MODE_ALLOWED SELECTED_PROVIDERS_MODE = 0 + SELECTED_PROVIDERS_MODE_MIXED SELECTED_PROVIDERS_MODE = 1 + SELECTED_PROVIDERS_MODE_EXCLUSIVE SELECTED_PROVIDERS_MODE = 2 + SELECTED_PROVIDERS_MODE_DISABLED SELECTED_PROVIDERS_MODE = 3 +) + +var SELECTED_PROVIDERS_MODE_name = map[int32]string{ + 0: "ALLOWED", + 1: "MIXED", + 2: "EXCLUSIVE", + 3: "DISABLED", +} + +var SELECTED_PROVIDERS_MODE_value = map[string]int32{ + "ALLOWED": 0, + "MIXED": 1, + "EXCLUSIVE": 2, + "DISABLED": 3, +} + +func (x SELECTED_PROVIDERS_MODE) String() string { + return proto.EnumName(SELECTED_PROVIDERS_MODE_name, int32(x)) +} + +func (SELECTED_PROVIDERS_MODE) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_9f89a31663a330ce, []int{0} +} + type ProjectKey_Type int32 const ( @@ -205,11 +237,13 @@ func (m *ProjectKey) GetKinds() uint32 { // protobuf expected in YAML format: used "moretags" to simplify parsing type Policy struct { - ChainPolicies []ChainPolicy `protobuf:"bytes,1,rep,name=chain_policies,json=chainPolicies,proto3" json:"chain_policies" mapstructure:"chain_policies"` - GeolocationProfile uint64 `protobuf:"varint,2,opt,name=geolocation_profile,json=geolocationProfile,proto3" json:"geolocation_profile" mapstructure:"geolocation_profile"` - TotalCuLimit uint64 `protobuf:"varint,3,opt,name=total_cu_limit,json=totalCuLimit,proto3" json:"total_cu_limit" mapstructure:"total_cu_limit"` - EpochCuLimit uint64 `protobuf:"varint,4,opt,name=epoch_cu_limit,json=epochCuLimit,proto3" json:"epoch_cu_limit" mapstructure:"epoch_cu_limit"` - MaxProvidersToPair uint64 `protobuf:"varint,5,opt,name=max_providers_to_pair,json=maxProvidersToPair,proto3" json:"max_providers_to_pair" mapstructure:"max_providers_to_pair"` + ChainPolicies []ChainPolicy `protobuf:"bytes,1,rep,name=chain_policies,json=chainPolicies,proto3" json:"chain_policies" mapstructure:"chain_policies"` + GeolocationProfile uint64 `protobuf:"varint,2,opt,name=geolocation_profile,json=geolocationProfile,proto3" json:"geolocation_profile" mapstructure:"geolocation_profile"` + TotalCuLimit uint64 `protobuf:"varint,3,opt,name=total_cu_limit,json=totalCuLimit,proto3" json:"total_cu_limit" mapstructure:"total_cu_limit"` + EpochCuLimit uint64 `protobuf:"varint,4,opt,name=epoch_cu_limit,json=epochCuLimit,proto3" json:"epoch_cu_limit" mapstructure:"epoch_cu_limit"` + MaxProvidersToPair uint64 `protobuf:"varint,5,opt,name=max_providers_to_pair,json=maxProvidersToPair,proto3" json:"max_providers_to_pair" mapstructure:"max_providers_to_pair"` + SelectedProvidersMode SELECTED_PROVIDERS_MODE `protobuf:"varint,6,opt,name=selected_providers_mode,json=selectedProvidersMode,proto3,enum=lavanet.lava.projects.SELECTED_PROVIDERS_MODE" json:"selected_providers_mode" mapstructure:"selected_providers_mode"` + SelectedProviders []string `protobuf:"bytes,7,rep,name=selected_providers,json=selectedProviders,proto3" json:"selected_providers" mapstructure:"selected_providers"` } func (m *Policy) Reset() { *m = Policy{} } @@ -280,6 +314,20 @@ func (m *Policy) GetMaxProvidersToPair() uint64 { return 0 } +func (m *Policy) GetSelectedProvidersMode() SELECTED_PROVIDERS_MODE { + if m != nil { + return m.SelectedProvidersMode + } + return SELECTED_PROVIDERS_MODE_ALLOWED +} + +func (m *Policy) GetSelectedProviders() []string { + if m != nil { + return m.SelectedProviders + } + return nil +} + type ChainPolicy struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty" mapstructure:"chain_id"` Apis []string `protobuf:"bytes,2,rep,name=apis,proto3" json:"apis,omitempty" mapstructure:"apis"` @@ -446,6 +494,7 @@ func (m *ProjectData) GetPolicy() *Policy { } func init() { + proto.RegisterEnum("lavanet.lava.projects.SELECTED_PROVIDERS_MODE", SELECTED_PROVIDERS_MODE_name, SELECTED_PROVIDERS_MODE_value) proto.RegisterEnum("lavanet.lava.projects.ProjectKey_Type", ProjectKey_Type_name, ProjectKey_Type_value) proto.RegisterType((*Project)(nil), "lavanet.lava.projects.Project") proto.RegisterType((*ProjectKey)(nil), "lavanet.lava.projects.ProjectKey") @@ -458,54 +507,64 @@ func init() { func init() { proto.RegisterFile("projects/project.proto", fileDescriptor_9f89a31663a330ce) } var fileDescriptor_9f89a31663a330ce = []byte{ - // 750 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4f, 0x6b, 0xe3, 0x46, - 0x14, 0xb7, 0x6c, 0xf9, 0xdf, 0xb3, 0x13, 0xcc, 0x24, 0x69, 0x44, 0xda, 0x58, 0xee, 0xd0, 0x82, - 0xe9, 0xc1, 0x86, 0x84, 0x96, 0x52, 0x28, 0x34, 0x8e, 0x5d, 0x70, 0x9a, 0x3a, 0x46, 0x84, 0x42, - 0x7b, 0x31, 0x63, 0x69, 0x6a, 0x4f, 0x23, 0x6b, 0x84, 0xfe, 0x18, 0xfb, 0x5b, 0xf4, 0xb4, 0x9f, - 0x61, 0xbf, 0xc7, 0x5e, 0x72, 0xcc, 0x71, 0x4f, 0x62, 0x71, 0x6e, 0x39, 0xfa, 0xb0, 0xe7, 0x45, - 0x23, 0xf9, 0x8f, 0x36, 0x0e, 0x04, 0xf6, 0xa4, 0x79, 0xef, 0xfd, 0xde, 0xfb, 0xcd, 0x9b, 0xf7, - 0xf4, 0x83, 0xaf, 0x6c, 0x87, 0xff, 0x47, 0x75, 0xcf, 0x6d, 0xc6, 0x87, 0x86, 0xed, 0x70, 0x8f, - 0xa3, 0x23, 0x93, 0x4c, 0x89, 0x45, 0xbd, 0x46, 0xf8, 0x6d, 0xac, 0x40, 0x27, 0x87, 0x23, 0x3e, - 0xe2, 0x02, 0xd1, 0x0c, 0x4f, 0x11, 0x18, 0x7f, 0x4c, 0x43, 0xbe, 0x1f, 0x41, 0xd0, 0x21, 0x64, - 0x99, 0x65, 0xd0, 0x99, 0x22, 0xd5, 0xa4, 0x7a, 0x51, 0x8b, 0x0c, 0x84, 0xa1, 0xec, 0xfa, 0x43, - 0x57, 0x77, 0x98, 0xed, 0x31, 0x6e, 0x29, 0x69, 0x11, 0x4c, 0xf8, 0x90, 0x02, 0x79, 0x6a, 0x91, - 0xa1, 0x49, 0x0d, 0x45, 0xae, 0x49, 0xf5, 0x82, 0xb6, 0x32, 0xd1, 0x15, 0x94, 0xe3, 0x1b, 0x0c, - 0xee, 0xe8, 0xdc, 0x55, 0xb2, 0xb5, 0x4c, 0xbd, 0x74, 0xf6, 0x6d, 0x63, 0xe7, 0x1d, 0x1b, 0xf1, - 0x4d, 0xfe, 0xa0, 0xf3, 0x96, 0x7c, 0x1f, 0xa8, 0x29, 0xad, 0x64, 0xaf, 0x3d, 0x2e, 0xfa, 0x0d, - 0xca, 0xc4, 0x98, 0x30, 0x6b, 0x60, 0x73, 0x93, 0xe9, 0x73, 0x25, 0x57, 0x93, 0xea, 0xa5, 0xb3, - 0xd3, 0x97, 0x6a, 0x09, 0x90, 0x56, 0x12, 0x29, 0x91, 0x81, 0x8e, 0x21, 0xef, 0xbb, 0xd4, 0x18, - 0xe8, 0xbe, 0x92, 0xaf, 0x49, 0x75, 0x59, 0xcb, 0x85, 0xe6, 0xa5, 0x8f, 0x7a, 0x70, 0xb0, 0xdd, - 0xd0, 0x8a, 0xa1, 0xf0, 0x1a, 0x06, 0xb4, 0x9d, 0x19, 0x13, 0x9d, 0x40, 0xc1, 0xb5, 0x88, 0xed, - 0x8e, 0xb9, 0xa7, 0x14, 0x05, 0xd3, 0xda, 0xbe, 0x92, 0x0b, 0x99, 0x8a, 0x8c, 0x4d, 0x80, 0x4d, - 0xb7, 0xa8, 0x02, 0x99, 0x3b, 0x3a, 0x8f, 0x1f, 0x3e, 0x3c, 0x86, 0xc3, 0xb8, 0x63, 0x96, 0xe1, - 0x8a, 0x07, 0xdd, 0xd3, 0x22, 0x03, 0xff, 0x00, 0xf2, 0xed, 0xdc, 0xa6, 0xa8, 0x00, 0x72, 0xef, - 0xa6, 0xd7, 0xa9, 0xa4, 0x50, 0x11, 0xb2, 0x17, 0xed, 0x3f, 0xbb, 0xbd, 0x8a, 0x84, 0xf6, 0xa0, - 0xd8, 0xee, 0xfc, 0xd5, 0xb9, 0xbe, 0xe9, 0x77, 0xb4, 0x4a, 0xfa, 0x4a, 0x2e, 0xa4, 0x2b, 0x99, - 0x98, 0xed, 0x8d, 0x0c, 0xb9, 0xf8, 0x6a, 0x36, 0xec, 0xeb, 0x63, 0xb2, 0x7a, 0x45, 0x46, 0x5d, - 0x45, 0x12, 0x33, 0xc1, 0x2f, 0x74, 0x79, 0x19, 0x82, 0xa3, 0xdc, 0xd6, 0xf7, 0xe1, 0x50, 0x96, - 0x81, 0x7a, 0x3a, 0x21, 0xb6, 0xeb, 0x39, 0xbe, 0xee, 0xf9, 0x0e, 0xfd, 0x05, 0x27, 0xeb, 0x61, - 0x6d, 0x4f, 0x5f, 0xe7, 0x30, 0xea, 0x22, 0x0b, 0x0e, 0x46, 0x94, 0x9b, 0x5c, 0x27, 0xd1, 0xdb, - 0x3a, 0xfc, 0x5f, 0x66, 0x52, 0xb1, 0x48, 0x72, 0xeb, 0xd7, 0xa7, 0x40, 0xdd, 0x15, 0x5e, 0x06, - 0x2a, 0x4e, 0xb2, 0xec, 0x00, 0x61, 0x0d, 0x6d, 0x79, 0xfb, 0x91, 0x13, 0xfd, 0x0d, 0xfb, 0x1e, - 0xf7, 0x88, 0x39, 0xd0, 0xfd, 0x81, 0xc9, 0x26, 0xcc, 0x53, 0x32, 0x82, 0xea, 0xfc, 0x29, 0x50, - 0x3f, 0x8b, 0x3c, 0xef, 0x25, 0x19, 0xc7, 0x5a, 0x59, 0x38, 0x2e, 0xfd, 0xeb, 0xd0, 0x0c, 0x4b, - 0x53, 0x9b, 0xeb, 0xe3, 0x4d, 0x69, 0x79, 0x53, 0x3a, 0x19, 0x79, 0x5e, 0x3a, 0x19, 0xc7, 0x5a, - 0x59, 0x38, 0x56, 0xa5, 0x3d, 0x38, 0x9a, 0x90, 0x59, 0xd8, 0xd9, 0x94, 0x19, 0xd4, 0x71, 0x07, - 0x1e, 0x1f, 0xd8, 0x84, 0x39, 0x4a, 0x56, 0x30, 0x5c, 0x3c, 0x05, 0xea, 0x6e, 0xc0, 0x32, 0x50, - 0xbf, 0x4b, 0x12, 0xed, 0x84, 0x61, 0x0d, 0x4d, 0xc8, 0xac, 0xbf, 0x72, 0xdf, 0xf2, 0x7e, 0xe8, - 0x9c, 0x42, 0x69, 0x6b, 0xc0, 0xe8, 0x27, 0x28, 0x44, 0xc3, 0x64, 0x46, 0xb4, 0x8c, 0xad, 0xaf, - 0x97, 0x81, 0x7a, 0xbc, 0x6b, 0xdc, 0xcc, 0xc0, 0x5a, 0x5e, 0x1c, 0xbb, 0x06, 0x6a, 0x82, 0x4c, - 0x6c, 0xe6, 0x2a, 0xe9, 0x5a, 0x26, 0xcc, 0x89, 0xd7, 0xe4, 0x20, 0x99, 0x17, 0x22, 0xb0, 0x26, - 0x80, 0xf8, 0x67, 0x40, 0xfd, 0x50, 0x80, 0xda, 0x74, 0x4a, 0x4d, 0x6e, 0x53, 0xa7, 0x4d, 0x3c, - 0x82, 0xbe, 0x81, 0x62, 0xbc, 0x77, 0xdd, 0x76, 0xfc, 0x33, 0x6c, 0x1c, 0xd1, 0x42, 0xe3, 0x77, - 0x12, 0x94, 0xe2, 0x3f, 0x47, 0xe4, 0x20, 0x90, 0x2d, 0x32, 0xa1, 0x31, 0x5c, 0x9c, 0xb7, 0xf5, - 0x28, 0x93, 0xd4, 0xa3, 0x2e, 0x6c, 0x4b, 0x8a, 0x22, 0x7f, 0x81, 0x1c, 0xfd, 0x08, 0xb9, 0x58, - 0x26, 0xb2, 0xaf, 0x91, 0x89, 0x18, 0x1c, 0x75, 0xd1, 0xfa, 0xfd, 0xed, 0xa2, 0x2a, 0xdd, 0x2f, - 0xaa, 0xd2, 0xc3, 0xa2, 0x2a, 0x7d, 0x58, 0x54, 0xa5, 0xff, 0x1f, 0xab, 0xa9, 0x87, 0xc7, 0x6a, - 0xea, 0xfd, 0x63, 0x35, 0xf5, 0x4f, 0x7d, 0xc4, 0xbc, 0xb1, 0x3f, 0x6c, 0xe8, 0x7c, 0xd2, 0x8c, - 0x8b, 0x8a, 0x6f, 0x73, 0xd6, 0x5c, 0x8b, 0xbe, 0x37, 0xb7, 0xa9, 0x3b, 0xcc, 0x09, 0x19, 0x3f, - 0xff, 0x14, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x50, 0x6f, 0x75, 0x0d, 0x06, 0x00, 0x00, + // 897 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0x8f, 0x13, 0xe7, 0xdf, 0x4b, 0x5a, 0x85, 0xe9, 0x96, 0x5a, 0xbb, 0x6c, 0x9c, 0x1d, 0x01, + 0x8a, 0xf6, 0x90, 0x48, 0x5d, 0x81, 0x10, 0x08, 0x89, 0x26, 0x36, 0x52, 0x4a, 0x9a, 0x44, 0xd3, + 0x52, 0x16, 0x2e, 0x91, 0x6b, 0x0f, 0xed, 0x6c, 0x9d, 0x8c, 0xe5, 0x3f, 0x55, 0xf3, 0x2d, 0xf8, + 0x18, 0x5c, 0xb8, 0xf0, 0x15, 0xb8, 0xec, 0x71, 0x8f, 0x9c, 0x2c, 0xd4, 0xde, 0x72, 0xcc, 0x81, + 0x33, 0xf2, 0xd8, 0x49, 0x63, 0x9a, 0x88, 0x95, 0x38, 0x79, 0xde, 0x7b, 0xbf, 0xf7, 0x7e, 0xef, + 0xcd, 0x9f, 0x9f, 0xe1, 0x43, 0xc7, 0xe5, 0x6f, 0xa8, 0xe9, 0x7b, 0xed, 0x64, 0xd1, 0x72, 0x5c, + 0xee, 0x73, 0xb4, 0x6f, 0x1b, 0x37, 0xc6, 0x94, 0xfa, 0xad, 0xe8, 0xdb, 0x5a, 0x82, 0x9e, 0x3e, + 0xb9, 0xe4, 0x97, 0x5c, 0x20, 0xda, 0xd1, 0x2a, 0x06, 0xe3, 0xbf, 0xb3, 0x50, 0x1c, 0xc5, 0x10, + 0xf4, 0x04, 0xf2, 0x6c, 0x6a, 0xd1, 0x5b, 0x45, 0x6a, 0x48, 0xcd, 0x32, 0x89, 0x0d, 0x84, 0xa1, + 0xea, 0x05, 0x17, 0x9e, 0xe9, 0x32, 0xc7, 0x67, 0x7c, 0xaa, 0x64, 0x45, 0x30, 0xe5, 0x43, 0x0a, + 0x14, 0xe9, 0xd4, 0xb8, 0xb0, 0xa9, 0xa5, 0xc8, 0x0d, 0xa9, 0x59, 0x22, 0x4b, 0x13, 0x1d, 0x43, + 0x35, 0xe9, 0x60, 0x7c, 0x4d, 0x67, 0x9e, 0x92, 0x6f, 0xe4, 0x9a, 0x95, 0xc3, 0x17, 0xad, 0x8d, + 0x3d, 0xb6, 0x92, 0x4e, 0xbe, 0xa3, 0xb3, 0x8e, 0xfc, 0x36, 0x54, 0x33, 0xa4, 0xe2, 0xac, 0x3c, + 0x1e, 0xfa, 0x06, 0xaa, 0x86, 0x35, 0x61, 0xd3, 0xb1, 0xc3, 0x6d, 0x66, 0xce, 0x94, 0x42, 0x43, + 0x6a, 0x56, 0x0e, 0x9f, 0x6f, 0xab, 0x25, 0x40, 0xa4, 0x22, 0x52, 0x62, 0x03, 0x1d, 0x40, 0x31, + 0xf0, 0xa8, 0x35, 0x36, 0x03, 0xa5, 0xd8, 0x90, 0x9a, 0x32, 0x29, 0x44, 0x66, 0x37, 0x40, 0x03, + 0xd8, 0x5b, 0x1f, 0x68, 0xc9, 0x50, 0x7a, 0x1f, 0x06, 0xb4, 0x9e, 0x99, 0x10, 0x3d, 0x85, 0x92, + 0x37, 0x35, 0x1c, 0xef, 0x8a, 0xfb, 0x4a, 0x59, 0x30, 0xad, 0xec, 0x63, 0xb9, 0x94, 0xab, 0xc9, + 0xd8, 0x06, 0x78, 0x98, 0x16, 0xd5, 0x20, 0x77, 0x4d, 0x67, 0xc9, 0xc6, 0x47, 0xcb, 0xe8, 0x30, + 0xae, 0xd9, 0xd4, 0xf2, 0xc4, 0x86, 0xee, 0x90, 0xd8, 0xc0, 0x2f, 0x41, 0x3e, 0x9b, 0x39, 0x14, + 0x95, 0x40, 0x1e, 0x0c, 0x07, 0x7a, 0x2d, 0x83, 0xca, 0x90, 0x3f, 0xd2, 0x4e, 0x7a, 0x83, 0x9a, + 0x84, 0x76, 0xa0, 0xac, 0xe9, 0xe7, 0x7a, 0x7f, 0x38, 0xd2, 0x49, 0x2d, 0x7b, 0x2c, 0x97, 0xb2, + 0xb5, 0x5c, 0xc2, 0xf6, 0x7b, 0x01, 0x0a, 0x49, 0x6b, 0x0e, 0xec, 0x9a, 0x57, 0xc6, 0x72, 0x17, + 0x19, 0xf5, 0x14, 0x49, 0x9c, 0x09, 0xde, 0x32, 0x65, 0x37, 0x02, 0xc7, 0xb9, 0x9d, 0x4f, 0xa2, + 0x43, 0x59, 0x84, 0xea, 0xf3, 0x89, 0xe1, 0x78, 0xbe, 0x1b, 0x98, 0x7e, 0xe0, 0xd2, 0x2f, 0x71, + 0xba, 0x1e, 0x26, 0x3b, 0xe6, 0x2a, 0x87, 0x51, 0x0f, 0x4d, 0x61, 0xef, 0x92, 0x72, 0x9b, 0x9b, + 0x46, 0xbc, 0xb7, 0x2e, 0xff, 0x99, 0xd9, 0x54, 0x5c, 0x24, 0xb9, 0xf3, 0xf5, 0x3c, 0x54, 0x37, + 0x85, 0x17, 0xa1, 0x8a, 0xd3, 0x2c, 0x1b, 0x40, 0x98, 0xa0, 0x35, 0xef, 0x28, 0x76, 0xa2, 0x1f, + 0x61, 0xd7, 0xe7, 0xbe, 0x61, 0x8f, 0xcd, 0x60, 0x6c, 0xb3, 0x09, 0xf3, 0x95, 0x9c, 0xa0, 0x7a, + 0x35, 0x0f, 0xd5, 0x7f, 0x45, 0x1e, 0xcf, 0x92, 0x8e, 0x63, 0x52, 0x15, 0x8e, 0x6e, 0xd0, 0x8f, + 0xcc, 0xa8, 0x34, 0x75, 0xb8, 0x79, 0xf5, 0x50, 0x5a, 0x7e, 0x28, 0x9d, 0x8e, 0x3c, 0x2e, 0x9d, + 0x8e, 0x63, 0x52, 0x15, 0x8e, 0x65, 0x69, 0x1f, 0xf6, 0x27, 0xc6, 0x6d, 0x34, 0xd9, 0x0d, 0xb3, + 0xa8, 0xeb, 0x8d, 0x7d, 0x3e, 0x76, 0x0c, 0xe6, 0x2a, 0x79, 0xc1, 0x70, 0x34, 0x0f, 0xd5, 0xcd, + 0x80, 0x45, 0xa8, 0x7e, 0x9c, 0x26, 0xda, 0x08, 0xc3, 0x04, 0x4d, 0x8c, 0xdb, 0xd1, 0xd2, 0x7d, + 0xc6, 0x47, 0x06, 0x73, 0xd1, 0x6f, 0x12, 0x1c, 0x78, 0xd4, 0xa6, 0xa6, 0x4f, 0xad, 0xb5, 0x9c, + 0x09, 0xb7, 0xa8, 0x78, 0x5f, 0xbb, 0x87, 0xad, 0x2d, 0xf7, 0xe2, 0x54, 0xef, 0xeb, 0xdd, 0x33, + 0x5d, 0x1b, 0x8f, 0xc8, 0xf0, 0xbc, 0xa7, 0xe9, 0xe4, 0x74, 0x7c, 0x32, 0xd4, 0xf4, 0x8e, 0x3e, + 0x0f, 0xd5, 0x6d, 0x25, 0x17, 0xa1, 0xfa, 0x69, 0xba, 0xd5, 0x2d, 0x40, 0x4c, 0xf6, 0x97, 0x91, + 0x55, 0xc7, 0x27, 0xdc, 0xa2, 0xe8, 0x0d, 0xa0, 0xc7, 0x29, 0x4a, 0xb1, 0x91, 0x6b, 0x96, 0x3b, + 0x5f, 0xcd, 0x43, 0x75, 0x43, 0x74, 0x11, 0xaa, 0x2f, 0xfe, 0x8b, 0x14, 0x93, 0x0f, 0x1e, 0xf1, + 0xe1, 0x1b, 0xa8, 0xac, 0x5d, 0x7e, 0xf4, 0x39, 0x94, 0xe2, 0x8b, 0xce, 0xac, 0xf8, 0xa1, 0x76, + 0x9e, 0x2d, 0x42, 0xf5, 0x60, 0xd3, 0x53, 0x60, 0x16, 0x26, 0x45, 0xb1, 0xec, 0x59, 0xa8, 0x0d, + 0xb2, 0xe1, 0x30, 0x4f, 0xc9, 0x8a, 0x26, 0x9f, 0x25, 0x4f, 0x68, 0x2f, 0x9d, 0x17, 0x21, 0x30, + 0x11, 0x40, 0xfc, 0x05, 0xa0, 0x51, 0x24, 0xce, 0x1a, 0xbd, 0xa1, 0x36, 0x77, 0xa8, 0xab, 0x19, + 0xbe, 0x81, 0x3e, 0x82, 0x72, 0xb2, 0xf7, 0x3d, 0x2d, 0x11, 0x8a, 0x07, 0x47, 0xfc, 0xd8, 0xf1, + 0x1f, 0x12, 0x54, 0x12, 0x55, 0x11, 0x39, 0x08, 0xe4, 0xa9, 0x31, 0xa1, 0x09, 0x5c, 0xac, 0xd7, + 0xb5, 0x3a, 0x97, 0xd6, 0xea, 0x1e, 0xac, 0xcb, 0xad, 0x22, 0xff, 0x0f, 0xa9, 0xfe, 0x0c, 0x0a, + 0x89, 0x84, 0xe6, 0xdf, 0x47, 0x42, 0x13, 0x70, 0x3c, 0xc5, 0xcb, 0x01, 0x1c, 0x6c, 0xb9, 0x5c, + 0xa8, 0x02, 0xc5, 0xa3, 0x7e, 0x7f, 0xf8, 0x83, 0xae, 0xc5, 0xd2, 0x77, 0xd2, 0x7b, 0xad, 0x6b, + 0xb1, 0xf4, 0xe9, 0xaf, 0xbb, 0xfd, 0xef, 0x4f, 0x7b, 0xe7, 0x7a, 0x2d, 0x8b, 0xaa, 0x50, 0xd2, + 0x7a, 0xa7, 0x47, 0x9d, 0xbe, 0xae, 0xd5, 0x72, 0x9d, 0x6f, 0x7f, 0xbd, 0xab, 0x4b, 0x6f, 0xef, + 0xea, 0xd2, 0xbb, 0xbb, 0xba, 0xf4, 0xd7, 0x5d, 0x5d, 0xfa, 0xe5, 0xbe, 0x9e, 0x79, 0x77, 0x5f, + 0xcf, 0xfc, 0x79, 0x5f, 0xcf, 0xfc, 0xd4, 0xbc, 0x64, 0xfe, 0x55, 0x70, 0xd1, 0x32, 0xf9, 0xa4, + 0x9d, 0x34, 0x29, 0xbe, 0xed, 0xdb, 0xf6, 0xea, 0x07, 0xeb, 0xcf, 0x1c, 0xea, 0x5d, 0x14, 0xc4, + 0x2f, 0xf3, 0xd5, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x0b, 0xfe, 0x8d, 0x79, 0x07, 0x00, + 0x00, } func (this *Project) Equal(that interface{}) bool { @@ -624,6 +683,17 @@ func (this *Policy) Equal(that interface{}) bool { if this.MaxProvidersToPair != that1.MaxProvidersToPair { return false } + if this.SelectedProvidersMode != that1.SelectedProvidersMode { + return false + } + if len(this.SelectedProviders) != len(that1.SelectedProviders) { + return false + } + for i := range this.SelectedProviders { + if this.SelectedProviders[i] != that1.SelectedProviders[i] { + return false + } + } return true } func (this *ChainPolicy) Equal(that interface{}) bool { @@ -870,6 +940,20 @@ func (m *Policy) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.SelectedProviders) > 0 { + for iNdEx := len(m.SelectedProviders) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SelectedProviders[iNdEx]) + copy(dAtA[i:], m.SelectedProviders[iNdEx]) + i = encodeVarintProject(dAtA, i, uint64(len(m.SelectedProviders[iNdEx]))) + i-- + dAtA[i] = 0x3a + } + } + if m.SelectedProvidersMode != 0 { + i = encodeVarintProject(dAtA, i, uint64(m.SelectedProvidersMode)) + i-- + dAtA[i] = 0x30 + } if m.MaxProvidersToPair != 0 { i = encodeVarintProject(dAtA, i, uint64(m.MaxProvidersToPair)) i-- @@ -1133,6 +1217,15 @@ func (m *Policy) Size() (n int) { if m.MaxProvidersToPair != 0 { n += 1 + sovProject(uint64(m.MaxProvidersToPair)) } + if m.SelectedProvidersMode != 0 { + n += 1 + sovProject(uint64(m.SelectedProvidersMode)) + } + if len(m.SelectedProviders) > 0 { + for _, s := range m.SelectedProviders { + l = len(s) + n += 1 + l + sovProject(uint64(l)) + } + } return n } @@ -1718,6 +1811,57 @@ func (m *Policy) Unmarshal(dAtA []byte) error { break } } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SelectedProvidersMode", wireType) + } + m.SelectedProvidersMode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProject + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SelectedProvidersMode |= SELECTED_PROVIDERS_MODE(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SelectedProviders", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProject + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProject + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProject + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SelectedProviders = append(m.SelectedProviders, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipProject(dAtA[iNdEx:]) diff --git a/x/projects/types/types.go b/x/projects/types/types.go index 05c76964d3..96580dcff3 100644 --- a/x/projects/types/types.go +++ b/x/projects/types/types.go @@ -1,5 +1,10 @@ package types +import ( + "bytes" + "encoding/json" +) + const ( MAX_PROJECT_NAME_LEN = 50 ) @@ -16,3 +21,23 @@ const ( AddProjectKeyEventName = "add_key_to_project_event" DelProjectKeyEventName = "del_key_from_project_event" ) + +// allows unmarshaling parser func +func (s SELECTED_PROVIDERS_MODE) MarshalJSON() ([]byte, error) { + buffer := bytes.NewBufferString(`"`) + buffer.WriteString(SELECTED_PROVIDERS_MODE_name[int32(s)]) + buffer.WriteString(`"`) + return buffer.Bytes(), nil +} + +// UnmarshalJSON unmashals a quoted json string to the enum value +func (s *SELECTED_PROVIDERS_MODE) UnmarshalJSON(b []byte) error { + var j string + err := json.Unmarshal(b, &j) + if err != nil { + return err + } + // Note that if the string cannot be found then it will be set to the zero value, 'Created' in this case. + *s = SELECTED_PROVIDERS_MODE(SELECTED_PROVIDERS_MODE_value[j]) + return nil +}