diff --git a/Cargo.lock b/Cargo.lock index ebe6bf8..b1ba340 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,32 +328,13 @@ dependencies = [ "cw-storage-plus 0.14.0", "cw-utils 0.14.0", "derivative", - "itertools 0.10.5", - "prost 0.9.0", + "itertools", + "prost", "schemars", "serde", "thiserror", ] -[[package]] -name = "cw-multi-test" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e2c2f2c0877b839c5cad85e67811074e854a50c1ff3085eb8290b1c27809c" -dependencies = [ - "anyhow", - "cosmwasm-std", - "cw-storage-plus 1.2.0", - "cw-utils 1.0.3", - "derivative", - "itertools 0.11.0", - "prost 0.12.3", - "schemars", - "serde", - "sha2 0.10.8", - "thiserror", -] - [[package]] name = "cw-storage-gas-meter" version = "1.0.0" @@ -487,7 +468,7 @@ checksum = "c434e2509b361075f867323f7edba3aa77860c93f75a0d426d1747104144ca90" dependencies = [ "anyhow", "cosmwasm-std", - "cw-multi-test 0.14.0", + "cw-multi-test", "cw-storage-plus 0.14.0", "cyber-std", "schemars", @@ -497,11 +478,11 @@ dependencies = [ [[package]] name = "cybernet" -version = "0.2.0" +version = "0.3.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-multi-test 0.18.0", + "cw-multi-test", "cw-storage-gas-meter", "cw-storage-plus 1.2.0", "cw-utils 1.0.3", @@ -782,15 +763,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.9" @@ -992,17 +964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ "bytes", - "prost-derive 0.9.0", -] - -[[package]] -name = "prost" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" -dependencies = [ - "bytes", - "prost-derive 0.12.3", + "prost-derive", ] [[package]] @@ -1012,25 +974,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools", "proc-macro2", "quote", "syn 1.0.109", ] -[[package]] -name = "prost-derive" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" -dependencies = [ - "anyhow", - "itertools 0.11.0", - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "quote" version = "1.0.33" diff --git a/Cargo.toml b/Cargo.toml index e9468c4..d804bc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cybernet" -version = "0.2.0" +version = "0.3.0" authors = ["C H "] edition = "2021" @@ -65,7 +65,7 @@ scale-info = { version = "2.0.0", default-features = false } cyber-std = { version = "0.2.2"} [dev-dependencies] -cw-multi-test = { version = "0.18.0", features = ["iterator"]} +cw-multi-test = { version = "0.14.0", features = ["iterator"]} cyber-std = { version = "0.2.2"} cyber-std-test = { version = "0.2.1"} rand = { version = "0.8.4" } diff --git a/schema/cybernet.json b/schema/cybernet.json index 05e080c..ec7c581 100644 --- a/schema/cybernet.json +++ b/schema/cybernet.json @@ -1,6 +1,6 @@ { "contract_name": "cybernet", - "contract_version": "0.2.0", + "contract_version": "0.3.0", "idl_version": "1.0.0", "instantiate": { "$schema": "http://json-schema.org/draft-07/schema#", @@ -167,6 +167,31 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "set_delegate_commission" + ], + "properties": { + "set_delegate_commission": { + "type": "object", + "required": [ + "commission", + "hotkey" + ], + "properties": { + "commission": { + "type": "string" + }, + "hotkey": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ @@ -1435,10 +1460,37 @@ ], "properties": { "sudo_set_subnet_metadata": { + "type": "object", + "required": [ + "metadata", + "netuid" + ], + "properties": { + "metadata": { + "$ref": "#/definitions/Metadata" + }, + "netuid": { + "type": "integer", + "format": "uint16", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_subnet_owner" + ], + "properties": { + "sudo_set_subnet_owner": { "type": "object", "required": [ "netuid", - "particle" + "new_owner" ], "properties": { "netuid": { @@ -1446,7 +1498,28 @@ "format": "uint16", "minimum": 0.0 }, - "particle": { + "new_owner": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_root" + ], + "properties": { + "sudo_set_root": { + "type": "object", + "required": [ + "new_root" + ], + "properties": { + "new_root": { "type": "string" } }, @@ -1454,9 +1527,105 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_verse_metadata" + ], + "properties": { + "sudo_set_verse_metadata": { + "type": "object", + "required": [ + "metadata" + ], + "properties": { + "metadata": { + "$ref": "#/definitions/Metadata" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_unstake_all" + ], + "properties": { + "sudo_unstake_all": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_commission_change" + ], + "properties": { + "sudo_set_commission_change": { + "type": "object", + "required": [ + "change" + ], + "properties": { + "change": { + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ], "definitions": { + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" @@ -2304,6 +2473,99 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "get_block_rewards" + ], + "properties": { + "get_block_rewards": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_subnet_metadata" + ], + "properties": { + "get_subnet_metadata": { + "type": "object", + "required": [ + "netuid" + ], + "properties": { + "netuid": { + "type": "integer", + "format": "uint16", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_subnets_metadata" + ], + "properties": { + "get_subnets_metadata": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint16", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "integer", + "null" + ], + "format": "uint16", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_verse_metadata" + ], + "properties": { + "get_verse_metadata": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_economy" + ], + "properties": { + "get_economy": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ @@ -2403,6 +2665,29 @@ } } }, + "get_block_rewards": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Coin", + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + }, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } + }, "get_burn": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Nullable_uint64", @@ -2429,6 +2714,21 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, "DelegateInfo": { "type": "object", "required": [ @@ -2436,7 +2736,7 @@ "nominators", "owner", "registrations", - "return_per_1000", + "return_per_giga", "take", "total_daily_return", "validator_permits" @@ -2474,10 +2774,8 @@ "minimum": 0.0 } }, - "return_per_1000": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "return_per_giga": { + "$ref": "#/definitions/Coin" }, "take": { "type": "integer", @@ -2485,9 +2783,7 @@ "minimum": 0.0 }, "total_daily_return": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "$ref": "#/definitions/Coin" }, "validator_permits": { "type": "array", @@ -2499,6 +2795,10 @@ } }, "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } }, @@ -2536,6 +2836,21 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, "DelegateInfo": { "type": "object", "required": [ @@ -2543,7 +2858,7 @@ "nominators", "owner", "registrations", - "return_per_1000", + "return_per_giga", "take", "total_daily_return", "validator_permits" @@ -2581,10 +2896,8 @@ "minimum": 0.0 } }, - "return_per_1000": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "return_per_giga": { + "$ref": "#/definitions/Coin" }, "take": { "type": "integer", @@ -2592,9 +2905,7 @@ "minimum": 0.0 }, "total_daily_return": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "$ref": "#/definitions/Coin" }, "validator_permits": { "type": "array", @@ -2606,6 +2917,10 @@ } }, "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } }, @@ -2621,6 +2936,21 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, "DelegateInfo": { "type": "object", "required": [ @@ -2628,7 +2958,7 @@ "nominators", "owner", "registrations", - "return_per_1000", + "return_per_giga", "take", "total_daily_return", "validator_permits" @@ -2666,10 +2996,8 @@ "minimum": 0.0 } }, - "return_per_1000": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "return_per_giga": { + "$ref": "#/definitions/Coin" }, "take": { "type": "integer", @@ -2677,9 +3005,7 @@ "minimum": 0.0 }, "total_daily_return": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "$ref": "#/definitions/Coin" }, "validator_permits": { "type": "array", @@ -2691,6 +3017,10 @@ } }, "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } }, @@ -2704,6 +3034,72 @@ "format": "uint64", "minimum": 0.0 }, + "get_economy": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "EconomyData", + "type": "object", + "required": [ + "block_rewards", + "commission_change", + "default_commission", + "staker_apr", + "total_issuance", + "total_rewards", + "total_stake", + "validator_apr" + ], + "properties": { + "block_rewards": { + "$ref": "#/definitions/Coin" + }, + "commission_change": { + "type": "boolean" + }, + "default_commission": { + "$ref": "#/definitions/Decimal" + }, + "staker_apr": { + "$ref": "#/definitions/Decimal" + }, + "total_issuance": { + "$ref": "#/definitions/Coin" + }, + "total_rewards": { + "$ref": "#/definitions/Coin" + }, + "total_stake": { + "$ref": "#/definitions/Coin" + }, + "validator_apr": { + "$ref": "#/definitions/Decimal" + } + }, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } + }, "get_emission_value_by_subnet": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "uint64", @@ -5897,7 +6293,7 @@ "minimum": 0.0 }, "metadata": { - "type": "string" + "$ref": "#/definitions/Metadata" }, "min_allowed_weights": { "type": "integer", @@ -5938,6 +6334,70 @@ "Addr": { "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" + }, + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + } + } + }, + "get_subnet_metadata": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Metadata", + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" } } }, @@ -5961,6 +6421,37 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + }, "SubnetInfo": { "type": "object", "required": [ @@ -6029,7 +6520,7 @@ "minimum": 0.0 }, "metadata": { - "type": "string" + "$ref": "#/definitions/Metadata" }, "min_allowed_weights": { "type": "integer", @@ -6069,6 +6560,59 @@ } } }, + "get_subnets_metadata": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Array_of_Tuple_of_uint16_and_Metadata", + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "integer", + "format": "uint16", + "minimum": 0.0 + }, + { + "$ref": "#/definitions/Metadata" + } + ], + "maxItems": 2, + "minItems": 2 + }, + "definitions": { + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + } + } + }, "get_tempo": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Nullable_uint16", @@ -6137,6 +6681,39 @@ "format": "uint16", "minimum": 0.0 }, + "get_verse_metadata": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Metadata", + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + }, "get_weights": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Array_of_Array_of_uint16", diff --git a/schema/raw/execute.json b/schema/raw/execute.json index 1070417..384914b 100644 --- a/schema/raw/execute.json +++ b/schema/raw/execute.json @@ -157,6 +157,31 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "set_delegate_commission" + ], + "properties": { + "set_delegate_commission": { + "type": "object", + "required": [ + "commission", + "hotkey" + ], + "properties": { + "commission": { + "type": "string" + }, + "hotkey": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ @@ -1425,10 +1450,37 @@ ], "properties": { "sudo_set_subnet_metadata": { + "type": "object", + "required": [ + "metadata", + "netuid" + ], + "properties": { + "metadata": { + "$ref": "#/definitions/Metadata" + }, + "netuid": { + "type": "integer", + "format": "uint16", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_subnet_owner" + ], + "properties": { + "sudo_set_subnet_owner": { "type": "object", "required": [ "netuid", - "particle" + "new_owner" ], "properties": { "netuid": { @@ -1436,7 +1488,7 @@ "format": "uint16", "minimum": 0.0 }, - "particle": { + "new_owner": { "type": "string" } }, @@ -1444,9 +1496,126 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_root" + ], + "properties": { + "sudo_set_root": { + "type": "object", + "required": [ + "new_root" + ], + "properties": { + "new_root": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_verse_metadata" + ], + "properties": { + "sudo_set_verse_metadata": { + "type": "object", + "required": [ + "metadata" + ], + "properties": { + "metadata": { + "$ref": "#/definitions/Metadata" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_unstake_all" + ], + "properties": { + "sudo_unstake_all": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "sudo_set_commission_change" + ], + "properties": { + "sudo_set_commission_change": { + "type": "object", + "required": [ + "change" + ], + "properties": { + "change": { + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ], "definitions": { + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" diff --git a/schema/raw/query.json b/schema/raw/query.json index d2bf796..11b2002 100644 --- a/schema/raw/query.json +++ b/schema/raw/query.json @@ -839,6 +839,99 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "get_block_rewards" + ], + "properties": { + "get_block_rewards": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_subnet_metadata" + ], + "properties": { + "get_subnet_metadata": { + "type": "object", + "required": [ + "netuid" + ], + "properties": { + "netuid": { + "type": "integer", + "format": "uint16", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_subnets_metadata" + ], + "properties": { + "get_subnets_metadata": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint16", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "integer", + "null" + ], + "format": "uint16", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_verse_metadata" + ], + "properties": { + "get_verse_metadata": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "get_economy" + ], + "properties": { + "get_economy": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ diff --git a/schema/raw/response_to_get_block_rewards.json b/schema/raw/response_to_get_block_rewards.json new file mode 100644 index 0000000..6e18ef9 --- /dev/null +++ b/schema/raw/response_to_get_block_rewards.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Coin", + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + }, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/schema/raw/response_to_get_delegate.json b/schema/raw/response_to_get_delegate.json index c6734f2..d807354 100644 --- a/schema/raw/response_to_get_delegate.json +++ b/schema/raw/response_to_get_delegate.json @@ -14,6 +14,21 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, "DelegateInfo": { "type": "object", "required": [ @@ -21,7 +36,7 @@ "nominators", "owner", "registrations", - "return_per_1000", + "return_per_giga", "take", "total_daily_return", "validator_permits" @@ -59,10 +74,8 @@ "minimum": 0.0 } }, - "return_per_1000": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "return_per_giga": { + "$ref": "#/definitions/Coin" }, "take": { "type": "integer", @@ -70,9 +83,7 @@ "minimum": 0.0 }, "total_daily_return": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "$ref": "#/definitions/Coin" }, "validator_permits": { "type": "array", @@ -84,6 +95,10 @@ } }, "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } } diff --git a/schema/raw/response_to_get_delegated.json b/schema/raw/response_to_get_delegated.json index 179f78e..db46a11 100644 --- a/schema/raw/response_to_get_delegated.json +++ b/schema/raw/response_to_get_delegated.json @@ -22,6 +22,21 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, "DelegateInfo": { "type": "object", "required": [ @@ -29,7 +44,7 @@ "nominators", "owner", "registrations", - "return_per_1000", + "return_per_giga", "take", "total_daily_return", "validator_permits" @@ -67,10 +82,8 @@ "minimum": 0.0 } }, - "return_per_1000": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "return_per_giga": { + "$ref": "#/definitions/Coin" }, "take": { "type": "integer", @@ -78,9 +91,7 @@ "minimum": 0.0 }, "total_daily_return": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "$ref": "#/definitions/Coin" }, "validator_permits": { "type": "array", @@ -92,6 +103,10 @@ } }, "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } } diff --git a/schema/raw/response_to_get_delegates.json b/schema/raw/response_to_get_delegates.json index 4ca2f31..5c07e73 100644 --- a/schema/raw/response_to_get_delegates.json +++ b/schema/raw/response_to_get_delegates.json @@ -10,6 +10,21 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, "DelegateInfo": { "type": "object", "required": [ @@ -17,7 +32,7 @@ "nominators", "owner", "registrations", - "return_per_1000", + "return_per_giga", "take", "total_daily_return", "validator_permits" @@ -55,10 +70,8 @@ "minimum": 0.0 } }, - "return_per_1000": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "return_per_giga": { + "$ref": "#/definitions/Coin" }, "take": { "type": "integer", @@ -66,9 +79,7 @@ "minimum": 0.0 }, "total_daily_return": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "$ref": "#/definitions/Coin" }, "validator_permits": { "type": "array", @@ -80,6 +91,10 @@ } }, "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } } diff --git a/schema/raw/response_to_get_economy.json b/schema/raw/response_to_get_economy.json new file mode 100644 index 0000000..bffa1b1 --- /dev/null +++ b/schema/raw/response_to_get_economy.json @@ -0,0 +1,66 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "EconomyData", + "type": "object", + "required": [ + "block_rewards", + "commission_change", + "default_commission", + "staker_apr", + "total_issuance", + "total_rewards", + "total_stake", + "validator_apr" + ], + "properties": { + "block_rewards": { + "$ref": "#/definitions/Coin" + }, + "commission_change": { + "type": "boolean" + }, + "default_commission": { + "$ref": "#/definitions/Decimal" + }, + "staker_apr": { + "$ref": "#/definitions/Decimal" + }, + "total_issuance": { + "$ref": "#/definitions/Coin" + }, + "total_rewards": { + "$ref": "#/definitions/Coin" + }, + "total_stake": { + "$ref": "#/definitions/Coin" + }, + "validator_apr": { + "$ref": "#/definitions/Decimal" + } + }, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/schema/raw/response_to_get_subnet_info.json b/schema/raw/response_to_get_subnet_info.json index 0dcdcec..3ffbed8 100644 --- a/schema/raw/response_to_get_subnet_info.json +++ b/schema/raw/response_to_get_subnet_info.json @@ -68,7 +68,7 @@ "minimum": 0.0 }, "metadata": { - "type": "string" + "$ref": "#/definitions/Metadata" }, "min_allowed_weights": { "type": "integer", @@ -109,6 +109,37 @@ "Addr": { "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" + }, + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } } } } diff --git a/schema/raw/response_to_get_subnet_metadata.json b/schema/raw/response_to_get_subnet_metadata.json new file mode 100644 index 0000000..3310951 --- /dev/null +++ b/schema/raw/response_to_get_subnet_metadata.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Metadata", + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } +} diff --git a/schema/raw/response_to_get_subnets_info.json b/schema/raw/response_to_get_subnets_info.json index b906cad..030b26b 100644 --- a/schema/raw/response_to_get_subnets_info.json +++ b/schema/raw/response_to_get_subnets_info.json @@ -10,6 +10,37 @@ "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", "type": "string" }, + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + }, "SubnetInfo": { "type": "object", "required": [ @@ -78,7 +109,7 @@ "minimum": 0.0 }, "metadata": { - "type": "string" + "$ref": "#/definitions/Metadata" }, "min_allowed_weights": { "type": "integer", diff --git a/schema/raw/response_to_get_subnets_metadata.json b/schema/raw/response_to_get_subnets_metadata.json new file mode 100644 index 0000000..72d9948 --- /dev/null +++ b/schema/raw/response_to_get_subnets_metadata.json @@ -0,0 +1,53 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Array_of_Tuple_of_uint16_and_Metadata", + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "integer", + "format": "uint16", + "minimum": 0.0 + }, + { + "$ref": "#/definitions/Metadata" + } + ], + "maxItems": 2, + "minItems": 2 + }, + "definitions": { + "Metadata": { + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } + } + } +} diff --git a/schema/raw/response_to_get_verse_metadata.json b/schema/raw/response_to_get_verse_metadata.json new file mode 100644 index 0000000..3310951 --- /dev/null +++ b/schema/raw/response_to_get_verse_metadata.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Metadata", + "type": "object", + "required": [ + "description", + "extra", + "logo", + "name", + "particle", + "types" + ], + "properties": { + "description": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "particle": { + "type": "string" + }, + "types": { + "type": "string" + } + } +} diff --git a/schema/raw/response_to_get_verse_type.json b/schema/raw/response_to_get_verse_type.json new file mode 100644 index 0000000..f689ace --- /dev/null +++ b/schema/raw/response_to_get_verse_type.json @@ -0,0 +1,5 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "String", + "type": "string" +} diff --git a/src/block_step.rs b/src/block_step.rs index 3963444..bc868a2 100644 --- a/src/block_step.rs +++ b/src/block_step.rs @@ -8,22 +8,27 @@ use crate::state::{ BURN_REGISTRATIONS_THIS_INTERVAL, DELEGATES, DIFFICULTY, EMISSION_VALUES, LAST_ADJUSTMENT_BLOCK, LAST_MECHANISM_STEP_BLOCK, LOADED_EMISSION, MAX_BURN, MAX_DIFFICULTY, MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, PENDING_EMISSION, POW_REGISTRATIONS_THIS_INTERVAL, - REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, STAKE, SUBNET_OWNER, SUBNET_OWNER_CUT, - TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_COLDKEY_STAKE, TOTAL_HOTKEY_STAKE, - TOTAL_ISSUANCE, TOTAL_STAKE, + REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, STAKE, SUBNET_OWNER, + TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_HOTKEY_STAKE, + TOTAL_ISSUANCE, }; -use crate::utils::get_blocks_since_last_step; +use crate::utils::{ensure_root, get_blocks_since_last_step}; use crate::ContractError; -use cosmwasm_std::{ - coins, Addr, Api, BankMsg, CosmosMsg, DepsMut, Env, Order, StdResult, Storage, Uint128, -}; +use cosmwasm_std::{Addr, Api, CosmosMsg, DepsMut, Env, Order, StdResult, Storage}; use cyber_std::Response; use substrate_fixed::types::I110F18; use substrate_fixed::types::I64F64; use substrate_fixed::types::I96F32; +#[cfg(test)] +use crate::state::{TOTAL_COLDKEY_STAKE, TOTAL_STAKE}; + /// Executes the necessary operations for each block. -pub fn block_step(deps: DepsMut, env: Env) -> Result { +pub fn block_step(deps: DepsMut, env: Env, caller: Option) -> Result { + if caller.is_some() { + ensure_root(deps.storage, &caller.unwrap())?; + } + let block_number: u64 = env.block.height; deps.api .debug(&format!("🕛 block_step for block: {:?} ", block_number)); @@ -141,14 +146,14 @@ pub fn generate_emission( )); let subnet_has_owner = SUBNET_OWNER.has(store, netuid); - let mut remaining = I96F32::from_num(new_queued_emission); + let remaining = I96F32::from_num(new_queued_emission); if subnet_has_owner { - let subnet_owner_cut = SUBNET_OWNER_CUT.load(store)?; - let cut = remaining - .saturating_mul(I96F32::from_num(subnet_owner_cut)) - .saturating_div(I96F32::from_num(u16::MAX)); - - remaining = remaining.saturating_sub(cut); + // let subnet_owner_cut = SUBNET_OWNER_CUT.load(store)?; + // let cut = remaining + // .saturating_mul(I96F32::from_num(subnet_owner_cut)) + // .saturating_div(I96F32::from_num(u16::MAX)); + // + // remaining = remaining.saturating_sub(cut); // TODO back to this, by default subnet owner cut is zero // let subnet_owner = SUBNET_OWNER.load(store, netuid)?; @@ -159,9 +164,9 @@ pub fn generate_emission( // amount: coins(Uint128::from(cut.to_num::()).u128(), denom), // })); - TOTAL_ISSUANCE.update(store, |a| -> StdResult<_> { - Ok(a.saturating_add(cut.to_num::())) - })?; + // TOTAL_ISSUANCE.update(store, |a| -> StdResult<_> { + // Ok(a.saturating_add(cut.to_num::())) + // })?; } // --- 5. Add remaining amount to the network's pending emission. PENDING_EMISSION.update(store, netuid, |queued| -> StdResult<_> { diff --git a/src/contract.rs b/src/contract.rs index 2b6617c..6016abb 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -1,56 +1,39 @@ +use std::ops::{Div, Mul, Sub}; + +use cosmwasm_std::{Addr, BankMsg, Binary, Coin, CosmosMsg, Decimal, Deps, DepsMut, ensure, Env, MessageInfo, Order, StdResult, Storage, to_json_binary, Uint128}; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; -use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Deps, DepsMut, Env, MessageInfo, Order, StdResult, Storage, Uint128, CosmosMsg, BankMsg, coins}; -use cw2::{get_contract_version, set_contract_version, ContractVersion}; -use cyber_std::Response; +use cw2::{ContractVersion, get_contract_version, set_contract_version}; +use cw_storage_plus::Bound; +use cyber_std::{create_forget_thought_msg, Response}; use cyber_std::{create_creat_thought_msg, Load, Trigger}; use crate::block_step::block_step; use crate::delegate_info::{get_delegate, get_delegated, get_delegates}; use crate::error::ContractError; -use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, SudoMsg}; +use crate::msg::{EconomyData, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, SudoMsg}; use crate::neuron_info::{get_neuron, get_neuron_lite, get_neurons, get_neurons_lite}; use crate::registration::{do_burned_registration, do_registration, do_sudo_registration}; use crate::root::{do_root_register, get_network_lock_cost, user_add_network, user_remove_network}; use crate::serving::{do_serve_axon, do_serve_prometheus}; use crate::stake_info::{get_stake_info_for_coldkey, get_stake_info_for_coldkeys}; -use crate::staking::{do_add_stake, do_become_delegate, do_remove_stake}; -use crate::state::{ - AxonInfo, PrometheusInfo, ACTIVE, ACTIVITY_CUTOFF, ADJUSTMENTS_ALPHA, ADJUSTMENT_INTERVAL, - ALLOW_FAUCET, AXONS, BLOCKS_SINCE_LAST_STEP, BLOCK_EMISSION, BONDS_MOVING_AVERAGE, BURN, - BURN_REGISTRATIONS_THIS_INTERVAL, CONSENSUS, DEFAULT_TAKE, DELEGATES, DENOM, DIFFICULTY, - DIVIDENDS, EMISSION, EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, LAST_ADJUSTMENT_BLOCK, - LAST_UPDATE, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, MAX_DIFFICULTY, - MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, METADATA, MIN_ALLOWED_WEIGHTS, MIN_BURN, - MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, - NETWORK_LAST_REGISTERED, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, - NETWORK_MODALITY, NETWORK_RATE_LIMIT, NETWORK_REGISTERED_AT, NETWORK_REGISTRATION_ALLOWED, - OWNER, PENDING_EMISSION, POW_REGISTRATIONS_THIS_INTERVAL, PROMETHEUS, PRUNING_SCORES, RANK, - RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, - ROOT, SERVING_RATE_LIMIT, STAKE, SUBNETWORK_N, SUBNET_LIMIT, SUBNET_LOCKED, SUBNET_OWNER, - SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_COLDKEY_STAKE, - TOTAL_HOTKEY_STAKE, TOTAL_ISSUANCE, TOTAL_NETWORKS, TOTAL_STAKE, TRUST, TX_RATE_LIMIT, UIDS, - VALIDATOR_PERMIT, VALIDATOR_TRUST, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, -}; +use crate::staking::{do_add_stake, do_become_delegate, do_remove_stake, do_set_delegate_commission}; +use crate::state::{ACTIVE, ACTIVITY_CUTOFF, ADJUSTMENT_INTERVAL, ADJUSTMENTS_ALPHA, ALLOW_FAUCET, AxonInfo, AXONS, BLOCK_EMISSION, BLOCKS_SINCE_LAST_STEP, BONDS_MOVING_AVERAGE, BURN, BURN_REGISTRATIONS_THIS_INTERVAL, COMMISSION_CHANGE, CONSENSUS, DEFAULT_TAKE, DELEGATES, DENOM, DIFFICULTY, DIVIDENDS, EMISSION, EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, LAST_ADJUSTMENT_BLOCK, LAST_UPDATE, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, Metadata, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, NETWORK_LAST_REGISTERED, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, NETWORK_MODALITY, NETWORK_RATE_LIMIT, NETWORK_REGISTERED_AT, NETWORK_REGISTRATION_ALLOWED, NETWORKS_ADDED, NETWORKS_METADATA, OWNER, PENDING_EMISSION, POW_REGISTRATIONS_THIS_INTERVAL, PROMETHEUS, PrometheusInfo, PRUNING_SCORES, RANK, RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, ROOT, SERVING_RATE_LIMIT, STAKE, SUBNET_LIMIT, SUBNET_LOCKED, SUBNET_OWNER, SUBNET_OWNER_CUT, SUBNETWORK_N, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_COLDKEY_STAKE, TOTAL_HOTKEY_STAKE, TOTAL_ISSUANCE, TOTAL_NETWORKS, TOTAL_REWARDS, TOTAL_STAKE, TRUST, TX_RATE_LIMIT, UIDS, VALIDATOR_PERMIT, VALIDATOR_TRUST, VERSE_METADATA, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY}; use crate::state_info::get_state_info; use crate::subnet_info::{get_subnet_hyperparams, get_subnet_info, get_subnets_info}; use crate::uids::get_registered_networks_for_hotkey; use crate::utils::{ do_sudo_set_activity_cutoff, do_sudo_set_adjustment_alpha, do_sudo_set_adjustment_interval, - do_sudo_set_block_emission, do_sudo_set_bonds_moving_average, do_sudo_set_default_take, - do_sudo_set_difficulty, do_sudo_set_immunity_period, do_sudo_set_kappa, - do_sudo_set_lock_reduction_interval, do_sudo_set_max_allowed_uids, - do_sudo_set_max_allowed_validators, do_sudo_set_max_burn, do_sudo_set_max_difficulty, - do_sudo_set_max_registrations_per_block, do_sudo_set_max_weight_limit, - do_sudo_set_min_allowed_weights, do_sudo_set_min_burn, do_sudo_set_min_difficulty, - do_sudo_set_network_immunity_period, do_sudo_set_network_min_lock_cost, - do_sudo_set_network_rate_limit, do_sudo_set_network_registration_allowed, - do_sudo_set_rao_recycled, do_sudo_set_rho, do_sudo_set_serving_rate_limit, - do_sudo_set_subnet_limit, do_sudo_set_subnet_metadata, do_sudo_set_subnet_owner_cut, - do_sudo_set_target_registrations_per_interval, do_sudo_set_tempo, do_sudo_set_total_issuance, - do_sudo_set_tx_rate_limit, do_sudo_set_validator_permit_for_uid, - do_sudo_set_validator_prune_len, do_sudo_set_weights_set_rate_limit, - do_sudo_set_weights_version_key, + do_sudo_set_block_emission, do_sudo_set_bonds_moving_average, do_sudo_set_commission_change, do_sudo_set_default_take, do_sudo_set_difficulty, + do_sudo_set_immunity_period, do_sudo_set_kappa, do_sudo_set_lock_reduction_interval, do_sudo_set_max_allowed_uids, + do_sudo_set_max_allowed_validators, do_sudo_set_max_burn, do_sudo_set_max_difficulty, do_sudo_set_max_registrations_per_block, + do_sudo_set_max_weight_limit, do_sudo_set_min_allowed_weights, do_sudo_set_min_burn, do_sudo_set_min_difficulty, + do_sudo_set_network_immunity_period, do_sudo_set_network_min_lock_cost, do_sudo_set_network_rate_limit, do_sudo_set_network_registration_allowed, + do_sudo_set_rao_recycled, do_sudo_set_rho, do_sudo_set_root, do_sudo_set_serving_rate_limit, do_sudo_set_subnet_limit, + do_sudo_set_subnet_metadata, do_sudo_set_subnet_owner, do_sudo_set_subnet_owner_cut, do_sudo_set_target_registrations_per_interval, + do_sudo_set_tempo, do_sudo_set_total_issuance, do_sudo_set_tx_rate_limit, do_sudo_set_validator_permit_for_uid, + do_sudo_set_validator_prune_len, do_sudo_set_verse_metadata, do_sudo_set_weights_set_rate_limit, do_sudo_set_weights_version_key, do_sudo_unstake_all, + ensure_root }; use crate::weights::{do_set_weights, get_network_weights, get_network_weights_sparse}; @@ -69,11 +52,13 @@ pub fn instantiate( ROOT.save(deps.storage, &info.sender)?; ALLOW_FAUCET.save(deps.storage, &false)?; - if info.funds.len() > 0 { - DENOM.save(deps.storage, &info.funds[0].denom)?; - } else { - DENOM.save(deps.storage, &"boot".to_string())?; - } + // denom which sent during instantiate is general denom for contract + ensure!( + info.funds.len() == 1, + ContractError::DenomSetError {} + ); + DENOM.save(deps.storage, &info.funds[0].denom)?; + COMMISSION_CHANGE.save(deps.storage, &false)?; TOTAL_ISSUANCE.save(deps.storage, &0)?; TOTAL_STAKE.save(deps.storage, &0)?; @@ -81,19 +66,20 @@ pub fn instantiate( // -- Cybertensor parameters initialization -- SUBNET_LIMIT.save(deps.storage, &16)?; - NETWORK_IMMUNITY_PERIOD.save(deps.storage, &7200)?; + NETWORK_IMMUNITY_PERIOD.save(deps.storage, &14400)?; BLOCK_EMISSION.save(deps.storage, &4_200_000)?; SUBNET_OWNER_CUT.save(deps.storage, &0)?; NETWORK_RATE_LIMIT.save(deps.storage, &0)?; - // 6.25% (2^12/2^16) - DEFAULT_TAKE.save(deps.storage, &4096)?; + // 20% (113108/2^16) + DEFAULT_TAKE.save(deps.storage, &13107)?; TX_RATE_LIMIT.save(deps.storage, &0)?; NETWORK_LAST_LOCK_COST.save(deps.storage, &10_000_000_000)?; NETWORK_MIN_LOCK_COST.save(deps.storage, &10_000_000_000)?; - NETWORK_LOCK_REDUCTION_INTERVAL.save(deps.storage, &(7 * 7200))?; + NETWORK_LOCK_REDUCTION_INTERVAL.save(deps.storage, &(7 * 14400))?; + TOTAL_REWARDS.save(deps.storage, &0)?; // -- Root network initialization -- let root_netuid: u16 = 0; @@ -127,10 +113,10 @@ pub fn instantiate( KAPPA.save(deps.storage, root_netuid, &32_767)?; RHO.save(deps.storage, root_netuid, &30)?; RAO_RECYCLED_FOR_REGISTRATION.save(deps.storage, root_netuid, &0)?; - ACTIVITY_CUTOFF.save(deps.storage, root_netuid, &5000)?; + ACTIVITY_CUTOFF.save(deps.storage, root_netuid, &14400)?; SERVING_RATE_LIMIT.save(deps.storage, root_netuid, &50)?; DIFFICULTY.save(deps.storage, root_netuid, &10_000_000)?; - IMMUNITY_PERIOD.save(deps.storage, root_netuid, &7200)?; + IMMUNITY_PERIOD.save(deps.storage, root_netuid, &14400)?; POW_REGISTRATIONS_THIS_INTERVAL.save(deps.storage, root_netuid, &0)?; BURN_REGISTRATIONS_THIS_INTERVAL.save(deps.storage, root_netuid, &0)?; ADJUSTMENTS_ALPHA.save(deps.storage, root_netuid, &0)?; @@ -139,10 +125,17 @@ pub fn instantiate( EMISSION_VALUES.save(deps.storage, root_netuid, &0)?; NETWORK_LAST_REGISTERED.save(deps.storage, &0)?; TOTAL_NETWORKS.save(deps.storage, &1)?; - METADATA.save( + NETWORKS_METADATA.save( deps.storage, root_netuid, - &"Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + &Metadata { + name: "root".to_string(), + particle: "Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + description: "Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + logo: "".to_string(), + types: "".to_string(), + extra: "".to_string(), + } )?; // -- Subnetwork 1 initialization -- @@ -155,16 +148,16 @@ pub fn instantiate( TEMPO.save(deps.storage, netuid, &10)?; KAPPA.save(deps.storage, netuid, &0)?; DIFFICULTY.save(deps.storage, netuid, &10_000_000)?; - IMMUNITY_PERIOD.save(deps.storage, netuid, &7200)?; - ACTIVITY_CUTOFF.save(deps.storage, netuid, &5000)?; + IMMUNITY_PERIOD.save(deps.storage, netuid, &14400)?; + ACTIVITY_CUTOFF.save(deps.storage, netuid, &14400)?; EMISSION_VALUES.save(deps.storage, netuid, &0)?; MAX_WEIGHTS_LIMIT.save(deps.storage, netuid, &u16::MAX)?; MIN_ALLOWED_WEIGHTS.save(deps.storage, netuid, &0)?; REGISTRATIONS_THIS_INTERVAL.save(deps.storage, netuid, &0)?; POW_REGISTRATIONS_THIS_INTERVAL.save(deps.storage, netuid, &0)?; BURN_REGISTRATIONS_THIS_INTERVAL.save(deps.storage, netuid, &0)?; - MAX_ALLOWED_VALIDATORS.save(deps.storage, netuid, &64)?; - MAX_ALLOWED_UIDS.save(deps.storage, netuid, &1024)?; + MAX_ALLOWED_VALIDATORS.save(deps.storage, netuid, &32)?; + MAX_ALLOWED_UIDS.save(deps.storage, netuid, &128)?; WEIGHTS_VERSION_KEY.save(deps.storage, netuid, &0)?; WEIGHTS_SET_RATE_LIMIT.save(deps.storage, netuid, &100)?; @@ -191,10 +184,17 @@ pub fn instantiate( SUBNET_LOCKED.save(deps.storage, netuid, &0)?; TARGET_REGISTRATIONS_PER_INTERVAL.save(deps.storage, netuid, &1)?; NETWORK_REGISTRATION_ALLOWED.save(deps.storage, netuid, &true)?; - METADATA.save( + NETWORKS_METADATA.save( deps.storage, netuid, - &"Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + &Metadata { + name: "x".to_string(), + particle: "Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + description: "Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + logo: "".to_string(), + types: "".to_string(), + extra: "".to_string(), + } )?; RANK.save(deps.storage, netuid, &vec![])?; @@ -217,7 +217,13 @@ pub fn instantiate( Ok(Response::default().add_attribute("action", "instantiate")) } -pub fn activate(deps: DepsMut, env: Env) -> Result { +pub fn activate( + deps: DepsMut, + env: Env, + info: MessageInfo +) -> Result { + ensure_root(deps.storage, &info.sender)?; + let denom = DENOM.load(deps.storage)?; let res = Response::new() .add_message(create_creat_thought_msg( @@ -234,6 +240,7 @@ pub fn activate(deps: DepsMut, env: Env) -> Result { amount: Uint128::from(10u128), }, }, + // TODO replace dmn thought name later env.contract.address.as_str()[0..32].to_string(), "Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), )) @@ -242,19 +249,37 @@ pub fn activate(deps: DepsMut, env: Env) -> Result { Ok(res) } -pub fn deactivate(deps: DepsMut, env: Env) -> Result { +pub fn deactivate( + deps: DepsMut, + env: Env, + info: MessageInfo, +) -> Result { + ensure_root(deps.storage, &info.sender)?; + let denom = DENOM.load(deps.storage)?; let root = ROOT.load(deps.storage)?; - let coin = deps.querier.query_balance(env.contract.address, denom).unwrap(); + let contract_balance = deps.querier.query_balance(env.clone().contract.address, denom.clone()).unwrap(); + let total_stake = TOTAL_STAKE.load(deps.storage)?; - let msg = CosmosMsg::Bank(BankMsg::Send { + let return_rewards_msg = CosmosMsg::Bank(BankMsg::Send { to_address: root.to_string(), - amount: vec![coin], + amount: vec![ + Coin { + denom, + amount: contract_balance.amount.sub(Uint128::from(total_stake)), + }, + ], }); + let disable_dmn = create_forget_thought_msg( + env.contract.address.to_string(), + env.contract.address.as_str()[0..32].to_string() + ); + let res = Response::new() - .add_message(msg) + .add_message(return_rewards_msg) + .add_message(disable_dmn) .add_attribute("action", "deactivate"); Ok(res) @@ -268,10 +293,9 @@ pub fn execute( msg: ExecuteMsg, ) -> Result { match msg { - ExecuteMsg::Activate {} => activate(deps, env), - ExecuteMsg::Deactivate {} => deactivate(deps, env), - ExecuteMsg::BlockStep {} => block_step(deps, env), - + ExecuteMsg::Activate {} => activate(deps, env, info), + ExecuteMsg::Deactivate {} => deactivate(deps, env, info), + ExecuteMsg::BlockStep {} => block_step(deps, env, Some(info.sender)), ExecuteMsg::SetWeights { netuid, dests, @@ -283,6 +307,9 @@ pub fn execute( ExecuteMsg::RemoveStake { hotkey, amount } => { do_remove_stake(deps, env, info, hotkey, amount) } + ExecuteMsg::SetDelegateCommission { hotkey, commission } => { + do_set_delegate_commission(deps, env, info, hotkey, commission) + } ExecuteMsg::ServeAxon { netuid, version, @@ -485,16 +512,31 @@ pub fn execute( ExecuteMsg::SudoSetBlockEmission { emission } => { do_sudo_set_block_emission(deps, env, info, emission) } - ExecuteMsg::SudoSetSubnetMetadata { netuid, particle } => { - do_sudo_set_subnet_metadata(deps, env, info, netuid, particle) - } + ExecuteMsg::SudoSetSubnetMetadata { netuid, metadata } => { + do_sudo_set_subnet_metadata(deps, env, info, netuid, metadata) + } + ExecuteMsg::SudoSetSubnetOwner { netuid, new_owner } => { + do_sudo_set_subnet_owner(deps, env, info, netuid, new_owner) + } + ExecuteMsg::SudoSetRoot { new_root, } => { + do_sudo_set_root(deps, env, info, new_root) + }, + ExecuteMsg::SudoSetVerseMetadata { metadata } => { + do_sudo_set_verse_metadata(deps, env, info, metadata) + }, + ExecuteMsg::SudoUnstakeAll { limit } => { + do_sudo_unstake_all(deps, env, info, limit) + }, + ExecuteMsg::SudoSetCommissionChange { change } => { + do_sudo_set_commission_change(deps, env, info, change) + }, } } #[cfg_attr(not(feature = "library"), entry_point)] pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result { match msg { - SudoMsg::BlockStep {} => block_step(deps, env), + SudoMsg::BlockStep {} => block_step(deps, env, None), } } @@ -635,6 +677,17 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { QueryMsg::GetWeightsSparse { netuid } => { to_json_binary(&get_network_weights_sparse(deps.storage, netuid)?) } + QueryMsg::GetBlockRewards {} => { + to_json_binary(&get_block_rewards(deps.storage)?) + } + QueryMsg::GetSubnetMetadata { netuid } => { + to_json_binary(&get_subnet_metadata(deps.storage, netuid)?) + } + QueryMsg::GetSubnetsMetadata { start_after, limit } => { + to_json_binary(&get_subnets_metadata(deps.storage, start_after, limit)?) + } + QueryMsg::GetVerseMetadata {} => to_json_binary(&get_verse_metadata(deps.storage)?), + QueryMsg::GetEconomy {} => to_json_binary(&get_economy(deps.storage)?), } } @@ -865,6 +918,89 @@ pub fn query_get_stake(store: &dyn Storage, hotkey: &Addr) -> StdResult StdResult { + let block_rewards = BLOCK_EMISSION.load(store)?; + let denom = DENOM.load(store)?; + Ok(Coin::new(u128::from(block_rewards), denom)) +} + +pub fn get_subnet_metadata( + store: &dyn Storage, + netuid: u16, +) -> StdResult { + let subnet_meta = NETWORKS_METADATA.load(store, netuid)?; + Ok(subnet_meta) +} + +pub fn get_subnets_metadata( + store: &dyn Storage, + start_after: Option, + limit: Option, +) -> StdResult> { + let start = start_after.map(Bound::exclusive); + let subnets_limit = limit.unwrap_or(32) as usize; + + let subnets = NETWORKS_METADATA + .range(store, start, None, Order::Ascending) + .take(subnets_limit) + .map(|item| { + let (k, v) = item.unwrap(); + (k, v) + }) + .collect::>(); + + Ok(subnets) +} + +pub fn get_verse_metadata( + store: &dyn Storage, +) -> StdResult { + let verse_meta = VERSE_METADATA.load(store)?; + Ok(verse_meta) +} + +pub fn get_economy( + store: &dyn Storage, +) -> StdResult { + let block_rewards = BLOCK_EMISSION.load(store)?; + let denom = DENOM.load(store)?; + let total_stake = TOTAL_STAKE.load(store)?; + let default_take = DEFAULT_TAKE.load(store)?; + let default_commission = Decimal::from_ratio(default_take, u16::MAX) + .mul(Decimal::from_atomics(Uint128::from(100u64),0).unwrap()); + let commission_change = COMMISSION_CHANGE.load(store)?; + let blocks_per_year = 5256000u64; + let total_issuance = TOTAL_ISSUANCE.load(store)?; + let total_rewards = TOTAL_REWARDS.load(store)?; + + let validator_apr = Decimal::new(Uint128::from(block_rewards).mul(Uint128::from(blocks_per_year))) + .div(Decimal::new(Uint128::from(total_stake))) + .mul(Decimal::from_atomics(Uint128::from(100u64),0).unwrap()); + + let staker_apr = Decimal::new(Uint128::from(block_rewards).mul(Uint128::from(blocks_per_year))) + .div(Decimal::new(Uint128::from(total_stake))) + .mul(Decimal::one().sub(Decimal::from_ratio(default_take, u16::MAX))) + .mul(Decimal::from_atomics(Uint128::from(100u64),0).unwrap()); + + + let total_rewards = Coin::new(u128::from(total_rewards), denom.clone()); + + let economy_data = EconomyData{ + validator_apr, + staker_apr, + block_rewards: Coin::new(u128::from(block_rewards), denom.clone()), + total_stake: Coin::new(u128::from(total_stake), denom.clone()), + default_commission, + commission_change, + total_issuance: Coin::new(u128::from(total_issuance), denom), + total_rewards + }; + + Ok(economy_data) +} + #[cfg_attr(not(feature = "library"), entry_point)] pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result { let storage_version: ContractVersion = get_contract_version(deps.storage)?; @@ -873,6 +1009,8 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result, // Vec of netuid this delegate has validator permit on - return_per_1000: u64, - // Delegators current daily return per 1000 TAO staked minus take fee - total_daily_return: u64, // Delegators current daily return + return_per_giga: Coin, + // Delegators current daily return per X tokens staked minus take fee + total_daily_return: Coin, // Delegators current daily return } pub fn get_delegate_by_existing_account(store: &dyn Storage, delegate: &Addr) -> DelegateInfo { @@ -58,7 +58,7 @@ pub fn get_delegate_by_existing_account(store: &dyn Storage, delegate: &Addr) -> let emission = U64F64::from_num(get_emission_for_uid(store, *netuid, uid)); let tempo = U64F64::from_num(get_tempo(store, *netuid)); - let epochs_per_day = U64F64::from_num(7200) / tempo; + let epochs_per_day = U64F64::from_num(14400) / tempo; emissions_per_day += emission * epochs_per_day; } } @@ -68,13 +68,16 @@ pub fn get_delegate_by_existing_account(store: &dyn Storage, delegate: &Addr) -> let total_stake = U64F64::from_num(get_total_stake_for_hotkey(store, &delegate)); - let mut return_per_1000 = U64F64::from_num(0); + let mut return_per_giga = U64F64::from_num(0); if total_stake > U64F64::from_num(0) { - return_per_1000 = - (emissions_per_day * U64F64::from_num(0.82)) / (total_stake / U64F64::from_num(1000)); + // TODO rewrite this to Decimal and load take from store + return_per_giga = + (emissions_per_day * U64F64::from_num(0.8)) / (total_stake / U64F64::from_num(1000000000)); } + let denom = DENOM.load(store).unwrap(); + return DelegateInfo { delegate: delegate.clone(), take, @@ -82,8 +85,8 @@ pub fn get_delegate_by_existing_account(store: &dyn Storage, delegate: &Addr) -> owner: owner.clone(), registrations: registrations.iter().map(|x| *x).collect(), validator_permits, - return_per_1000: U64F64::to_num::(return_per_1000).into(), - total_daily_return: U64F64::to_num::(emissions_per_day).into(), + return_per_giga: Coin::new(U64F64::to_num::(return_per_giga), denom.clone()), + total_daily_return: Coin::new(U64F64::to_num::(emissions_per_day), denom), }; } diff --git a/src/epoch.rs b/src/epoch.rs index 828c6de..6ce3152 100644 --- a/src/epoch.rs +++ b/src/epoch.rs @@ -18,11 +18,13 @@ use crate::state::{ use crate::uids::get_subnetwork_n; use crate::utils::{ get_activity_cutoff, get_bonds_moving_average, get_kappa, get_last_update, - get_max_allowed_validators, get_neuron_block_at_registration, get_rho, get_validator_permit, + get_max_allowed_validators, get_neuron_block_at_registration, get_validator_permit, }; #[cfg(test)] use crate::uids::get_stake_for_uid_and_subnetwork; +#[cfg(test)] +use crate::utils::get_rho; // Calculates reward consensus values, then updates rank, trust, consensus, incentive, dividend, pruning_score, emission and bonds, and // returns the emissions for uids/hotkeys in a given `netuid`. @@ -39,14 +41,14 @@ use crate::uids::get_stake_for_uid_and_subnetwork; // pub fn epoch( store: &mut dyn Storage, - api: &dyn Api, + _api: &dyn Api, netuid: u16, token_emission: u64, current_block: u64, ) -> Result, ContractError> { // Get subnetwork size. let n: u16 = get_subnetwork_n(store, netuid); - api.debug(&format!("⚪️ subnet_n: {:?}", n)); + // api.debug(&format!("⚪️ subnet_n: {:?}", n)); // ====================== // == Active & updated == @@ -54,32 +56,32 @@ pub fn epoch( // Get current block. // let current_block: u64 = get_current_block_as_u64(); - api.debug(&format!("⚪️ current_block: {:?}", current_block)); + // api.debug(&format!("⚪️ current_block: {:?}", current_block)); // Get activity cutoff. let activity_cutoff: u64 = get_activity_cutoff(store, netuid) as u64; - api.debug(&format!("⚪️ activity_cutoff: {:?}", activity_cutoff)); + // api.debug(&format!("⚪️ activity_cutoff: {:?}", activity_cutoff)); // Last update vector. let last_update: Vec = get_last_update(store, netuid); - api.debug(&format!("⚪️ last_update: {:?}", &last_update)); + // api.debug(&format!("⚪️ last_update: {:?}", &last_update)); // Inactive mask. let inactive: Vec = last_update .iter() .map(|updated| *updated + activity_cutoff < current_block) .collect(); - api.debug(&format!("⚪️ inactive: {:?}", inactive.clone())); + // api.debug(&format!("⚪️ inactive: {:?}", inactive.clone())); // Logical negation of inactive. let active: Vec = inactive.iter().map(|&b| !b).collect(); // Block at registration vector (block when each neuron was most recently registered). let block_at_registration: Vec = get_block_at_registration(store, netuid); - api.debug(&format!( - "⚪️ block_at_registration: {:?}", - &block_at_registration - )); + // api.debug(&format!( + // "⚪️ block_at_registration: {:?}", + // &block_at_registration + // )); // =========== // == Stake == @@ -93,7 +95,7 @@ pub fn epoch( let (uid_i, hotkey) = item.unwrap(); hotkeys.push((uid_i, hotkey)); } - api.debug(&format!("⚪️ hotkeys: {:?}", &hotkeys)); + // api.debug(&format!("⚪️ hotkeys: {:?}", &hotkeys)); // Access network stake as normalized vector. let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; @@ -103,7 +105,7 @@ pub fn epoch( inplace_normalize_64(&mut stake_64); let stake: Vec = vec_fixed64_to_fixed32(stake_64); // range: I32F32(0, 1) - api.debug(&format!("⚪️ stake: {:?}", &stake)); + // api.debug(&format!("⚪️ stake: {:?}", &stake)); // ======================= // == Validator permits == @@ -111,24 +113,24 @@ pub fn epoch( // Get current validator permits. let validator_permits: Vec = get_validator_permit(store, netuid); - api.debug(&format!("⚪️ validator_permits: {:?}", validator_permits)); + // api.debug(&format!("⚪️ validator_permits: {:?}", validator_permits)); // Logical negation of validator_permits. let validator_forbids: Vec = validator_permits.iter().map(|&b| !b).collect(); // Get max allowed validators. let max_allowed_validators: u16 = get_max_allowed_validators(store, netuid); - api.debug(&format!( - "⚪️ max_allowed_validators: {:?}", - max_allowed_validators - )); + // api.debug(&format!( + // "⚪️ max_allowed_validators: {:?}", + // max_allowed_validators + // )); // Get new validator permits. let new_validator_permits: Vec = is_topk(&stake, max_allowed_validators as usize); - api.debug(&format!( - "⚪️ new_validator_permits: {:?}", - new_validator_permits - )); + // api.debug(&format!( + // "⚪️ new_validator_permits: {:?}", + // new_validator_permits + // )); // ================== // == Active Stake == @@ -144,7 +146,7 @@ pub fn epoch( // Normalize active stake. inplace_normalize(&mut active_stake); - api.debug(&format!("⚪️ stake: {:?}", &active_stake)); + // api.debug(&format!("⚪️ stake: {:?}", &active_stake)); // ============= // == Weights == @@ -186,13 +188,13 @@ pub fn epoch( // Clip weights at majority consensus let kappa: I32F32 = get_float_kappa(store, netuid); // consensus majority ratio, e.g. 51%. let consensus: Vec = weighted_median_col_sparse(&active_stake, &weights, n, kappa); - api.debug(&format!("⚪️ consensus: {:?}", &consensus)); + // api.debug(&format!("⚪️ consensus: {:?}", &consensus)); weights = col_clip_sparse(&weights, &consensus); // api.debug(&format!("W: {:?}", &weights)); let validator_trust: Vec = row_sum_sparse(&weights); - api.debug(&format!("⚪️ validator_trust: {:?}", &validator_trust)); + // api.debug(&format!("⚪️ validator_trust: {:?}", &validator_trust)); // ============================= // == Ranks, Trust, Incentive == @@ -205,11 +207,11 @@ pub fn epoch( // Compute server trust: ratio of rank after vs. rank before. let trust: Vec = vecdiv(&ranks, &preranks); // range: I32F32(0, 1) - api.debug(&format!("⚪️ trust: {:?}", &trust)); + // api.debug(&format!("⚪️ trust: {:?}", &trust)); inplace_normalize(&mut ranks); // range: I32F32(0, 1) let incentive: Vec = ranks.clone(); - api.debug(&format!("⚪️ incentive: {:?}", &incentive)); + // api.debug(&format!("⚪️ incentive: {:?}", &incentive)); // ========================= // == Bonds and Dividends == @@ -257,7 +259,7 @@ pub fn epoch( // range: I32F32(0, 1) let mut dividends: Vec = matmul_transpose_sparse(&ema_bonds, &incentive); inplace_normalize(&mut dividends); - api.debug(&format!("⚪️ dividends: {:?}", ÷nds)); + // api.debug(&format!("⚪️ dividends: {:?}", ÷nds)); // ================================= // == Emission and Pruning scores == @@ -323,16 +325,16 @@ pub fn epoch( .map(|e: &I96F32| e.to_num::()) .collect(); - api.debug(&format!("⚪️ nSE: {:?}", &normalized_server_emission)); - api.debug(&format!("⚪️ SE: {:?}", &server_emission)); - api.debug(&format!("⚪️ nVE: {:?}", &normalized_validator_emission)); - api.debug(&format!("⚪️ VE: {:?}", &validator_emission)); - api.debug(&format!("⚪️ nCE: {:?}", &normalized_combined_emission)); - api.debug(&format!("⚪️ CE: {:?}", &combined_emission)); + // api.debug(&format!("⚪️ nSE: {:?}", &normalized_server_emission)); + // api.debug(&format!("⚪️ SE: {:?}", &server_emission)); + // api.debug(&format!("⚪️ nVE: {:?}", &normalized_validator_emission)); + // api.debug(&format!("⚪️ VE: {:?}", &validator_emission)); + // api.debug(&format!("⚪️ nCE: {:?}", &normalized_combined_emission)); + // api.debug(&format!("⚪️ CE: {:?}", &combined_emission)); // Set pruning scores using combined emission scores. let pruning_scores: Vec = normalized_combined_emission.clone(); - api.debug(&format!("⚪️ Psc: {:?}", &pruning_scores)); + // api.debug(&format!("⚪️ Psc: {:?}", &pruning_scores)); // =================== // == Value storage == diff --git a/src/error.rs b/src/error.rs index ade961d..90e68b9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -161,6 +161,18 @@ pub enum ContractError { #[error("Thrown when all subnets are in the immunity period")] AllNetworksInImmunity {}, - #[error("Thrown when particle metadata size is invalid")] - MetadataSizeError {}, + #[error("Thrown when metadata is invalid")] + MetadataError {}, + + #[error("Thrown when contract denom is not set based on instantiate message token")] + DenomSetError {}, + + #[error("Thrown when contract have issue during migration")] + MigrationError {}, + + #[error("Thrown when delegate attempt to set invalid commission")] + InvalidCommission {}, + + #[error("Thrown when commission change disabled for this verse")] + CommissionChangeDisabled {}, } diff --git a/src/lib.rs b/src/lib.rs index 88d049e..2bddb77 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,20 @@ mod block_step; pub mod contract; -mod delegate_info; +pub mod delegate_info; mod epoch; mod error; pub mod helpers; mod math; pub mod msg; -mod neuron_info; +pub mod neuron_info; mod registration; mod root; mod serving; -mod stake_info; +pub mod stake_info; mod staking; pub mod state; mod state_info; -mod subnet_info; +pub mod subnet_info; #[cfg(test)] mod test_helpers; #[cfg(test)] diff --git a/src/msg.rs b/src/msg.rs index 6d1bb49..6b6acd4 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -1,5 +1,8 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::Uint128; +use cosmwasm_std::{Uint128, Coin, Decimal}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use crate::state::Metadata; #[cw_serde] pub struct InstantiateMsg {} @@ -8,9 +11,8 @@ pub struct InstantiateMsg {} pub enum ExecuteMsg { Activate {}, Deactivate {}, - // TODO remove later, use for manual block_step + // TODO remove later, use for debug block_step and tests, production - sudo call only BlockStep {}, - SetWeights { netuid: u16, dests: Vec, @@ -28,6 +30,10 @@ pub enum ExecuteMsg { hotkey: String, amount: u64, }, + SetDelegateCommission { + hotkey: String, + commission: String, + }, ServeAxon { netuid: u16, version: u32, @@ -210,7 +216,23 @@ pub enum ExecuteMsg { }, SudoSetSubnetMetadata { netuid: u16, - particle: String, + metadata: Metadata, + }, + SudoSetSubnetOwner { + netuid: u16, + new_owner: String, + }, + SudoSetRoot { + new_root: String, + }, + SudoSetVerseMetadata { + metadata: Metadata, + }, + SudoUnstakeAll{ + limit: Option + }, + SudoSetCommissionChange { + change: bool, }, } @@ -312,9 +334,35 @@ pub enum QueryMsg { #[returns(Vec>)] GetWeightsSparse { netuid: u16 }, + #[returns(Coin)] + GetBlockRewards {}, + #[returns(Metadata)] + GetSubnetMetadata { netuid: u16 }, + #[returns(Vec<(u16, Metadata)>)] + GetSubnetsMetadata { + start_after: Option, + limit: Option, + }, + #[returns(Metadata)] + GetVerseMetadata {}, + #[returns(EconomyData)] + GetEconomy {}, + #[returns(crate::state_info::StateInfo)] GetState {}, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct EconomyData { + pub validator_apr: Decimal, + pub staker_apr: Decimal, + pub block_rewards: Coin, + pub total_stake: Coin, + pub default_commission: Decimal, + pub commission_change: bool, + pub total_issuance: Coin, + pub total_rewards: Coin, +} + #[cw_serde] pub struct MigrateMsg {} diff --git a/src/registration.rs b/src/registration.rs index dd3474c..8e906cf 100644 --- a/src/registration.rs +++ b/src/registration.rs @@ -426,6 +426,7 @@ pub fn do_registration( // --- 7. Check Work is the product of the nonce, the block number, and hotkey. Add this as used work. let seal: H256 = create_seal_hash(block_number, nonce, hotkey.as_str()); + // TODO revisit PoW cross testing ensure!(seal == work_hash, ContractError::InvalidSeal {}); USED_WORK.save(deps.storage, work.clone(), ¤t_block_number)?; diff --git a/src/root.rs b/src/root.rs index 2452260..4e62371 100644 --- a/src/root.rs +++ b/src/root.rs @@ -11,11 +11,11 @@ use crate::staking::{ create_account_if_non_existent, delegate_hotkey, get_total_stake_for_hotkey, hotkey_is_delegate, }; use crate::state::{ - ACTIVE, ACTIVITY_CUTOFF, ADJUSTMENTS_ALPHA, ADJUSTMENT_INTERVAL, BLOCKS_SINCE_LAST_STEP, BONDS, + Metadata, ACTIVE, ACTIVITY_CUTOFF, ADJUSTMENTS_ALPHA, ADJUSTMENT_INTERVAL, BLOCKS_SINCE_LAST_STEP, BONDS, BONDS_MOVING_AVERAGE, BURN, BURN_REGISTRATIONS_THIS_INTERVAL, CONSENSUS, DENOM, DIFFICULTY, DIVIDENDS, EMISSION, EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, KEYS, LAST_ADJUSTMENT_BLOCK, LAST_UPDATE, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, - MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, METADATA, MIN_ALLOWED_WEIGHTS, + MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, NETWORKS_METADATA, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, NETWORK_LAST_REGISTERED, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, NETWORK_MODALITY, NETWORK_RATE_LIMIT, NETWORK_REGISTERED_AT, NETWORK_REGISTRATION_ALLOWED, @@ -23,7 +23,7 @@ use crate::state::{ RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, SERVING_RATE_LIMIT, SUBNETWORK_N, SUBNET_LIMIT, SUBNET_OWNER, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_NETWORKS, TRUST, UIDS, VALIDATOR_PERMIT, - VALIDATOR_TRUST, WEIGHTS, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, + VALIDATOR_TRUST, WEIGHTS, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, TOTAL_REWARDS, }; use crate::uids::{append_neuron, get_hotkey_for_net_and_uid, get_subnetwork_n, replace_neuron}; use crate::utils::{ @@ -309,7 +309,13 @@ pub fn root_epoch( // --- 4. Determines the total block emission across all the subnetworks. This is the // value which will be distributed based on the computation below. - let block_emission: I64F64 = I64F64::from_num(get_block_emission(store)); + let block_emission_u64: u64 = get_block_emission(store); + let block_emission: I64F64 = I64F64::from_num(block_emission_u64); + TOTAL_REWARDS.update(store, |val| -> StdResult<_> { + let mut amount = val; + amount += block_emission_u64; + Ok(amount) + })?; api.debug(&format!("🔵 block_emission: {:?}", block_emission)); // --- 5. A collection of all registered hotkeys on the root network. Hotkeys @@ -576,7 +582,7 @@ pub fn do_root_register( // --- 13. Force all members on root to become a delegate. if !hotkey_is_delegate(deps.storage, &hotkey) { - delegate_hotkey(deps.storage, &hotkey, 11796); + delegate_hotkey(deps.storage, &hotkey, 13107); } // --- 14. Update the registration counters for both the block and interval. @@ -776,14 +782,14 @@ pub fn init_new_network( // --- 6. Set all default values **explicitly**. NETWORK_REGISTRATION_ALLOWED.save(store, netuid, &true)?; - MAX_ALLOWED_UIDS.save(store, netuid, &256)?; - MAX_ALLOWED_VALIDATORS.save(store, netuid, &64)?; + MAX_ALLOWED_UIDS.save(store, netuid, &128)?; + MAX_ALLOWED_VALIDATORS.save(store, netuid, &32)?; MIN_ALLOWED_WEIGHTS.save(store, netuid, &1)?; MAX_WEIGHTS_LIMIT.save(store, netuid, &u16::MAX)?; ADJUSTMENT_INTERVAL.save(store, netuid, &360)?; TARGET_REGISTRATIONS_PER_INTERVAL.save(store, netuid, &1)?; ADJUSTMENTS_ALPHA.save(store, netuid, &58000)?; - IMMUNITY_PERIOD.save(store, netuid, &7200)?; + IMMUNITY_PERIOD.save(store, netuid, &14400)?; DIFFICULTY.save(store, netuid, &10_000_000)?; MIN_DIFFICULTY.save(store, netuid, &10_000_000)?; @@ -791,8 +797,7 @@ pub fn init_new_network( // Make network parameters explicit. KAPPA.save(store, netuid, &32_767)?; // 0.5 = 65535/2 - // IMMUNITY_PERIOD.save(store, netuid, &0)?; - ACTIVITY_CUTOFF.save(store, netuid, &5000)?; + ACTIVITY_CUTOFF.save(store, netuid, &14400)?; EMISSION_VALUES.save(store, netuid, &0)?; REGISTRATIONS_THIS_INTERVAL.save(store, netuid, &0)?; @@ -814,17 +819,23 @@ pub fn init_new_network( MAX_BURN.save(store, netuid, &100_000_000_000)?; REGISTRATIONS_THIS_BLOCK.save(store, netuid, &0)?; - // MAX_REGISTRATION_PER_BLOCK.save(store, netuid, &3)?; KAPPA.save(store, netuid, &32_767)?; RHO.save(store, netuid, &30)?; RAO_RECYCLED_FOR_REGISTRATION.save(store, netuid, &0)?; SERVING_RATE_LIMIT.save(store, netuid, &50)?; ADJUSTMENTS_ALPHA.save(store, netuid, &0)?; LAST_UPDATE.save(store, netuid, &vec![])?; - METADATA.save( + NETWORKS_METADATA.save( store, netuid, - &"Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + &Metadata { + name: "empty".to_string(), + particle: "".to_string(), + description: "".to_string(), + logo: "".to_string(), + types: "".to_string(), + extra: "".to_string(), + } )?; Ok(()) @@ -929,7 +940,7 @@ pub fn remove_network(store: &mut dyn Storage, netuid: u16) -> Result<(), Contra ADJUSTMENTS_ALPHA.remove(store, netuid); NETWORK_REGISTRATION_ALLOWED.remove(store, netuid); TARGET_REGISTRATIONS_PER_INTERVAL.remove(store, netuid); - METADATA.remove(store, netuid); + NETWORKS_METADATA.remove(store, netuid); Ok(()) } diff --git a/src/stake_info.rs b/src/stake_info.rs index 375fddc..a664699 100644 --- a/src/stake_info.rs +++ b/src/stake_info.rs @@ -5,9 +5,9 @@ use crate::state::STAKE; #[cw_serde] pub struct StakeInfo { - hotkey: Addr, - coldkey: Addr, - stake: u64, + pub hotkey: Addr, + pub coldkey: Addr, + pub stake: u64, } fn _get_stake_info_for_coldkeys( diff --git a/src/staking.rs b/src/staking.rs index 77d567a..1132d7d 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1,14 +1,12 @@ -use std::ops::Deref; +use std::ops::{Deref, Mul}; +use std::str::FromStr; -use cosmwasm_std::{ - coins, ensure, Addr, BankMsg, CosmosMsg, DepsMut, Env, MessageInfo, Order, StdResult, Storage, - Uint128, -}; +use cosmwasm_std::{coins, ensure, Addr, BankMsg, CosmosMsg, DepsMut, Env, MessageInfo, Order, StdResult, Storage, Uint128, Decimal}; use cw_utils::must_pay; use crate::state::{ DELEGATES, DENOM, OWNER, STAKE, TOTAL_COLDKEY_STAKE, TOTAL_HOTKEY_STAKE, TOTAL_ISSUANCE, - TOTAL_STAKE, + TOTAL_STAKE, COMMISSION_CHANGE, }; use crate::utils::{exceeds_tx_rate_limit, get_default_take, get_last_tx_block, set_last_tx_block}; use crate::ContractError; @@ -310,6 +308,78 @@ pub fn do_remove_stake( .add_attribute("stake_to_be_removed", format!("{}", stake_to_be_removed))) } +pub fn do_set_delegate_commission( + deps: DepsMut, + env: Env, + info: MessageInfo, + hotkey_address: String, + new_commission: String, +) -> Result { + let commission_change = COMMISSION_CHANGE.load(deps.storage)?; + ensure!( + commission_change, + ContractError::CommissionChangeDisabled {} + ); + + let commission = Decimal::from_str(&new_commission).map_err(|_| ContractError::InvalidCommission {})?; + ensure!( + commission > Decimal::zero() && commission <= Decimal::one(), + ContractError::InvalidCommission {} + ); + + // --- 1. We check the coldkey signuture. + let coldkey = info.sender; + let hotkey = deps.api.addr_validate(&hotkey_address)?; + + deps.api.debug(&format!( + "🌐 do_set_deletate_commission ( coldkey:{:?} hotkey:{:?}, commission:{:?} )", + coldkey, hotkey, new_commission + )); + + // --- 2. Ensure we are delegating an known key. + ensure!( + hotkey_account_exists(deps.storage, &hotkey), + ContractError::NotRegistered {} + ); + + // --- 3. Ensure that the coldkey is the owner. + ensure!( + coldkey_owns_hotkey(deps.storage, &coldkey, &hotkey), + ContractError::NonAssociatedColdKey {} + ); + + // --- 5. Ensure we don't exceed tx rate limit + ensure!( + !exceeds_tx_rate_limit( + deps.storage, + get_last_tx_block(deps.storage, &coldkey), + env.block.height + ), + ContractError::TxRateLimitExceeded {} + ); + + // --- 6. Delegate the key. + let take = Decimal::new(Uint128::new(65536u128)).mul(commission).to_uint_floor().u128(); + delegate_hotkey(deps.storage, &hotkey, take as u16); + + // Set last block for rate limiting + set_last_tx_block(deps.storage, &coldkey, env.block.height); + + // --- 7. Emit the staking event. + deps.api.debug(&format!( + "🌐 SetDelegateCommission( coldkey:{:?}, hotkey:{:?}, commission:{:?} )", + coldkey, + hotkey, + commission + )); + + // --- 8. Ok and return. + Ok(Response::default() + .add_attribute("action", "set_delegate_commission") + .add_attribute("hotkey", hotkey) + .add_attribute("commission", format!("{}", commission))) +} + // Returns true if the passed hotkey allow delegative staking. // pub fn hotkey_is_delegate(store: &dyn Storage, hotkey: &Addr) -> bool { diff --git a/src/state.rs b/src/state.rs index 86322bd..a1156ce 100644 --- a/src/state.rs +++ b/src/state.rs @@ -3,12 +3,14 @@ use cw_storage_plus::{Item, Map}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +// ============================ +// ==== Verse Settings ==== +// ============================ pub const ROOT: Item = Item::new("root"); - +pub const COMMISSION_CHANGE: Item = Item::new("commission_switch"); pub const DENOM: Item = Item::new("denom"); - -// --- ITEM ( percentage ) // TODO change to decimal -// pub const SENATE_REQUIRED_STAKE_PERCENTAGE: Item = Item::new("senate_required_stake_percentage"); +pub const VERSE_METADATA: Item = Item::new("verse_metadata"); +pub const TOTAL_REWARDS: Item = Item::new("total_rewards"); // ============================ // ==== Staking + Accounts ==== @@ -18,8 +20,10 @@ pub const DENOM: Item = Item::new("denom"); pub const TOTAL_STAKE: Item = Item::new("total_stake"); // --- ITEM ( default_take ) pub const DEFAULT_TAKE: Item = Item::new("default_take"); +// TODO think about to rename to block_reward // --- ITEM ( global_block_emission ) pub const BLOCK_EMISSION: Item = Item::new("global_block_emission"); +// TODo revisit total issuance and stake // --- ITEM ( total_issuance ) pub const TOTAL_ISSUANCE: Item = Item::new("total_issuance"); // --- MAP ( hot ) --> stake | Returns the total amount of stake under a hotkey. @@ -28,7 +32,8 @@ pub const TOTAL_HOTKEY_STAKE: Map<&Addr, u64> = Map::new("total_hotkey_stake"); pub const TOTAL_COLDKEY_STAKE: Map<&Addr, u64> = Map::new("total_coldkey_stake"); // --- MAP ( hot ) --> cold | Returns the controlling coldkey for a hotkey. pub const OWNER: Map<&Addr, Addr> = Map::new("hotkey_coldkey"); -// --- MAP ( hot ) --> stake | Returns the hotkey delegation stake. And signals that this key is open for delegation. +// --- MAP ( hot ) --> stake take | Returns the hotkey delegation stake take(commission). And signals that this key is open for delegation. +// TODO rename storage name pub const DELEGATES: Map<&Addr, u16> = Map::new("hotkey_stake"); // --- DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. pub const STAKE: Map<(&Addr, &Addr), u64> = Map::new("staked_hotkey_coldkey"); @@ -116,7 +121,19 @@ pub const SUBNET_OWNER: Map = Map::new("subnet_owner"); // --- MAP (netuid ) --> subnet_locked pub const SUBNET_LOCKED: Map = Map::new("subnet_locked"); // --- MAP (netuid ) --> metadata +// TODO need to write migration pub const METADATA: Map = Map::new("metadata"); +pub const NETWORKS_METADATA: Map = Map::new("networks_metadata"); + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Metadata { + pub name: String, + pub particle: String, // particle + pub description: String, // particle + pub logo: String, // particle + pub types: String, + pub extra: String, +} // ================================= // ==== Axon / Promo Endpoints ===== diff --git a/src/subnet_info.rs b/src/subnet_info.rs index aa319a3..039f9cf 100644 --- a/src/subnet_info.rs +++ b/src/subnet_info.rs @@ -3,9 +3,9 @@ use cosmwasm_std::{Addr, Deps, Order, StdResult}; use crate::root::if_subnet_exist; use crate::state::{ - ACTIVITY_CUTOFF, ADJUSTMENT_INTERVAL, BLOCKS_SINCE_LAST_STEP, BONDS_MOVING_AVERAGE, BURN, + Metadata, ACTIVITY_CUTOFF, ADJUSTMENT_INTERVAL, BLOCKS_SINCE_LAST_STEP, BONDS_MOVING_AVERAGE, BURN, DIFFICULTY, EMISSION_VALUES, IMMUNITY_PERIOD, KAPPA, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, - MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, METADATA, + MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, NETWORKS_METADATA, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_MODALITY, NETWORK_REGISTRATION_ALLOWED, RHO, SUBNET_OWNER, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, @@ -30,7 +30,7 @@ pub struct SubnetInfo { pub emission_values: u64, pub burn: u64, pub owner: Addr, - pub metadata: String, + pub metadata: Metadata, } #[cw_serde] @@ -75,7 +75,7 @@ pub fn get_subnet_info(deps: Deps, netuid: u16) -> StdResult> let emission_values = EMISSION_VALUES.load(deps.storage, netuid)?; let burn = BURN.load(deps.storage, netuid)?; let owner = SUBNET_OWNER.load(deps.storage, netuid)?; - let metadata = METADATA.load(deps.storage, netuid)?; + let metadata = NETWORKS_METADATA.load(deps.storage, netuid)?; return Ok(Some(SubnetInfo { rho: rho.into(), diff --git a/src/test_helpers.rs b/src/test_helpers.rs index 3bf9677..e64fc79 100644 --- a/src/test_helpers.rs +++ b/src/test_helpers.rs @@ -1,9 +1,10 @@ #[cfg(test)] use std::fs::File; use std::io::Write; +use std::ops::Deref; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier}; -use cosmwasm_std::{coin, Addr, Coin, DepsMut, Empty, Env, OwnedDeps, Storage}; +use cosmwasm_std::{coin, Addr, Coin, DepsMut, Empty, Env, OwnedDeps, Storage, Uint128, CustomQuery, Api, QuerierWrapper}; use cw_multi_test::{Contract, ContractWrapper, Executor}; use cw_storage_gas_meter::MemoryStorageWithGas; use cyber_std::CyberMsgWrapper; @@ -59,6 +60,14 @@ fn mock_app(contract_balance: &[Coin]) -> CyberApp { contract_balance.to_vec(), ) .unwrap(); + router + .bank + .init_balance( + storage, + &Addr::unchecked(ROOT), + contract_balance.to_vec(), + ) + .unwrap(); }); app } @@ -89,7 +98,7 @@ pub fn instantiate_contract() -> (TestDeps, Env) { let mut env = mock_env(); env.block.height = 1; - let info = mock_info(ROOT, &[]); + let info = mock_info(ROOT, &[coin(1u128, "boot".to_string())]); let res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap(); // root_register(deps.as_mut(), env.clone(), ROOT, ROOT); assert_eq!(res.messages.len(), 0); @@ -98,7 +107,7 @@ pub fn instantiate_contract() -> (TestDeps, Env) { execute( deps.as_mut(), env.clone(), - mock_info("ROOT", &[]), + mock_info(ROOT, &[]), ExecuteMsg::BlockStep {}, ) .is_ok(), @@ -108,47 +117,48 @@ pub fn instantiate_contract() -> (TestDeps, Env) { (deps, env) } -// pub fn instantiate_contract_app(app: &mut CyberApp) -> Addr { -// // TODO fix this -// let cn_id = app.store_code(cn_contract()); -// let msg = crate::msg::InstantiateMsg {}; -// -// app.instantiate_contract( -// cn_id, -// Addr::unchecked(ROOT.to_string()), -// &msg, -// &[], -// "cybernet", -// None, -// ) -// .unwrap() -// } +pub fn instantiate_contract_app(app: &mut CyberApp) -> Addr { + // TODO fix this + let cn_id = app.store_code(cn_contract()); + let msg = crate::msg::InstantiateMsg {}; -// pub fn register_ok_neuron_app( -// app: &mut CyberApp, -// netuid: u16, -// hotkey: &str, -// coldkey: String, -// nonce: u64, -// ) { -// let msg = ExecuteMsg::Register { -// netuid, -// block_number: app.block_info().height, -// nonce, -// work: vec![], -// hotkey: hotkey.to_string(), -// coldkey, -// }; -// -// let res = app.execute_contract( -// Addr::unchecked(hotkey), -// Addr::unchecked(CT_ADDR.to_string()), -// &msg, -// &[], -// ); -// // app.update_block(|block| block.height += 100); -// assert_eq!(res.is_ok(), true); -// } + app.instantiate_contract( + cn_id, + Addr::unchecked(ROOT.to_string()), + &msg, + &[coin(1u128, "boot".to_string())], + "cybernet", + None, + ) + .unwrap() +} + +pub fn register_ok_neuron_app( + app: &mut CyberApp, + netuid: u16, + hotkey: &str, + coldkey: String, + nonce: u64, +) { + let msg = ExecuteMsg::Register { + netuid, + block_number: app.block_info().height, + nonce, + work: vec![0u8; 32], + hotkey: hotkey.to_string(), + coldkey, + }; + + let res = app.execute_contract( + Addr::unchecked(hotkey), + Addr::unchecked(CT_ADDR.to_string()), + &msg, + &[], + ); + println!("{:?}", res); + // app.update_block(|block| block.height += 100); + assert_eq!(res.is_ok(), true); +} pub fn register_ok_neuron( deps: DepsMut, @@ -316,7 +326,7 @@ pub fn step_block(mut deps: DepsMut, env: &mut Env) -> Result Vec<(Addr, u64, u64)> { // Get subnetwork size. let n: u16 = get_subnetwork_n(store, netuid); - println!("n:\n{:?}\n", n); + // println!("n:\n{:?}\n", n); // ====================== // == Active & updated == @@ -51,29 +51,29 @@ pub fn epoch_dense( // Get current block. // let current_block: u64 = env.block.height; - println!("current_block:\n{:?}\n", current_block); + // println!("current_block:\n{:?}\n", current_block); // Get activity cutoff. let activity_cutoff: u64 = get_activity_cutoff(store, netuid) as u64; - println!("activity_cutoff:\n{:?}\n", activity_cutoff); + // println!("activity_cutoff:\n{:?}\n", activity_cutoff); // Last update vector. let last_update: Vec = get_last_update(store, netuid); - println!("Last update:\n{:?}\n", &last_update); + // println!("Last update:\n{:?}\n", &last_update); // Inactive mask. let inactive: Vec = last_update .iter() .map(|updated| *updated + activity_cutoff < current_block) .collect(); - println!("Inactive:\n{:?}\n", inactive.clone()); + // println!("Inactive:\n{:?}\n", inactive.clone()); // Logical negation of inactive. let active: Vec = inactive.iter().map(|&b| !b).collect(); // Block at registration vector (block when each neuron was most recently registered). let block_at_registration: Vec = get_block_at_registration(store, netuid); - println!("Block at registration:\n{:?}\n", &block_at_registration); + // println!("Block at registration:\n{:?}\n", &block_at_registration); // Outdated matrix, updated_ij=True if i has last updated (weights) after j has last registered. let outdated: Vec> = last_update @@ -85,7 +85,7 @@ pub fn epoch_dense( .collect() }) .collect(); - println!("Outdated:\n{:?}\n", &outdated); + // println!("Outdated:\n{:?}\n", &outdated); // =========== // == Stake == @@ -99,7 +99,7 @@ pub fn epoch_dense( let (uid_i, hotkey) = item.unwrap(); hotkeys.push((uid_i, hotkey)); } - println!("hotkeys: {:?}", &hotkeys); + // println!("hotkeys: {:?}", &hotkeys); // Access network stake as normalized vector. let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; @@ -108,7 +108,7 @@ pub fn epoch_dense( } inplace_normalize_64(&mut stake_64); let stake: Vec = vec_fixed64_to_fixed32(stake_64); - println!("S:\n{:?}\n", &stake); + // println!("S:\n{:?}\n", &stake); // ======================= // == Validator permits == @@ -116,18 +116,18 @@ pub fn epoch_dense( // Get validator permits. let validator_permits: Vec = get_validator_permit(store, netuid); - println!("validator_permits: {:?}", validator_permits); + // println!("validator_permits: {:?}", validator_permits); // Logical negation of validator_permits. let validator_forbids: Vec = validator_permits.iter().map(|&b| !b).collect(); // Get max allowed validators. let max_allowed_validators: u16 = get_max_allowed_validators(store, netuid); - println!("max_allowed_validators: {:?}", max_allowed_validators); + // println!("max_allowed_validators: {:?}", max_allowed_validators); // Get new validator permits. let new_validator_permits: Vec = is_topk(&stake, max_allowed_validators as usize); - println!("new_validator_permits: {:?}", new_validator_permits); + // println!("new_validator_permits: {:?}", new_validator_permits); // ================== // == Active Stake == @@ -143,7 +143,7 @@ pub fn epoch_dense( // Normalize active stake. inplace_normalize(&mut active_stake); - println!("S:\n{:?}\n", &active_stake); + // println!("S:\n{:?}\n", &active_stake); // ============= // == Weights == @@ -151,23 +151,23 @@ pub fn epoch_dense( // Access network weights row unnormalized. let mut weights: Vec> = get_weights(store, netuid); - println!("W:\n{:?}\n", &weights); + // println!("W:\n{:?}\n", &weights); // Mask weights that are not from permitted validators. inplace_mask_rows(&validator_forbids, &mut weights); - println!("W (permit): {:?}", &weights); + // println!("W (permit): {:?}", &weights); // Remove self-weight by masking diagonal. inplace_mask_diag(&mut weights); - println!("W (permit+diag):\n{:?}\n", &weights); + // println!("W (permit+diag):\n{:?}\n", &weights); // Mask outdated weights: remove weights referring to deregistered neurons. inplace_mask_matrix(&outdated, &mut weights); - println!("W (permit+diag+outdate):\n{:?}\n", &weights); + // println!("W (permit+diag+outdate):\n{:?}\n", &weights); // Normalize remaining weights. inplace_row_normalize(&mut weights); - println!("W (mask+norm):\n{:?}\n", &weights); + // println!("W (mask+norm):\n{:?}\n", &weights); // ================================ // == Consensus, Validator Trust == @@ -194,7 +194,7 @@ pub fn epoch_dense( inplace_normalize(&mut ranks); let incentive: Vec = ranks.clone(); - println!("I:\n{:?}\n", &incentive); + // println!("I:\n{:?}\n", &incentive); // ========================= // == Bonds and Dividends == @@ -204,12 +204,12 @@ pub fn epoch_dense( let mut bonds: Vec> = get_bonds(store, netuid); inplace_mask_matrix(&outdated, &mut bonds); // mask outdated bonds inplace_col_normalize(&mut bonds); // sum_i b_ij = 1 - println!("B:\n{:?}\n", &bonds); + // println!("B:\n{:?}\n", &bonds); // Compute bonds delta column normalized. let mut bonds_delta: Vec> = row_hadamard(&weights, &active_stake); // ΔB = W◦S inplace_col_normalize(&mut bonds_delta); // sum_i b_ij = 1 - println!("ΔB:\n{:?}\n", &bonds_delta); + // println!("ΔB:\n{:?}\n", &bonds_delta); // Compute bonds moving average. let bonds_moving_average: I64F64 = @@ -217,12 +217,12 @@ pub fn epoch_dense( let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); let mut ema_bonds: Vec> = mat_ema(&bonds_delta, &bonds, alpha); inplace_col_normalize(&mut ema_bonds); // sum_i b_ij = 1 - println!("emaB:\n{:?}\n", &ema_bonds); + // println!("emaB:\n{:?}\n", &ema_bonds); // Compute dividends: d_i = SUM(j) b_ij * inc_j let mut dividends: Vec = matmul_transpose(&ema_bonds, &incentive); inplace_normalize(&mut dividends); - println!("D:\n{:?}\n", ÷nds); + // println!("D:\n{:?}\n", ÷nds); // ================================= // == Emission and Pruning scores == @@ -292,15 +292,15 @@ pub fn epoch_dense( .collect(); // api.debug(&format!( "nSE: {:?}", &normalized_server_emission )); - println!("SE: {:?}", &server_emission); + // println!("SE: {:?}", &server_emission); // api.debug(&format!( "nVE: {:?}", &normalized_validator_emission )); - println!("VE: {:?}", &validator_emission); + // println!("VE: {:?}", &validator_emission); // api.debug(&format!( "nCE: {:?}", &normalized_combined_emission )); - println!("CE: {:?}", &combined_emission); + // println!("CE: {:?}", &combined_emission); // Set pruning scores using combined emission scores. let pruning_scores: Vec = normalized_combined_emission.clone(); - println!("P: {:?}", &pruning_scores); + // println!("P: {:?}", &pruning_scores); // =================== // == Value storage == diff --git a/src/tests/epoch.rs b/src/tests/epoch.rs index 32f0217..b8875b9 100644 --- a/src/tests/epoch.rs +++ b/src/tests/epoch.rs @@ -1,11 +1,17 @@ -use crate::contract::execute; +use std::time::Instant; + +use cosmwasm_std::testing::mock_info; +use cosmwasm_std::{Addr, Api, DepsMut, Env, Storage}; +use rand::{distributions::Uniform, rngs::StdRng, seq::SliceRandom, thread_rng, Rng, SeedableRng}; +use substrate_fixed::transcendental::{cos, ln, sqrt, PI}; +use substrate_fixed::types::{I32F32, I64F64}; + +use crate::contract::{execute, get_economy}; use crate::epoch::{epoch, get_bonds}; use crate::msg::ExecuteMsg; use crate::registration::create_work_for_block_number; use crate::root::{get_subnet_emission_value, set_emission_values}; -use crate::staking::{ - get_total_stake, get_total_stake_for_hotkey, increase_stake_on_coldkey_hotkey_account, -}; +use crate::staking::{get_total_stake_for_hotkey, increase_stake_on_coldkey_hotkey_account}; use crate::test_helpers::{ add_balance_to_coldkey_account, add_network, instantiate_contract, pow_register_ok_neuron, run_step_to_block, set_weights, step_block, @@ -20,12 +26,6 @@ use crate::utils::{ set_max_weight_limit, set_min_allowed_weights, set_min_difficulty, set_target_registrations_per_interval, set_weights_set_rate_limit, }; -use cosmwasm_std::testing::mock_info; -use cosmwasm_std::{Addr, Api, DepsMut, Env, Storage}; -use rand::{distributions::Uniform, rngs::StdRng, seq::SliceRandom, thread_rng, Rng, SeedableRng}; -use std::time::Instant; -use substrate_fixed::transcendental::{cos, ln, sqrt, PI}; -use substrate_fixed::types::{I32F32, I64F64}; pub fn fixed(val: f32) -> I32F32 { I32F32::from_num(val) @@ -205,6 +205,7 @@ fn init_run_epochs( get_max_allowed_validators(deps.storage, netuid), validators.len() as u16 ); + epoch( deps.storage, deps.api, @@ -703,7 +704,14 @@ fn test_10_graph() { Addr::unchecked(i.to_string()), i as u16, 1, - ) + ); + + let gas = deps.storage.gas_used.borrow(); + println!( + "total {:?} gas {:?} write {:?} read {:?}", + gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + drop(gas); } assert_eq!(get_subnetwork_n(&deps.storage, netuid), 10); env.block.height += 1; // run to next block to ensure weights are set on nodes after their registration block @@ -718,6 +726,13 @@ fn test_10_graph() { let res = execute(deps.as_mut(), env.clone(), info, msg); // println!("{:?} {:?}",i, res); assert_eq!(res.is_ok(), true); + + let gas = deps.storage.gas_used.borrow(); + println!( + "total {:?} gas {:?} write {:?} read {:?}", + gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + drop(gas); } // Run the epoch. epoch( @@ -728,6 +743,12 @@ fn test_10_graph() { env.block.height, ) .unwrap(); + let gas = deps.storage.gas_used.borrow(); + println!( + "total {:?} gas {:?} write {:?} read {:?}", + gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + drop(gas); // Check return values. for i in 0..n { assert_eq!( @@ -826,7 +847,7 @@ fn test_512_graph() { } } -// // Test an epoch on a graph with 4096 nodes, of which the first 256 are validators setting random non-self weights, and the rest servers setting only self-weights. +// Test an epoch on a graph with 512 nodes, of which the first 64 are validators setting random non-self weights, and the rest servers setting only self-weights. #[test] fn test_512_graph_random_weights() { let netuid: u16 = 2; @@ -976,7 +997,7 @@ fn test_4096_graph() { true, ); // Because of genesis init - assert_eq!(get_total_stake(&deps.storage), 21_000_000_000_000_300); + // assert_eq!(get_total_stake(&deps.storage), 21_000_000_000_000_300); // assert_eq!(get_total_stake(&deps.storage), 21_000_000_000_000_000); let bonds = get_bonds(&deps.storage, netuid); for uid in &validators { @@ -2404,6 +2425,333 @@ fn test_validator_permits() { } } +#[test] +fn test_graph_with_gas_sim() { + let netuid: u16 = 2; + let network_n: u16 = 512; + let validators_n: u16 = 64; + // let max_stake_per_validator: u64 = 328_125_000_000_000; // 21_000_000_000_000_000 / 64 + let epochs: u16 = 3; + log::info!("test_{network_n:?}_graph ({validators_n:?} validators)"); + for interleave in 0..3 { + for server_self in vec![false, true] { + // server-self weight off/on + let (validators1, servers1) = distribute_nodes( + validators_n as usize, + network_n as usize, + interleave as usize, + ); + let validators = &validators1; + let servers = &servers1; + let server: usize = servers[0] as usize; + let validator: usize = validators[0] as usize; + let (mut deps, mut env) = instantiate_contract(); + let gas = deps.storage.gas_used.borrow(); + println!( + "before total {:?} gas {:?} write {:?} read {:?}", + gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + drop(gas); + + // fn init_run_epochs( + // mut deps: DepsMut, + // mut env: &mut Env, + // netuid: u16, + // n: u16, + // validators: &Vec, + // servers: &Vec, + // epochs: u16, + // stake_per_validator: u64, + // server_self: bool, + // input_stake: &Vec, + // use_input_stake: bool, + // input_weights: &Vec>, + // use_input_weights: bool, + // random_weights: bool, + // random_seed: u64, + // sparse: bool, + // ) { + + // init_run_epochs( + // deps.as_mut(), + // &mut env, + // netuid, + // network_n, + // &validators, + // &servers, + // epochs, + // 1, + // server_self, + // &vec![], + // false, + // &vec![], + // false, + // true, + // interleave as u64, + // false, + // ); + + // netuid: u16, + let n = network_n; + // validators: &Vec, + // servers: &Vec, + // epochs: u16, + let stake_per_validator = 1; + // server_self: bool, + let input_stake: &Vec = &vec![]; + let use_input_stake = false; + let input_weights: &Vec> = &vec![]; + let use_input_weights = false; + let random_weights = true; + let random_seed = interleave; + let sparse = false; + + // let (mut deps, mut env) = instantiate_contract(); + // === Create the network + add_network(&mut deps.storage, netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead + + // === Register uids + set_max_allowed_uids(&mut deps.storage, netuid, n); + for key in 0..n { + let stake: u64; + if use_input_stake { + stake = input_stake[key as usize]; + } else { + stake = if validators.contains(&key) { + stake_per_validator + } else { + 0 + }; // only validators receive stake + } + // let stake: u64 = 1; // alternative test: all nodes receive stake, should be same outcome, except stake + add_balance_to_coldkey_account(&Addr::unchecked((1000 + key).to_string()), stake); + append_neuron( + &mut deps.storage, + &mut deps.api, + netuid, + &(Addr::unchecked((1000 + key).to_string())), + 0, + ) + .unwrap(); + increase_stake_on_coldkey_hotkey_account( + &mut deps.storage, + &Addr::unchecked((1000 + key).to_string()), + &Addr::unchecked((1000 + key).to_string()), + stake as u64, + ); + } + assert_eq!(get_subnetwork_n(&mut deps.storage, netuid), n); + + // === Issue validator permits + set_max_allowed_validators(&mut deps.storage, netuid, validators.len() as u16); + + assert_eq!( + get_max_allowed_validators(&mut deps.storage, netuid), + validators.len() as u16 + ); + + epoch( + &mut deps.storage, + &mut deps.api, + netuid, + 1_000_000_000, + env.block.height, + ) + .unwrap(); // run first epoch to set allowed validators + step_block(deps.as_mut(), &mut env).unwrap(); // run to next block to ensure weights are set on nodes after their registration block + + // === Set weights + let mut rng = StdRng::seed_from_u64(random_seed); // constant seed so weights over multiple runs are equal + let range = Uniform::new(0, u16::MAX); + let mut weights: Vec = vec![u16::MAX / n; servers.len() as usize]; + for uid in validators { + if random_weights { + weights = (0..servers.len()).map(|_| rng.sample(&range)).collect(); + weights = normalize_weights(weights); + // assert_eq!(weights.iter().map(|x| *x as u64).sum::(), u16::MAX as u64); // normalized weight sum not always u16::MAX + } + if use_input_weights { + let sparse_weights = input_weights[*uid as usize].clone(); + weights = sparse_weights.iter().map(|(_, w)| *w).collect(); + let srvs: Vec = sparse_weights.iter().map(|(s, _)| *s).collect(); + + let result = set_weights( + deps.as_mut(), + env.clone(), + (1000 + uid).to_string().as_str(), + netuid, + srvs.clone(), + weights.clone(), + 0, + ); + assert_eq!(result.is_ok(), true); + + + // let msg = ExecuteMsg::SetWeights { + // netuid, + // dests: srvs.clone(), + // weights: weights.clone(), + // version_key: 0, + // }; + // let info = mock_info((1000 + uid).to_string().as_str(), &[]); + // let res = execute(deps.branch(), env.clone(), info, msg); + // assert_eq!(res.is_ok(), true); + + } else { + let result = set_weights( + deps.as_mut(), + env.clone(), + (1000 + uid).to_string().as_str(), + netuid, + servers.clone(), + weights.clone(), + 0, + ); + assert_eq!(result.is_ok(), true); + + // let msg = ExecuteMsg::SetWeights { + // netuid, + // dests: servers.clone(), + // weights: weights.clone(), + // version_key: 0, + // }; + // let info = mock_info((1000 + uid).to_string().as_str(), &[]); + // let res = execute(deps.branch(), env.clone(), info, msg); + // assert_eq!(res.is_ok(), true); + } + } + for uid in servers { + if server_self { + let result = set_weights( + deps.as_mut(), + env.clone(), + (1000 + uid).to_string().as_str(), + netuid, + vec![*uid as u16], + vec![u16::MAX], + 0, + ); + assert_eq!(result.is_ok(), true); + + // let msg = ExecuteMsg::SetWeights { + // netuid, + // dests: vec![*uid as u16], + // weights: vec![u16::MAX], + // version_key: 0, + // }; // server self-weight + // let info = mock_info((1000 + uid).to_string().as_str(), &[]); + // let res = execute(deps.branch(), env.clone(), info, msg); + // assert_eq!(res.is_ok(), true); + } + } + + // === Run the epochs. + for n in 0..epochs { + println!("Start {n} epoch"); + let start = Instant::now(); + let gas = deps.storage.gas_used.borrow(); + let gas_total = gas.total; + let gas_last = gas.last; + let gas_write_cnt = gas.write_cnt; + let gas_read_cnt = gas.read_cnt; + println!( + "before epoch {:?} total {:?} gas {:?} write {:?} read {:?}", + n, gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + drop(gas); + + if sparse { + epoch( + &mut deps.storage, + &mut deps.api, + netuid, + 1_000_000_000, + env.block.height, + ) + .unwrap(); + } else { + epoch_dense(&mut deps.storage, netuid, 1_000_000_000, env.block.height); + } + + let gas = deps.storage.gas_used.borrow(); + println!( + "after epoch {:?} total {:?} gas {:?} write {:?} read {:?}", + n, gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + println!( + "after epoch {:?} total {:?} gas {:?} write {:?} read {:?}", + n, gas_total, gas_last, gas_write_cnt, gas_read_cnt + ); + println!( + "diff epoch {:?} gas {:?} write {:?} read {:?}", + n, gas.total-gas_total, gas.write_cnt-gas_write_cnt, gas.read_cnt-gas_read_cnt + ); + drop(gas); + + let duration = start.elapsed(); + println!( + "Time elapsed in (sparse={sparse}) epoch() is: {:?}", + duration + ); + } + + // let bonds = get_bonds(&deps.storage, netuid ); + // for (uid, node) in vec![ (validators[0], "validator"), (servers[0], "server") ] { + // log::info!("\n{node}" ); + // uid_stats(netuid, uid); + // log::info!("bonds: {:?} (on validator), {:?} (on server)", bonds[uid as usize][0], bonds[uid as usize][servers[0] as usize]); + // } + + + let gas = deps.storage.gas_used.borrow(); + println!( + "after total {:?} gas {:?} write {:?} read {:?}", + gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + drop(gas); + + let bonds = get_bonds(&deps.storage, netuid); + for uid in validators { + // assert_eq!( + // get_total_stake_for_hotkey( + // &deps.storage, + // &Addr::unchecked((1000 + uid).to_string()), + // ), + // max_stake_per_validator + // ); + assert_eq!(get_rank_for_uid(&deps.storage, netuid, *uid), 0); + assert_eq!(get_trust_for_uid(&deps.storage, netuid, *uid), 0); + assert_eq!(get_consensus_for_uid(&deps.storage, netuid, *uid), 0); + assert_eq!(get_incentive_for_uid(&deps.storage, netuid, *uid), 0); + // assert_eq!(get_dividends_for_uid(&deps.storage, netuid, *uid), 1023); // Note D = floor(1 / 64 * 65_535) = 1023 + // assert_eq!(get_emission_for_uid(&deps.storage, netuid, *uid), 7812500); // Note E = 0.5 / 200 * 1_000_000_000 = 7_812_500 + assert_eq!(bonds[*uid as usize][validator], 0.0); + // assert_eq!(bonds[*uid as usize][server], I32F32::from_num(65_535)); + // Note B_ij = floor(1 / 64 * 65_535) / 65_535 = 1023 / 65_535, then max-upscaled to 65_535 + } + for uid in servers { + assert_eq!( + get_total_stake_for_hotkey( + &deps.storage, + &Addr::unchecked((1000 + uid).to_string()), + ), + 0 + ); + // assert_eq!(get_rank_for_uid(&deps.storage, netuid, *uid), 146); // Note R = floor(1 / (512 - 64) * 65_535) = 146 + // assert_eq!(get_trust_for_uid(&deps.storage, netuid, *uid), 65535); + // assert_eq!(get_consensus_for_uid(&deps.storage, netuid, *uid), 146); // Note C = floor(1 / (512 - 64) * 65_535) = 146 + // assert_eq!(get_incentive_for_uid(&deps.storage, netuid, *uid), 146); // Note I = floor(1 / (512 - 64) * 65_535) = 146 + assert_eq!(get_dividends_for_uid(&deps.storage, netuid, *uid), 0); + // assert_eq!(get_emission_for_uid(&deps.storage, netuid, *uid), 1116071); // Note E = floor(0.5 / (512 - 64) * 1_000_000_000) = 1_116_071 + assert_eq!(bonds[*uid as usize][validator], 0.0); + assert_eq!(bonds[*uid as usize][server], 0.0); + } + drop(deps); + drop(env); + } + } +} + // // Map the retention graph for consensus guarantees with an single epoch on a graph with 512 nodes, of which the first 64 are validators, the graph is split into a major and minor set, each setting specific weight on itself and the complement on the other. // // // // ```import torch diff --git a/src/tests/registration.rs b/src/tests/registration.rs index 88073d0..6f8e96c 100644 --- a/src/tests/registration.rs +++ b/src/tests/registration.rs @@ -1,5 +1,5 @@ use cosmwasm_std::testing::mock_info; -use cosmwasm_std::Addr; +use cosmwasm_std::{Addr, Uint128}; use crate::contract::execute; use crate::msg::ExecuteMsg; @@ -1000,7 +1000,7 @@ fn test_registration_get_neuron_metadata() { // let neuron_uid = get_uid_for_net_and_hotkey(&deps.storage, netuid, &hotkey_account_id ).unwrap(); let neuron: AxonInfoOf = get_axon_info(&deps.storage, netuid, &Addr::unchecked(hotkey_account_id)); - assert_eq!(neuron.ip, 0); + assert_eq!(neuron.ip, Uint128::zero()); assert_eq!(neuron.version, 0); assert_eq!(neuron.port, 0) } diff --git a/src/tests/root.rs b/src/tests/root.rs index 35eda7a..3582b27 100644 --- a/src/tests/root.rs +++ b/src/tests/root.rs @@ -1,13 +1,14 @@ use cosmwasm_std::Addr; use crate::block_step::blocks_until_next_epoch; +use crate::contract::get_economy; use crate::registration::create_work_for_block_number; use crate::root::{ get_all_subnet_netuids, get_max_subnets, get_network_lock_cost, get_num_subnets, get_subnet_emission_value, if_subnet_exist, remove_network, root_epoch, set_lock_reduction_interval, }; -use crate::staking::hotkey_is_delegate; +use crate::staking::{get_total_stake, hotkey_is_delegate}; use crate::state_info::get_state_info; use crate::test_helpers::{ add_balance_to_coldkey_account, add_network, add_stake, burned_register_ok_neuron, @@ -15,12 +16,9 @@ use crate::test_helpers::{ step_block, }; use crate::uids::{get_subnetwork_n, get_uid_for_net_and_hotkey, is_hotkey_registered_on_network}; -use crate::utils::{ - do_sudo_set_block_emission, get_pending_emission, get_total_issuance, set_block_emission, - set_burn, set_difficulty, set_max_allowed_uids, set_max_registrations_per_block, - set_target_registrations_per_interval, set_tempo, set_weights_set_rate_limit, -}; +use crate::utils::{do_sudo_set_block_emission, get_pending_emission, get_total_issuance, set_block_emission, set_burn, set_difficulty, set_max_allowed_uids, set_max_registrations_per_block, set_target_registrations_per_interval, set_tempo, set_weights_set_rate_limit, unstake_all}; use crate::ContractError; +use crate::delegate_info::get_delegate_by_existing_account; #[test] fn test_root_register_network_exist() { @@ -96,7 +94,7 @@ fn test_root_register_stake_based_pruning_works() { let root_netuid: u16 = 0; let other_netuid: u16 = 1; remove_network(&mut deps.storage, 1).unwrap(); // delete after contract creation network - add_network(&mut deps.storage, other_netuid, 0, 0); + add_network(&mut deps.storage, other_netuid, 10, 0); // Set params to allow all registrations to subnet. set_burn(&mut deps.storage, other_netuid, 0); @@ -207,6 +205,15 @@ fn test_root_register_stake_based_pruning_works() { // Check that they are NOT senate members // assert!(!is_senate_member(&hot)); } + + println!("total stake: {:?}", get_total_stake(&deps.storage)); + // unstake_all(&mut deps.storage, Some(128)); + // println!("total stake: {:?}", get_total_stake(&deps.storage)); + let economy = get_economy(&deps.storage); + println!("{:?}", economy); + + let delegate_info = get_delegate_by_existing_account(&deps.storage, &Addr::unchecked("1100")); + println!("{:?}", delegate_info); } #[test] @@ -297,10 +304,37 @@ fn test_root_set_weights() { // Run the root epoch println!("Running Root epoch"); set_tempo(&mut deps.storage, root_netuid, 1); + + { + let gas = deps.storage.gas_used.borrow(); + // let gas_total = gas.total; + // let gas_last = gas.last; + // let gas_write_cnt = gas.write_cnt; + // let gas_read_cnt = gas.read_cnt; + println!( + "before total {:?} gas {:?} write {:?} read {:?}", + gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + } + // drop(gas); + assert_eq!( root_epoch(&mut deps.storage, &deps.api, 1_000_000_001).is_ok(), true ); + + { + let gas = deps.storage.gas_used.borrow(); + println!( + "after epoch {:?} total {:?} gas {:?} write {:?} read {:?}", + n, gas.total, gas.last, gas.write_cnt, gas.read_cnt + ); + // println!( + // "diff epoch {:?} gas {:?} write {:?} read {:?}", + // n, gas.total-gas_total, gas.write_cnt-gas_write_cnt, gas.read_cnt-gas_read_cnt + // ); + } + // Check that the emission values have been set. for netuid in 1..n { println!("check emission for netuid: {}", netuid); diff --git a/src/tests/serving.rs b/src/tests/serving.rs index 6b292bb..bf97b05 100644 --- a/src/tests/serving.rs +++ b/src/tests/serving.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::Addr; +use cosmwasm_std::{Addr, Uint128}; use crate::serving::{get_axon_info, get_prometheus_info, is_valid_ip_address, is_valid_ip_type}; use crate::test_helpers::{ @@ -66,7 +66,7 @@ fn test_serving_ok() { assert!(result.is_ok()); let neuron = get_axon_info(&deps.storage, netuid, &Addr::unchecked(hotkey_account_id)); - assert_eq!(neuron.ip, ip); + assert_eq!(neuron.ip, Uint128::from(ip)); assert_eq!(neuron.version, version); assert_eq!(neuron.port, port); assert_eq!(neuron.ip_type, ip_type); @@ -119,7 +119,7 @@ fn test_serving_set_metadata_update() { assert!(result.is_ok()); let neuron = get_axon_info(&deps.storage, netuid, &Addr::unchecked(hotkey_account_id)); - assert_eq!(neuron.ip, ip); + assert_eq!(neuron.ip, Uint128::from(ip)); assert_eq!(neuron.version, version); assert_eq!(neuron.port, port); assert_eq!(neuron.ip_type, ip_type); @@ -150,7 +150,7 @@ fn test_serving_set_metadata_update() { assert!(result.is_ok()); let neuron = get_axon_info(&deps.storage, netuid, &Addr::unchecked(hotkey_account_id)); - assert_eq!(neuron.ip, ip2); + assert_eq!(neuron.ip, Uint128::from(ip2)); assert_eq!(neuron.version, version2); assert_eq!(neuron.port, port2); assert_eq!(neuron.ip_type, ip_type2); @@ -361,7 +361,7 @@ fn test_prometheus_serving_ok() { assert!(result.is_ok()); let neuron = get_prometheus_info(&deps.storage, netuid, &Addr::unchecked(hotkey_account_id)); - assert_eq!(neuron.ip, ip); + assert_eq!(neuron.ip, Uint128::from(ip)); assert_eq!(neuron.version, version); assert_eq!(neuron.port, port); assert_eq!(neuron.ip_type, ip_type); @@ -409,7 +409,7 @@ fn test_prometheus_serving_set_metadata_update() { assert!(result.is_ok()); let neuron = get_prometheus_info(&deps.storage, netuid, &Addr::unchecked(hotkey_account_id)); - assert_eq!(neuron.ip, ip); + assert_eq!(neuron.ip, Uint128::from(ip)); assert_eq!(neuron.version, version); assert_eq!(neuron.port, port); assert_eq!(neuron.ip_type, ip_type); @@ -432,7 +432,7 @@ fn test_prometheus_serving_set_metadata_update() { assert!(result.is_ok()); let neuron = get_prometheus_info(&deps.storage, netuid, &Addr::unchecked(hotkey_account_id)); - assert_eq!(neuron.ip, ip2); + assert_eq!(neuron.ip, Uint128::from(ip2)); assert_eq!(neuron.version, version2); assert_eq!(neuron.port, port2); assert_eq!(neuron.ip_type, ip_type2); diff --git a/src/uids.rs b/src/uids.rs index 7b040ea..9931814 100644 --- a/src/uids.rs +++ b/src/uids.rs @@ -3,12 +3,15 @@ use cosmwasm_std::{Addr, Api, CosmosMsg, Order, StdError, StdResult, Storage}; use crate::staking::unstake_all_coldkeys_from_hotkey_account; use crate::state::{ ACTIVE, BLOCK_AT_REGISTRATION, BONDS, CONSENSUS, DIVIDENDS, EMISSION, INCENTIVE, - IS_NETWORK_MEMBER, KEYS, LAST_UPDATE, PRUNING_SCORES, RANK, SUBNETWORK_N, TOTAL_HOTKEY_STAKE, + IS_NETWORK_MEMBER, KEYS, LAST_UPDATE, PRUNING_SCORES, RANK, SUBNETWORK_N, TRUST, UIDS, VALIDATOR_PERMIT, VALIDATOR_TRUST, WEIGHTS, }; use crate::utils::set_active_for_uid; use crate::ContractError; +#[cfg(test)] +use crate::state::TOTAL_HOTKEY_STAKE; + pub fn get_subnetwork_n(store: &dyn Storage, netuid: u16) -> u16 { SUBNETWORK_N.load(store, netuid.clone()).unwrap() } @@ -71,7 +74,7 @@ pub fn replace_neuron( // Appends the uid to the network. pub fn append_neuron( store: &mut dyn Storage, - api: &dyn Api, + _api: &dyn Api, netuid: u16, new_hotkey: &Addr, block_number: u64, @@ -79,12 +82,12 @@ pub fn append_neuron( // 1. Get the next uid. This is always equal to subnetwork_n. let next_uid: u16 = get_subnetwork_n(store, netuid.clone()); - api.debug(&format!( - "👾 append_neuron ( netuid: {:?} | next_uid: {:?} | new_hotkey: {:?} ) ", - netuid, - new_hotkey.to_string(), - next_uid.clone() - )); + // api.debug(&format!( + // "👾 append_neuron ( netuid: {:?} | next_uid: {:?} | new_hotkey: {:?} ) ", + // netuid, + // new_hotkey.to_string(), + // next_uid.clone() + // )); // 2. Get and increase the uid count. SUBNETWORK_N.save(store, netuid.clone(), &(next_uid.clone() + 1))?; diff --git a/src/utils.rs b/src/utils.rs index f9316a1..5a5394b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,27 +1,33 @@ use std::ops::Deref; -use cosmwasm_std::{ensure, Addr, Api, DepsMut, Env, MessageInfo, Storage}; +use cosmwasm_std::{Addr, Api, BankMsg, coins, CosmosMsg, DepsMut, ensure, Env, MessageInfo, Order, StdResult, Storage, Uint128}; +use cyber_std::Response; +use crate::ContractError; use crate::root::if_subnet_exist; +use crate::stake_info::StakeInfo; +use crate::staking::decrease_stake_on_coldkey_hotkey_account; use crate::state::{ - ACTIVE, ACTIVITY_CUTOFF, ADJUSTMENTS_ALPHA, ADJUSTMENT_INTERVAL, BLOCKS_SINCE_LAST_STEP, - BLOCK_AT_REGISTRATION, BLOCK_EMISSION, BONDS_MOVING_AVERAGE, BURN, - BURN_REGISTRATIONS_THIS_INTERVAL, CONSENSUS, DEFAULT_TAKE, DIFFICULTY, DIVIDENDS, EMISSION, - EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, LAST_ADJUSTMENT_BLOCK, - LAST_MECHANISM_STEP_BLOCK, LAST_TX_BLOCK, LAST_UPDATE, MAX_ALLOWED_UIDS, + ACTIVE, ACTIVITY_CUTOFF, ADJUSTMENT_INTERVAL, ADJUSTMENTS_ALPHA, BLOCK_AT_REGISTRATION, BLOCK_EMISSION, + BLOCKS_SINCE_LAST_STEP, BONDS_MOVING_AVERAGE, BURN, + CONSENSUS, DEFAULT_TAKE, DENOM, DIFFICULTY, DIVIDENDS, EMISSION, + EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, LAST_TX_BLOCK, LAST_UPDATE, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, - MAX_WEIGHTS_LIMIT, METADATA, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, - NETWORK_IMMUNITY_PERIOD, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, - NETWORK_RATE_LIMIT, NETWORK_REGISTRATION_ALLOWED, PENDING_EMISSION, - POW_REGISTRATIONS_THIS_INTERVAL, PRUNING_SCORES, RANK, RAO_RECYCLED_FOR_REGISTRATION, - REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, ROOT, SERVING_RATE_LIMIT, - SUBNET_LIMIT, SUBNET_LOCKED, SUBNET_OWNER, SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, - TEMPO, TOTAL_ISSUANCE, TRUST, TX_RATE_LIMIT, VALIDATOR_PERMIT, VALIDATOR_PRUNE_LEN, - VALIDATOR_TRUST, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, + MAX_WEIGHTS_LIMIT, Metadata, NETWORKS_METADATA, MIN_ALLOWED_WEIGHTS, MIN_BURN, + MIN_DIFFICULTY, NETWORK_IMMUNITY_PERIOD, NETWORK_LOCK_REDUCTION_INTERVAL, + NETWORK_MIN_LOCK_COST, NETWORK_RATE_LIMIT, NETWORK_REGISTRATION_ALLOWED, PRUNING_SCORES, RANK, + RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, ROOT, + SERVING_RATE_LIMIT, STAKE, SUBNET_LIMIT, SUBNET_LOCKED, SUBNET_OWNER, + SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_ISSUANCE, TRUST, TX_RATE_LIMIT, + VALIDATOR_PERMIT, VALIDATOR_PRUNE_LEN, VALIDATOR_TRUST, VERSE_METADATA, WEIGHTS_SET_RATE_LIMIT, + WEIGHTS_VERSION_KEY, COMMISSION_CHANGE, }; use crate::uids::get_subnetwork_n; -use crate::ContractError; -use cyber_std::Response; + +#[cfg(test)] +use crate::state::{LAST_ADJUSTMENT_BLOCK, POW_REGISTRATIONS_THIS_INTERVAL, BURN_REGISTRATIONS_THIS_INTERVAL, + LAST_MECHANISM_STEP_BLOCK, PENDING_EMISSION, +}; pub fn ensure_subnet_owner_or_root( store: &dyn Storage, @@ -661,10 +667,10 @@ pub fn do_sudo_set_weights_set_rate_limit( WEIGHTS_SET_RATE_LIMIT.save(deps.storage, netuid, &weights_set_rate_limit)?; - deps.api.debug(&format!( - "🛸 WeightsSetRateLimitSet ( netuid: {:?} weights_set_rate_limit: {:?} ) ", - netuid, weights_set_rate_limit - )); + // deps.api.debug(&format!( + // "🛸 WeightsSetRateLimitSet ( netuid: {:?} weights_set_rate_limit: {:?} ) ", + // netuid, weights_set_rate_limit + // )); Ok(Response::default() .add_attribute("active", "weights_set_rate_limit_set") @@ -837,7 +843,7 @@ pub fn do_sudo_set_immunity_period( ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; ensure!( - immunity_period <= 7200, + immunity_period <= 14400, ContractError::StorageValueOutOfRange {} ); @@ -1599,15 +1605,181 @@ pub fn do_sudo_set_subnet_metadata( _env: Env, info: MessageInfo, netuid: u16, - particle: String, + metadata: Metadata, +) -> Result { + ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; + + ensure!(metadata.name.len() <= 16, ContractError::MetadataError {}); + if netuid.ne(&0u16) { + ensure!(metadata.name.ne(&"root".to_string()), ContractError::MetadataError {}); + } + ensure!(metadata.particle.len() == 46, ContractError::MetadataError {}); + ensure!(metadata.description.len() == 46, ContractError::MetadataError {}); + ensure!(metadata.logo.len() == 46, ContractError::MetadataError {}); + ensure!(metadata.types.len() <= 256, ContractError::MetadataError {}); + ensure!(metadata.extra.len() <= 256, ContractError::MetadataError {}); + + NETWORKS_METADATA.save(deps.storage, netuid, &metadata)?; + + Ok(Response::default() + .add_attribute("action", "subnet_metadata_set") + .add_attribute("netuid", format!("{}", netuid)) + .add_attribute("name", format!("{}", metadata.name)) + .add_attribute("particle", format!("{}", metadata.particle))) +} + +pub fn do_sudo_set_subnet_owner( + deps: DepsMut, + _env: Env, + info: MessageInfo, + netuid: u16, + new_owner: String, ) -> Result { + // TODO change to subnet_owner auth only ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!(particle.len() == 46, ContractError::MetadataSizeError {}); - METADATA.save(deps.storage, netuid, &particle)?; + let owner = deps.api.addr_validate(&new_owner)?; + + SUBNET_OWNER.save(deps.storage, netuid, &owner)?; Ok(Response::default() - .add_attribute("action", "metadata_set") + .add_attribute("action", "subnet_owner_set") .add_attribute("netuid", format!("{}", netuid)) - .add_attribute("metadata", format!("{}", particle))) + .add_attribute("owner", format!("{}", owner))) +} + +pub fn do_sudo_set_root( + deps: DepsMut, + _env: Env, + info: MessageInfo, + new_root: String, +) -> Result { + ensure_root(deps.storage, &info.sender)?; + + let root = deps.api.addr_validate(&new_root)?; + + ROOT.save(deps.storage, &root)?; + + Ok(Response::default() + .add_attribute("action", "root_set") + .add_attribute("root", format!("{}", root))) +} + +pub fn do_sudo_set_verse_metadata( + deps: DepsMut, + _env: Env, + info: MessageInfo, + metadata: Metadata, +) -> Result { + ensure_root(deps.storage, &info.sender)?; + + ensure!(metadata.name.len() <= 16, ContractError::MetadataError {}); + ensure!(metadata.particle.len() == 46, ContractError::MetadataError {}); + ensure!(metadata.description.len() == 46, ContractError::MetadataError {}); + ensure!(metadata.logo.len() == 46, ContractError::MetadataError {}); + + ensure!(metadata.types.len() <= 256, ContractError::MetadataError {}); + ensure!(metadata.extra.len() <= 256, ContractError::MetadataError {}); + + VERSE_METADATA.save(deps.storage, &metadata)?; + + Ok(Response::default() + .add_attribute("action", "verse_metadata_set") + .add_attribute("verse_name", format!("{}", metadata.name))) +} + +pub fn do_sudo_set_commission_change( + deps: DepsMut, + _env: Env, + info: MessageInfo, + change: bool, +) -> Result { + ensure_root(deps.storage, &info.sender)?; + + COMMISSION_CHANGE.save(deps.storage, &change)?; + + Ok(Response::default() + .add_attribute("action", "set_commission_change") + .add_attribute("commission_change", format!("{}", change))) } + +pub fn do_sudo_unstake_all( + deps: DepsMut, + _env: Env, + info: MessageInfo, + limit: Option, +) -> Result { + ensure_root(deps.storage, &info.sender)?; + + let take_limit = limit.unwrap_or(20) as usize; + + let stakes = STAKE.range(deps.storage, None, None, Order::Ascending) + .filter( + |item| { + if let Ok((_, stake)) = item { + stake > &0 + } else { + false + } + }, + ) + .take(take_limit) + .map(|item| { + item.map(|((hotkey, coldkey), stake)| StakeInfo { + hotkey, + coldkey, + stake, + }) + }) + .collect::>>()?; + + let mut msgs = vec![]; + for stake_info in stakes { + let (coldkey, hotkey, stake) = (stake_info.coldkey, stake_info.hotkey, stake_info.stake); + decrease_stake_on_coldkey_hotkey_account(deps.storage, &coldkey, &hotkey, stake)?; + + let denom = DENOM.load(deps.storage)?; + let msg = CosmosMsg::Bank(BankMsg::Send { + to_address: coldkey.to_string(), + amount: coins(Uint128::from(stake).u128(), denom), + }); + msgs.push(msg); + } + + Ok(Response::default() + .add_messages(msgs) + .add_attribute("action", "sudo_unstake_all")) +} + +#[cfg(test)] +pub fn unstake_all( + store: &mut dyn Storage, + limit: Option, +) { + let take_limit = limit.unwrap_or(20) as usize; + + let stakes = STAKE.range(store, None, None, Order::Ascending) + .filter( + |item| { + if let Ok((_, stake)) = item { + stake > &0 + } else { + false + } + }, + ) + .take(take_limit) + .map(|item| { + item.map(|((hotkey, coldkey), stake)| StakeInfo { + hotkey, + coldkey, + stake, + }) + }) + .collect::>>().unwrap(); + + for stake_info in stakes { + let (coldkey, hotkey, stake) = (stake_info.coldkey, stake_info.hotkey, stake_info.stake); + decrease_stake_on_coldkey_hotkey_account(store, &coldkey, &hotkey, stake).unwrap(); + } +} \ No newline at end of file diff --git a/src/weights.rs b/src/weights.rs index 66296f4..1f6aa5b 100644 --- a/src/weights.rs +++ b/src/weights.rs @@ -85,10 +85,10 @@ pub fn do_set_weights( ) -> Result { // --- 1. Check the caller's signature. This is the hotkey of a registered account. let hotkey = info.sender; - deps.api.debug(&format!( - "💡 do_set_weights ( origin:{:?} netuid:{:?}, uids:{:?}, values:{:?})", - hotkey, netuid, uids, values - )); + // deps.api.debug(&format!( + // "💡 do_set_weights ( origin:{:?} netuid:{:?}, uids:{:?}, values:{:?})", + // hotkey, netuid, uids, values + // )); // --- 2. Check that the length of uid list and value list are equal for this network. ensure!( @@ -196,10 +196,10 @@ pub fn do_set_weights( set_last_update_for_uid(deps.storage, netuid, neuron_uid, current_block); // --- 18. Emit the tracking event. - deps.api.debug(&format!( - "💡 WeightsSet ( netuid:{:?}, neuron_uid:{:?} )", - netuid, neuron_uid - )); + // deps.api.debug(&format!( + // "💡 WeightsSet ( netuid:{:?}, neuron_uid:{:?} )", + // netuid, neuron_uid + // )); // --- 19. Return ok. Ok(Response::default() @@ -216,16 +216,16 @@ pub fn do_set_weights( // pub fn check_version_key( store: &dyn Storage, - api: &dyn Api, + _api: &dyn Api, netuid: u16, version_key: u64, ) -> bool { let network_version_key: u64 = WEIGHTS_VERSION_KEY.load(store, netuid).unwrap(); - api.debug(&format!( - "💡 check_version_key ( network_version_key:{:?}, version_key:{:?} )", - network_version_key.clone(), - version_key - )); + // api.debug(&format!( + // "💡 check_version_key ( network_version_key:{:?}, version_key:{:?} )", + // network_version_key.clone(), + // version_key + // )); return network_version_key.clone() == 0 || version_key >= network_version_key; }