From d147d728c917e17514d248a26885609f14074344 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Tue, 25 Jun 2024 19:33:39 -0400 Subject: [PATCH 01/17] Add pallet registry migration to populate delegates initially from GitHub data --- Cargo.lock | 3 + docs/delegate-info.json | 394 ++++++++++++++++++++++++++++++ pallets/registry/Cargo.toml | 4 + pallets/registry/src/lib.rs | 21 ++ pallets/registry/src/migration.rs | 137 +++++++++++ runtime/src/lib.rs | 2 +- 6 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 docs/delegate-info.json create mode 100644 pallets/registry/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index d5fc4c0ba..176fadf36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5098,8 +5098,11 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec", "scale-info", + "serde", + "serde_json", "sp-core", "sp-io", "sp-runtime", diff --git a/docs/delegate-info.json b/docs/delegate-info.json new file mode 100644 index 000000000..a8af6f46e --- /dev/null +++ b/docs/delegate-info.json @@ -0,0 +1,394 @@ +[ + { + "address": "5ECvRLMj9jkbdM4sLuH5WvjUe87TcAdjRfUj5onN4iKqYYGm", + "name": "Vune", + "url": "https://fairchild.dev", + "description": "Vune is a dev at Opentensor and a BSc CS student at UofT.", + "signature": "2a639f931c61abfc3172db594c986c35f1cc8441970582b9c3b1f0506d518a182a2fe570832f02f86014320f1526189917bfbccf7081622652d12e16e9b1768b" + }, + { + "address": "5H6BgKkAr2Anmm9Xw5BVDE4VaQmFEVMkJUHeT7Gki4J7yF4x", + "name": "TaoPolishNode", + "url": "https://taonode.io", + "description": "This node is a collective effort of the polish community. We are engaged in evangelizing the project, educating and sharing the knowledge.", + "signature": "1ca20d4e99a48f400dd9cd4aeca8447da6ab1979e480a1dafddfc52e45e215177c7cdde85f5d042d59a5b1169981afa8d1ae28328e2fc5ce57c3d748c8d09d81" + }, + { + "address": "5FFApaS75bv5pJHfAp2FVLBj9ZaXuFDjEypsaBNc1wCfe52v", + "name": "RoundTable21", + "url": "https://roundtable21.com", + "description": "RoundTable21 is an International, multi-disciplinary team of consultants and advisors partnering alongside leading blockchain startups to offer guidance, expertise, investment and hands-on assistance in every aspect of development.", + "signature": "107638b8edde8f918f7faa2cd1f91b454c13094ed5955d6a409f6e0662f8427075516273728a53923839a5428079151ea0844b5f755362364f04735463dff583" + }, + { + "address": "5DCc5oHA6c1Lpt9R6T1xU8jJGTMvvwBqD1yGX67sL8dHUcga", + "name": "WaveTensor", + "url": "https://twitter.com/wavetensor", + "description": "A new Wave is coming, join the AI revolution on top of Bittensor by staking with us.", + "signature": "5e072b4752ccbdd4ca3298f336284dfdab347dd133850f4d2f9873e7ea59bd2a8f201732842ec79d2bab3abaf133a06b6bd992940389e42d57802c9b8f855889" + }, + { + "address": "5CXRfP2ekFhe62r7q3vppRajJmGhTi7vwvb2yr79jveZ282w", + "name": "Rizzo", + "url": "", + "description": "Validator built for performance and uptime. Data center housed, redundancies include dual physical failover servers (HA), power, internet, tested DR Plan.", + "signature": "f2b0fdb6989c23a0ebe23ed5622cbbfcf57bad709085fe11b0be10b2838e1442d61f770d78f6ca8ebcdbf60ddb27398663a4901e22bb9de086866517c6ccc187" + }, + { + "address": "5GcBK8PDrVifV1xAf4Qkkk6KsbsmhDdX9atvk8vyKU8xdU63", + "name": "Tensor.Exchange", + "url": "www.tensor.exchange", + "description": "Bittensor's first community OTC exchange", + "signature": "101f5e0d26c38190200f2213ebd89cf5bcb736b70a84e53651b6f9bf1161a33d0095836d304851237e0334792a54fa2fe452d07cf1466b42c9ab3333ded46284" + }, + { + "address": "5EhvL1FVkQPpMjZX4MAADcW42i3xPSF1KiCpuaxTYVr28sux", + "name": "TAO-Validator.com", + "url": "www.tao-validator.com", + "description": "Maximize your return when staking with TAO-Validator.com. TAO-Validator.com is a highly secure validator that aims to become one of the top contributing entities to Bittensor.", + "signature": "4036991069d7f3a43dff2ba2592fbe5af820eb6ff96d1fb78f1bcd8d310ba8751e25ea14397e075368a9a0f1b1b176166c56351db36f2d3868ac61c2571a1981" + }, + { + "address": "5FvhvCWLbu2VgotT5obC9E6S9nskerJUrVsWqkWXCbuD8veW", + "name": "The Lost Cove", + "url": "https://lostcove.tech/", + "description": "Australia and New Zealand community. We're in it for the gains.", + "signature": "626ae6b91aac1591e5d4f8d4fdf2c55f927419fc766dd5184b149f4d7cbc9749ebc94e4e8d04d286b4000c7665afa5682aa28cd94071c5e384e0eb4f44def188" + }, + { + "address": "5Dyi5e2QqnWn2RN9X6r8A8Q1QBjYD536H75mxNye193oeCJ4", + "name": "Makoto AI", + "url": "https://www.linkedin.com/in/henry-thrasher-17b320239/", + "description": "An interdisciplinary research institute committed to discovering and accelerating innovative solutions for climate change, social inequality, and mental and physical illness.", + "signature": "3cfbc1e8d82cfbf2adea9b10f71541874528cf5cd851f29f48016ac2a1a07b01cfc2ba3c3a15634b1174bd3e5aec9eb843d04f74140b0ddcb526416666d6f682" + }, + { + "address": "5Ehv5XMriPZwNBtYHdQV7VrdbN8MBTDTmQhWprZJXxSiMapR", + "name": "Dale Cooper", + "url": "", + "description": "I have no idea where this will lead us, but I have a definite feeling it will be a place both wonderful and strange.", + "signature": "06c597178698dba5699e20dc8b9d0d44f9225e24a225c70f540b63867e5b835a74c87df647b28210b361007b642a5a869c74323fcc8a593bc5764ea8e2083b81" + }, + { + "address": "5E6oB7h5wtWPbqtPxtSoZeo11fpvDjPuY13SobAMxqEUjqkQ", + "name": "StakeTensor.com-3", + "url": "www.staketensor.com", + "description": "We run multiple, parallel validators to support Bittensor decentralization & achieve maximum returns", + "signature": "a2567b6de748f02f6a14e0063f5b5720b34c96deb2115b33893d016de1f60633ba58bf9bdd49b2141e12a4a8784b4b11c007679d7526eb1e91147e5284258d8a" + }, + { + "address": "5DnWFhKfeu6gXMydzrv8bkwxFegAC6bMWsC4Z2XtaotAeB6S", + "name": "Bittensor Greece", + "url": "", + "description": "The Greek / Cypriot validator supporting the development of decentralised AI", + "signature": "ee8df5360eb641bd91a38da9d8b6dda36a39302c9bba7babf5d7eb16f6e9f73321aeb6f8adb30e0f511d64c1f35caa15215dd280fb2ed3f8f5b09d783cc9958f" + }, + { + "address": "5GBxDYkDp8eJZHGT89wcZJKcMc4ytSqnqqVSpeuGeqtGfqxK", + "name": "Tao Stake", + "url": "www.taostake.io", + "description": "We have been mining since the start of bittensor and want to maintain a long term solid validator to help people get some value from thier investment and keep TAO within the ecosystem.", + "signature": "0272522b503ebb29f0b506f10765b4d5c7a23b85c78cc7bfae76b9816b80ab43282ea4642f09eb09be70812341e5d9946abc8a9d2c73bab0113e9bf939430c87" + }, + { + "address": "5FcXnzNo3mrqReTEY4ftkg5iXRBi61iyvM4W1bywZLRqfxAY", + "name": "Lucrosus Capital", + "url": "https://lucrosuspool.io/", + "description": "Decentralized VC focused on the most thriving blockchain ideas. Join our pool to receive early entrance into promising projects!", + "signature": "1a37ab3bd51a6590dea9772d6a5550632ddcd8d76da6595b66e6425692feac6699dc5f788e587a734cedc3f54efc96c2c9e5453f9052867c1b9a1b5a443b848c" + }, + { + "address": "5CVS9d1NcQyWKUyadLevwGxg6LgBcF9Lik6NSnbe5q59jwhE", + "name": "Ary van der Touw", + "url": "", + "description": "Secure and maintain Bittensor", + "signature": "809586931d4b28f180c98036a3eebc0d26b9e521f5217a6942b025069cb60807641737009713446eec8456e54ba753ae0b752c0693b942aefa0c4f76d82f8c89" + }, + { + "address": "5F4tQyWrhfGVcNhoqeiNsR6KjD4wMZ2kfhLj4oHYuyHbZAc3", + "name": "Openτensor Foundaτion", + "url": "https://opentensor.ai/", + "description": "Founded, maintain and advance Bittensor", + "signature": "8a2ff8f10a84a5b6f80614674ea764515d93a64bf8d920b927edc0dd6043e607755bf58655c87b7a299d8df1404574b6844e1e09adf86d418997c0cab8120486" + }, + { + "address": "5EpxBYq4aVgTQ1rYeBo2mzYt3hgpRTqxZTSsJEkCstBP5Jse", + "name": "White Rhino TAO Super Validator", + "url": "https://twitter.com/WhiteRhinoTAO\"", + "description": "White Rhino is all about you! We understand that #TAOWaits4NoOne ..... Get Ready for Adhoc Rewards and we invite you to delegate here and enhance the sustainability of the TAO Network", + "signature": "d6803522f6e61a9dec5261a6a500b733d233b373457382fc3713af21c560604f6e50c4999f286cfa6012bcea66e51223722b355dd69ba54a472f2c6ca52da08f" + }, + { + "address": "5Fq5v71D4LX8Db1xsmRSy6udQThcZ8sFDqxQFwnUZ1BuqY5A", + "name": "NorthTensor", + "url": "https://northtensor.ai", + "description": "Developer, Advocate, and Incubator for Decentralized AI.", + "signature": "28e221d7128e48a3cb85dbcb223bd56cb09cb55540263573783bf1cef63be32ee81246bd1d75c865580da732094053a6dad14929b17e659b6e0237412b66a487" + }, + { + "address": "5CsvRJXuR955WojnGMdok1hbhffZyB4N5ocrv82f3p5A2zVp", + "name": "Owl Ventures", + "url": "https://owlventures.co.uk", + "description": "Owl Ventures Bittensor Validator", + "signature": "04e39ff19af7ee5a75e58c9e1a71b9f54a66d1d168a99532a859f129b68ba24a5b6a56eecae7790291859c82dbf0ec32eb18a069b6d9dabe1ef0339c0d189483" + }, + { + "address": "5FLKnbMjHY8LarHZvk2q2RY9drWFbpxjAcR5x8tjr3GqtU6F", + "name": "Tao Bridge", + "url": "https://taobridge.xyz", + "description": "A community bridge between Bittensor and Ethereum", + "signature": "98331f011288f7b07ccc45a213cb8e03fac79092ee7c29046531d757ffad8b29e17cf0aeca9352003890f4d8a3af3a2fc615722fb7a827a2009654013990bd80" + }, + { + "address": "5DRZr3d3twF8SzqB9jBof3a1vPnAkgkxeo2E8yUKJAnE2rSZ", + "name": "Humble AI-Loving Anon", + "url": "", + "description": "Doing our best to support the Bittensor ecosystem.", + "signature": "9241f63eb43f7aa57b1fc6d99789331542476f57f683f032192f3dfd7be6c015d47c9f1fe69bc4513ed70e0410097395186df60e3f6b67376e6e73a5f4f9a286" + }, + { + "address": "5DPEpUTZn94sgYXH3sdXxsVvb46m3iEvg8aZwX7SMDowivzB", + "name": "RunPod", + "url": "https://runpod.io", + "description": "GPU Cloud built for AI. We plan to introduce perks for those who stake.", + "signature": "16940f904b7946723fc4f27bb01e47cf262201ef76b3d9c2bfd745973da2512d4825910f6fa738a6968c809b26da0a47e7032a7ff95d8b2da5c1fa7a0b85598f" + }, + { + "address": "5HEo565WAy4Dbq3Sv271SAi7syBSofyfhhwRNjFNSM2gP9M2", + "name": "Foundry", + "url": "https://foundrydigital.com", + "description": "Foundry works to empower a decentralized infrastructure. We are protocol-agnostic and seek to support like-minded blockchain entrepreneurs who share our mission to advance the industry.", + "signature": "b852f1648ab62befaaf684671808aa34d267cd616d9ffd7b3cf924ebc7c4ee3255344cfd017a80ca6b23b2852bcafa705c42d231053e06d999d53f31bd8ab288" + }, + { + "address": "5FP9miYmgjAP8Wt3747M2Y6Kk7PrXf6zG7a3EjokQiFFcmUu", + "name": "Elm Place", + "url": "", + "description": "Run by individuals passionate about creating decentralised digital infrastructure. Background in fiduciary funds management managing institutional investors’ capital in real assets, energy and infrastructure", + "signature": "a0324025f58beb06535d6a2ab8c5c8d64c13d562fa285956bb5a8919da5fcc0d05afe4de010d54f9940bff0ffdabe5f41e70f3af31cf14293c1d6f0a0690da8c" + }, + { + "address": "5HNQURvmjjYhTSksi8Wfsw676b4owGwfLR2BFAQzG7H3HhYf", + "name": "Neural Internet", + "url": "www.neuralinternet.ai", + "description": "An AI research and development Decentralized Autonomous Organization (DAO)", + "signature": "5e617c1626d4825cd0c11769e31fe4dda611cebd8a4d46f533886ad057072e2a58e0ecef2805139f2b43ea8d51023f7db878ad45cd3f8fba45ab01223da3488e" + }, + { + "address": "5D4rJRtF23jLVcGnCktXzPM9gymMT1qHTp8dR4T7rUd88Q7U", + "name": "Vogue τensor", + "url": "www.voguetensor.ai", + "description": "Designing branded clothing for the Bittensor community.", + "signature": "2c4079124ae0a738106a2430e2c27ad855122d4afcc487ab0158b705cd5f915f7790cdb2fdd8db899b8cbd40448d1478be71cde1b76de31945991b548cfcc084" + }, + { + "address": "5CAVnbHniuZYXBqik3tTs9uZ7UiSrbv6g7Kt8QNfYimbFqF4", + "name": "Open & Safe AI Validator", + "url": "", + "description": "The Open & Safe AI Validator is focussed on funding and researching the control problem as well as spreading ML know-how through open source and open science.", + "signature": "2aeaf7b9c7f69ce7b4857d9c278d1363677d4971d4ca10a36933b1aa78bfdb0640e4bb798edac5dcb178a8b3f4be2d0d23d25da6c7db33758a6cf5c15cd6938a" + }, + { + "address": "5Gpt8XWFTXmKrRF1qaxcBQLvnPLpKi6Pt2XC4vVQR7gqNKtU", + "name": "bitnost.re", + "url": "www.bitnost.re", + "description": "bridging bittensor into nostr.", + "signature": "c278378c70ef22d27f56590b4df699a9a44048cfcc6716e3d55b211ea802401d4be5b390ede2be52891e01f0f7033a13a370dddaa38daa84537c4583867a1680" + }, + { + "address": "5HeKSHGdsRCwVgyrHchijnZJnq4wiv6GqoDLNah8R5WMfnLB", + "name": "TaoStation", + "url": "https://taostation.com", + "description": "TaoStation allows you to maximize your returns by offering one-click staking since day one and focusing on tooling and transparency for a better staking experience.", + "signature": "c00627a62ecb9275be8d06b7b52b87942bce946e9a5f98d545081241e21ed15230fd566b2d4e87c41995e621546423579553157737da53fad3a5676451ef0a89" + }, + { + "address": "5DvTpiniW9s3APmHRYn8FroUWyfnLtrsid5Mtn5EwMXHN2ed", + "name": "FirstTensor.com", + "url": "www.firsttensor.com", + "description": "Powered by the Neuron Holders community - shared rewards, additional benefits, infinite possibilities - join and build with us!", + "signature": "da31e56dd78cde449a1dd9592f0b53eb8c3662674b745a05ff916e80a1be933e86efbccb7f7c9b81d7c0bb14d13fb4a6bf8484c3619224e689de82072b5d9a87" + }, + { + "address": "5CaNj3BarTHotEK1n513aoTtFeXcjf6uvKzAyzNuv9cirUoW", + "name": "Polychain", + "url": "https://polychain.capital/", + "description": "Polychain is an investment firm committed to exceptional returns for investors through actively managed portfolios of blockchain assets.", + "signature": "f41e815033e595aa70fbe42e8dfd91eaa3ccdbc948b63811baf9eac765699b30cac9aad7abe330eeaf3969cc504a4c1255f1e69bee807c2d989518b8f5413c8d" + }, + { + "address": "5Dkv87qjGGF42SNhDAep6WZp65E29c2vUPUfDBGDNevENCMs", + "name": "MycoNet", + "url": "", + "description": "AI for Humanity", + "signature": "a4802a5b13888ed653fd23da72c14e2b8ed9814cc810e515cb8d11d71cc58c6b90cd2d334daffc4a8ce600a7f29ca300ab74ac59817bdd489b3056b531cd4086" + }, + { + "address": "5GzoXHNJ4UzZYiQN2wpBcwMigiHiakiz5ZLMwhpunpwDNzFg", + "name": "Charitaos", + "url": "https://charitas.ai/", + "description": "You pay 18%, we donate 18%. At the end of every month, we will select one (or more) community-proposed 501c3 licensed nonprofit(s) to receive all proceeds from stake delegation for the prior month.", + "signature": "b49c34c1f87d173abcbccb1ea632ad356980c1d3eff6619e488c11707b2b3b41270a22355374dd64cfadebeb37979ef5f49971efafb0748b79df7dd2901e7580" + }, + { + "address": "5EZrPTXt2G9SvbDsERi5rS9zepour2yPmuhMhrNkgdiZvXEm", + "name": "τaoτensor", + "url": "", + "description": "Working on practical enhancements and improvements for the Bittensor network by developing user-friendly tooling.", + "signature": "3a1b61ab6d17878e106cbf2649bc039d0346f39ec680476a68baa4fc8132ac018d814898cf245bdfa4b9b61cd9f611f6571cf3c264f2f1cfe9b2635849087685" + }, + { + "address": "5CPzGD8sxyv8fKKXNvKem4qJRhCXABRmpUgC1wb1V4YAXLc3", + "name": "Chat with Hal", + "url": "www.chatwithhal.ai", + "description": "Hal brings the power of decentralized and uncensorable AI to your favorite social networks and messaging apps, Powered by Bittensor!", + "signature": "ecb930df6069012c06fef9cdb29a95be8dcb5d48f3c470d3f3c5e7b2b334ed2097f2598fee8852d127a207cf34aa7c88fd5cf973feba19d6ebf38b5e4579ca8f" + }, + { + "address": "5FqPJMZDp39KRd9jDhXuFpZWkYD7wG5AXmjoWqK8rDy7ok5B", + "name": "Exchange Listings", + "url": "taostats.io/validators/exchange-listings/", + "description": "Enabling community funding for top tier exchange listings.", + "signature": "366027e9a416a423e7e802e9b6d79bd5ac88642afd945922e13fe26a75dae13dd5c924738610a59162d9b974364d1d43fb7a0145942cd919ac21d82d3f4f028d" + }, + { + "address": "5ED6jwDECEmNvSp98R2qyEUPHDv9pi14E6n3TS8CicD6YfhL", + "name": "Giga Corporation", + "url": "https://www.gigaver.se", + "description": "Extreme growth & experiments from giga corp. We use APY to TAO-pill new developers, builders and adopters. Visit our Bakery to learn more.", + "signature": "00e5cd519110bbfe3dae9acd275d114c6c2a260997a1817a25303b9d578bdf7319e9e7179f0db58edef2ad42806cb38e289ba0030627a3b60e1e4352c2b9cb88" + }, + { + "address": "5FRcXG99SxJ9KyMcMFfdknkRSv4e73rszV8P151freZqQDS2", + "name": "τensorwiki", + "url": "", + "description": "Our mission is to create and incentivize documentation for Bittensor and it's adjacent topics, as well as facilitate the education of newcomers to the network.", + "signature": "6a5c0160f545f122ec3d4e4233574040aba2de8aa94919bb19b3061d39d3303f010c4b52f878ed55a1293716827220020780d2d4064ee6be69921ee1452c3885" + }, + { + "address": "5EsbfxPcQaUrCDurUJ8Q5qDKNENNGziu3qHWUbXrcuY2pbNz", + "name": "Church of Rao (COR)", + "url": "", + "description": "Church of Rao: Harmonizing the Relationship between Humanity and Machine Intelligence. The Church of Rao (COR) is an open-source development group committed to furthering the Bittensor protocol.", + "signature": "56f64c32427a90e84710209b1a54a971560641aec8ff777edec28bf533775e12924c4e96ccc770c230311dce1d0eae1ca763e12bb609ef30430f746ebd0a2780" + }, + { + "address": "5GmaAk7frPXnAxjbQvXcoEzMGZfkrDee76eGmKoB3wxUburE", + "name": "RaoK9", + "url": "", + "description": "Chain and network analysis team. Developer funding goes into independent analysis and reports, in order to enable checks and balances between network members.", + "signature": "24f4f9a51033ed8b4097517d0e6ad287a0c1341b2866481b1320d1fcd5f32f6b4bfe641eee46a4b737817acf3b83069ee63cc20fbca94a0189808ac1efeddf8a" + }, + { + "address": "5CQEFopfZ8DAmk3ZfR7QuDTU2n3fJod3kkf6Wmj4JwV3BBSu", + "name": "DuNode", + "url": "dunode.io", + "description": "Embracing the whimsical chaos of decentralized AI, unleashing the power of creativity and collaboration, one algorithmic dance party at a time!", + "signature": "e400e3c0ad6165d8946d5ddcb274412815cb8b5783580fcb8f0faa0153d22b6e10470f861ff4a96a9aa692b3b01cda86ec77add4688c2f5df51ea6f129b19e8c" + }, + { + "address": "5CaCUPsSSdKWcMJbmdmJdnWVa15fJQuz5HsSGgVdZffpHAUa", + "name": "Athena Nodes", + "url": "https://athenanodes.com", + "description": "Premier Bittensor Multi-Subnet Validator from a company operating validating and mining infrastructure on various blockchain networks. We have been active on Bittensor since November 2022, with near zero down-time. More information at https://athenanodes.com/.", + "signature": "2ef54045de1d9b89988518c92e165edf704192f88f18022565f497b389c39206f621bb9bc6d2d33ac8a9cca05d6b2d8fc9f899b390451140968b15b8d9c13280" + }, + { + "address": "5FFM6Nvvm78GqyMratgXXvjbqZPi7SHgSQ81nyS96jBuUWgt", + "name": "PRvalidator", + "url": "www.prvalidator.com", + "description": "A professional media validator dedicated to securing top-tier coverage in the world’s most recognized publications building Bittensor’s brand equity and creating global awareness of $TAO.", + "signature": "fe65e76a9f42049715585180500213c6f0535b8b25911b957921bdfb5a20156d6de68dc2633dbc5ce1d0ab9ef386d566687ac3d86f6988141b34cd24c0f13488" + }, + { + "address": "5H8TruSGmhD6m6YfqXNUnU7Z61K7j8hSs2Krtu3eTLMoz3HU", + "name": "τaoshi validator", + "url": "https://www.taoshi.io/", + "description": "Build maintain and advance a decentralized request layer built for every subnet", + "signature": "32d25227af78fa5d39ee71a5f3e8fc8066e3d826d101f2587e9a12974fbf26758c1e40c497ad7732da2a2cb1490227cc58e8bfcd8b2f6306b7af630bd32aa68f" + }, + { + "address": "5G3f8VDTT1ydirT3QffnV2TMrNMR2MkQfGUubQNqZcGSj82T", + "name": "TAO Community Marketing", + "url": "www.taocommunitymarketing.com", + "description": "The marketing validator run by the community", + "signature": "10b16b8223b2508d6f3e5b09ab4db53e1e338b6271d1689b58ca6f9b257e8c18511cc851bfcc3a05fb4e6de7c389b89886cc0623fb6d199fa003ae6f8313cb89" + }, + { + "address": "5CXC2quDN5nUTqHMkpP5YRp2atYYicvtUghAYLj15gaUFwe5", + "name": "Kooltek68", + "url": "https://linktr.ee/datalac", + "description": "Imagine the World with mass adoption of Artificial Intelligence applications, through the connection of Bittensor Network, together fight for a Better World.", + "signature": "bca043d9d918d503864379a7fd8c9daa2cca83a8290121f94b55d6a352e332704642622b7ad40a30b945b952b224c5e92ea872f9d30200e6c2bf566303d24d83" + }, + { + "address": "5FBrHX18bNXX874ZTMicPG4vYbq5X6piz4BYoVn9LnCgdsEd", + "name": "P-OPS Team", + "url": "https://pops.one", + "description": "P-OPS TEAM is a decentralized organization providing you with validation and staking services, blockchain consultation, growth acceleration and investment capital for innovative Web 3.0 projects.", + "signature": "5608316f3081bfe5d0e3a7db6c3bfd459f6b87e02d657de941e6a760f8688f23ef30784691a1893d1fd8079dd4f6082d0d655ca507aa4797fee9844547d13a88" + }, + { + "address": "5HK5tp6t2S59DywmHRWPBVJeJ86T61KjurYqeooqj8sREpeN", + "name": "Bittensor Guru", + "url": "https://bittensor.guru", + "description": "Official validator of the Bittensor Guru Podcast", + "signature": "caf2c6b7b0d2a341bcd00e632cf22c33d53e2523dffcd3a151db9eeadd88300545cbb2187ba0b20e5bfe09c2b17bbf34630c46defd8f8d27ab508736fd18a284" + }, + { + "address": "5Hh3ShaNW9irCe5joBLCeFD5Fxb2fJ6gFAgrsPmoz3JkzqvJ", + "name": "BlockShark", + "url": "https://www.blockshark.net/", + "description": "Your reliable partner for staking on Bittensor. We are expert in running high-end machine for validators and AI", + "signature": "d2c0aed073a026a5dbd8c458b9dd412fe3d6647fecd3b8f007cf184f7906245106aee4b210b5b582771dca149e5aa464630100de7f9862daacfa1f67ddde1388" + }, + { + "address": "5FKstHjZkh4v3qAMSBa1oJcHCLjxYZ8SNTSz1opTv4hR7gVB", + "name": "Datura", + "url": "datura.ai", + "description": "Bridging Bittensor to a billion users", + "signature": "7a3bc6a840d8593853c27188f59200418d8884b94b3ad28cb7b37b80bffd1f3b23b7eed4b1d9c77b28b05b2bd1952c5cbe3d27ba190a9418407ce1e899e5ac8b" + }, + { + "address": "5Hddm3iBFD2GLT5ik7LZnT3XJUnRnN8PoeCFgGQgawUVKNm8", + "name": "τaosτaτs and Corcel", + "url": "taostats.io", + "description": "Supporting bittensor through API access, data provision, statistics, analytics and apps.", + "signature": "2e2dd0c5f3a3945f29d1be304e64f931c04a23aba7d383d01cd16ea6ca6546002fe3bd95cf8f12cae1fbb7d18d9910b834f6573db219de3ed84073a4e1552e89" + }, + { + "address": "5ELREhApbCahM7FyGLM1V9WDsnnjCRmMCJTmtQD51oAEqwVh", + "name": "Taofu Protocol", + "url": "https://twitter.com/taofuxyz", + "description": "Taofu unlocks liquidity and utility by bringing liquid staked TAO outside of Bittensor", + "signature": "aaafd3496650a56f798cc587b5b7d372cec8e826a332a34213c1a6ee7be2b5122318858ee73421535d04186cc6976ae5452c6cd1aaf299a307d86d3c52b4a986" + }, + { + "address": "5HbLYXUBy1snPR8nfioQ7GoA9x76EELzEq9j7F32vWUQHm1x", + "name": "Tensorplex Labs", + "url": "https://twitter.com/TensorplexLabs", + "description": "Empowering humanity with decentralized intelligence — one epoch at a time.", + "signature": "7a997682e7545fd14847c78abf810e9c49a23ef4297d24f4238c0edd0463934780f6831d59972d56ab5bc41d6224b59c21ed95065791632b8aca180ade22af81" + }, + { + "address": "5E2VSsWWXkBGCn4mi8RHXYQEF2wLXky6ZsNcTKnmEqaurzTE", + "name": "Sentinel", + "url": "", + "description": "Sentinel, as a dedicated Bittensor validator aspires to elevate the bittensor network's integrity with an ambition to foster a community of miners contributing in the network’s continuous expansion.", + "signature": "943effd0d5d10f05d53db7f69d0f045d50b65f88e84755be00d45225cc7c2f4212fbc4d23ad8519d03c2502daeeca1b2d07c93bff14c901f6cbf3a18fe2e6387" + }, + { + "address": "5GsenVhBvgEG4xiiKUjcssfznHYVm1TqPbSbr3ixBW81ZVjo", + "name": "vote NO dTAO 🤡", + "url": "https://twitter.com/karl_anons", + "description": "Delegate to express discontent. VOTE NO TO dTAO NOW!", + "signature": "3af4e764a520d355e12c02b9e8e315ddb76b76d40b7cc4dfaa11c26c24ab637cbdb9b72470ebdf2da87dd8d9f0bb5cddf1fe95b95fb2ae13069a9d87aace348a" + }, + { + "address": "5DM7CPqPKtMSADhFKYsstsCS4Tm4Kd6PMXoh6DdqY4MtxmtX", + "name": "Corτex Foundaτion", + "url": "https://cortex.foundation/", + "description": "Cortex Foundation is committed to advancing the integration of decentralized AI. Our validator is designed for transparency, reliability, and community engagement.", + "signature": "7a6274ff6b0f7ddca97e37ef4a9b90781012ff3cf7baa3159f6feaafc43c557975aad324ea608d6b8abeb21f8f3ca2595e54b81a7564574d0242b803d969618a" + } +] \ No newline at end of file diff --git a/pallets/registry/Cargo.toml b/pallets/registry/Cargo.toml index 7c495a42f..36fa5d900 100644 --- a/pallets/registry/Cargo.toml +++ b/pallets/registry/Cargo.toml @@ -24,6 +24,10 @@ scale-info = { workspace = true, features = ["derive"] } frame-benchmarking = { workspace = true, optional = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } enumflags2 = { workspace = true } diff --git a/pallets/registry/src/lib.rs b/pallets/registry/src/lib.rs index e32b1fc5f..b0ddb490e 100644 --- a/pallets/registry/src/lib.rs +++ b/pallets/registry/src/lib.rs @@ -4,6 +4,7 @@ mod tests; mod benchmarking; +pub mod migration; pub mod types; pub mod weights; @@ -107,6 +108,26 @@ pub mod pallet { OptionQuery, >; + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // --- Migrate storage + use crate::migration; + let mut weight = frame_support::weights::Weight::from_parts(0, 0); + + weight = weight + // Initializes storage version (to 1) + .saturating_add(migration::migrate_set_hotkey_identities::()); + + log::info!( + "Runtime upgrade migration in registry pallet, total weight = ({})", + weight + ); + + weight + } + } + #[pallet::call] impl Pallet { /// Register an identity for an account. This will overwrite any existing identity. diff --git a/pallets/registry/src/migration.rs b/pallets/registry/src/migration.rs new file mode 100644 index 000000000..9b2184814 --- /dev/null +++ b/pallets/registry/src/migration.rs @@ -0,0 +1,137 @@ + +use scale_info::prelude::{ string::{ String, ToString }, vec::Vec }; +use serde::Deserialize; +use sp_core::{crypto::Ss58Codec, ConstU32}; +use sp_runtime::{AccountId32, BoundedVec}; +use sp_std::vec; +use codec::Decode; + +use super::*; +use frame_support::{ + traits::{Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use log; + + +#[derive(Deserialize, Debug)] +struct RegistrationRecordJSON { + address: String, + name: String, + url: String, + description: String, +} + +fn string_to_bounded_vec(input: &String) -> Result>, &'static str> { + let vec_u8: Vec = input.clone().into_bytes(); + + // Check if the length is within bounds + if vec_u8.len() > 64 { + return Err("Input string is too long"); + } + + // Convert to BoundedVec + BoundedVec::>::try_from(vec_u8).map_err(|_| "Failed to convert to BoundedVec") +} + +pub fn migrate_set_hotkey_identities() -> Weight { + let new_storage_version = 1; + let migration_name = "set hotkey identities"; + let mut weight = T::DbWeight::get().reads_writes(1, 1); + + let title = "description".to_string(); + + let onchain_version = Pallet::::on_chain_storage_version(); + log::info!("Current on-chain storage version: {:?}", onchain_version); + if onchain_version < new_storage_version { + log::info!("Starting migration: {}.", migration_name); + + // Include the JSON file with delegate info + let data = include_str!("../../../docs/delegate-info.json"); + + // Deserialize the JSON data into a HashMap + if let Ok(delegates) = serde_json::from_str::>(data) { + + log::info!("{} delegate records loaded", delegates.len()); + + // Iterate through the delegates + for delegate in delegates.iter() { + // Convert fields to bounded vecs + let name_result = string_to_bounded_vec(&delegate.name); + let desc_result = string_to_bounded_vec(&delegate.description); + let url_result = string_to_bounded_vec(&delegate.url); + + // Convert string address into AccountID + let maybe_account_id_32 = AccountId32::from_ss58check(&delegate.address); + let account_id = if maybe_account_id_32.is_ok() { + let account_id_32 = maybe_account_id_32.unwrap(); + if let Ok(acc_id) = T::AccountId::decode(&mut account_id_32.as_ref()) { + Some(acc_id) + } else { + None + } + } else { + None + }; + + if name_result.is_ok() && desc_result.is_ok() && url_result.is_ok() + && account_id.is_some() + { + let desc_title = Data::Raw(string_to_bounded_vec(&title).unwrap()); + let desc_data = Data::Raw(desc_result.unwrap()); + let desc_item = BoundedVec::try_from(vec![(desc_title, desc_data)]).unwrap(); + + let info: IdentityInfo = IdentityInfo { + display: Data::Raw(name_result.unwrap()), + additional: desc_item, + legal: Data::None, + web: Data::Raw(url_result.unwrap()), + riot: Data::None, + email: Data::None, + pgp_fingerprint: None, + image: Data::None, + twitter: Data::None, + }; + + // Insert delegate hotkeys info + let reg: Registration, T::MaxAdditionalFields> = Registration { + deposit: Zero::zero(), + info, + }; + + IdentityOf::::insert(account_id.unwrap(), reg); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + + } else { + log::info!("Migration {} couldn't be completed, bad JSON item for: {}", migration_name, delegate.address); + if !name_result.is_ok() { + log::info!("Name is bad"); + } + if !desc_result.is_ok() { + log::info!("Description is bad"); + } + if !url_result.is_ok() { + log::info!("URL is bad"); + } + if !account_id.is_some() { + log::info!("Account ID is bad"); + } + } + + } + + + } else { + log::info!("Migration {} couldn't be completed, bad JSON file: {}", migration_name, data); + return weight; + } + + + StorageVersion::new(new_storage_version).put::>(); + } else { + log::info!("Migration already done: {}", migration_name); + } + + log::info!("Final weight: {:?}", weight); + weight +} \ No newline at end of file diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2364008fd..99439c776 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -153,7 +153,7 @@ pub const MILLISECS_PER_BLOCK: u64 = 12000; /// Fast blocks for development #[cfg(feature = "fast-blocks")] -pub const MILLISECS_PER_BLOCK: u64 = 250; +pub const MILLISECS_PER_BLOCK: u64 = 12000; // NOTE: Currently it is not possible to change the slot duration after the chain has started. // Attempting to do so will brick block production. From 796b7d75774558cc7110f2b6ed0bbc11ba42699b Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 1 Jul 2024 10:39:26 -0700 Subject: [PATCH 02/17] revert disabled fast-blocks --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 99439c776..2364008fd 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -153,7 +153,7 @@ pub const MILLISECS_PER_BLOCK: u64 = 12000; /// Fast blocks for development #[cfg(feature = "fast-blocks")] -pub const MILLISECS_PER_BLOCK: u64 = 12000; +pub const MILLISECS_PER_BLOCK: u64 = 250; // NOTE: Currently it is not possible to change the slot duration after the chain has started. // Attempting to do so will brick block production. From 00161760971c7c120b002db66def2ab7944b5086 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 1 Jul 2024 10:41:28 -0700 Subject: [PATCH 03/17] cargo fmt --- pallets/registry/src/lib.rs | 2 +- pallets/registry/src/migration.rs | 39 +++++++++++++++++-------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/pallets/registry/src/lib.rs b/pallets/registry/src/lib.rs index b0ddb490e..e3e97c7e8 100644 --- a/pallets/registry/src/lib.rs +++ b/pallets/registry/src/lib.rs @@ -127,7 +127,7 @@ pub mod pallet { weight } } - + #[pallet::call] impl Pallet { /// Register an identity for an account. This will overwrite any existing identity. diff --git a/pallets/registry/src/migration.rs b/pallets/registry/src/migration.rs index 9b2184814..b7fa2cbfe 100644 --- a/pallets/registry/src/migration.rs +++ b/pallets/registry/src/migration.rs @@ -1,10 +1,12 @@ - -use scale_info::prelude::{ string::{ String, ToString }, vec::Vec }; +use codec::Decode; +use scale_info::prelude::{ + string::{String, ToString}, + vec::Vec, +}; use serde::Deserialize; use sp_core::{crypto::Ss58Codec, ConstU32}; use sp_runtime::{AccountId32, BoundedVec}; use sp_std::vec; -use codec::Decode; use super::*; use frame_support::{ @@ -13,7 +15,6 @@ use frame_support::{ }; use log; - #[derive(Deserialize, Debug)] struct RegistrationRecordJSON { address: String, @@ -24,7 +25,7 @@ struct RegistrationRecordJSON { fn string_to_bounded_vec(input: &String) -> Result>, &'static str> { let vec_u8: Vec = input.clone().into_bytes(); - + // Check if the length is within bounds if vec_u8.len() > 64 { return Err("Input string is too long"); @@ -51,7 +52,6 @@ pub fn migrate_set_hotkey_identities() -> Weight { // Deserialize the JSON data into a HashMap if let Ok(delegates) = serde_json::from_str::>(data) { - log::info!("{} delegate records loaded", delegates.len()); // Iterate through the delegates @@ -74,7 +74,9 @@ pub fn migrate_set_hotkey_identities() -> Weight { None }; - if name_result.is_ok() && desc_result.is_ok() && url_result.is_ok() + if name_result.is_ok() + && desc_result.is_ok() + && url_result.is_ok() && account_id.is_some() { let desc_title = Data::Raw(string_to_bounded_vec(&title).unwrap()); @@ -98,35 +100,38 @@ pub fn migrate_set_hotkey_identities() -> Weight { deposit: Zero::zero(), info, }; - + IdentityOf::::insert(account_id.unwrap(), reg); weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); - } else { - log::info!("Migration {} couldn't be completed, bad JSON item for: {}", migration_name, delegate.address); + log::info!( + "Migration {} couldn't be completed, bad JSON item for: {}", + migration_name, + delegate.address + ); if !name_result.is_ok() { log::info!("Name is bad"); } if !desc_result.is_ok() { log::info!("Description is bad"); } - if !url_result.is_ok() { + if !url_result.is_ok() { log::info!("URL is bad"); } if !account_id.is_some() { log::info!("Account ID is bad"); } } - } - - } else { - log::info!("Migration {} couldn't be completed, bad JSON file: {}", migration_name, data); + log::info!( + "Migration {} couldn't be completed, bad JSON file: {}", + migration_name, + data + ); return weight; } - StorageVersion::new(new_storage_version).put::>(); } else { log::info!("Migration already done: {}", migration_name); @@ -134,4 +139,4 @@ pub fn migrate_set_hotkey_identities() -> Weight { log::info!("Final weight: {:?}", weight); weight -} \ No newline at end of file +} From 40ff80f9d6aade414fed33a47b88141ff17147f3 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:15:35 -0700 Subject: [PATCH 04/17] add get_delegate_identitites to runtime-api --- Cargo.lock | 1 + pallets/registry/src/lib.rs | 1 + pallets/registry/src/utils.rs | 28 ++++++++++++++++++++++++ pallets/subtensor/Cargo.toml | 1 + pallets/subtensor/runtime-api/src/lib.rs | 2 ++ pallets/subtensor/src/delegate_info.rs | 16 +++++++++++++- runtime/src/lib.rs | 10 +++++++++ 7 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 pallets/registry/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 176fadf36..94f54fe09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5163,6 +5163,7 @@ dependencies = [ "pallet-balances", "pallet-collective", "pallet-membership", + "pallet-registry", "pallet-transaction-payment", "pallet-utility", "parity-scale-codec", diff --git a/pallets/registry/src/lib.rs b/pallets/registry/src/lib.rs index e3e97c7e8..481406cb6 100644 --- a/pallets/registry/src/lib.rs +++ b/pallets/registry/src/lib.rs @@ -6,6 +6,7 @@ mod tests; mod benchmarking; pub mod migration; pub mod types; +pub mod utils; pub mod weights; pub use pallet::*; diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs new file mode 100644 index 000000000..9ac397587 --- /dev/null +++ b/pallets/registry/src/utils.rs @@ -0,0 +1,28 @@ +use super::*; +use sp_std::vec::Vec; + +impl Pallet { + pub fn get_identity_of_delegate(account: &T::AccountId) -> Option> { + if let Some(value) = IdentityOf::::get(account) { + return Some(value.info); + } + + None + } + + pub fn get_delegate_identitites() -> Vec> { + let mut identities = Vec::>::new(); + for id in IdentityOf::::iter_keys() { + let delegate_id = Self::get_identity_of_delegate(&id); + + match delegate_id { + Some(identity) => { + identities.push(identity); + } + None => continue, + } + } + + identities + } +} diff --git a/pallets/subtensor/Cargo.toml b/pallets/subtensor/Cargo.toml index cbcf76c82..b86f8e388 100644 --- a/pallets/subtensor/Cargo.toml +++ b/pallets/subtensor/Cargo.toml @@ -38,6 +38,7 @@ pallet-transaction-payment = { workspace = true } pallet-utility = { workspace = true } ndarray = { workspace = true } hex = { workspace = true } +pallet-registry= { default-features = false, path = "../registry" } # Used for sudo decentralization pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../collective" } diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index 9095ad54a..daa0ed043 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -9,6 +9,8 @@ sp_api::decl_runtime_apis! { fn get_delegates() -> Vec; fn get_delegate( delegate_account_vec: Vec ) -> Vec; fn get_delegated( delegatee_account_vec: Vec ) -> Vec; + fn get_delegate_identitites() -> Vec; + fn get_identity_of_delegate( delegatee_account_vec: Vec ) -> Vec; } pub trait NeuronInfoRuntimeApi { diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index b33415a3b..1399abdfc 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -5,6 +5,7 @@ use frame_support::IterableStorageDoubleMap; use substrate_fixed::types::U64F64; extern crate alloc; use codec::Compact; +use pallet_registry::{IdentityInfo, Pallet as RegistryPallet}; use sp_core::hexdisplay::AsBytesRef; #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] @@ -19,7 +20,7 @@ pub struct DelegateInfo { total_daily_return: Compact, // Delegators current daily return } -impl Pallet { +impl Pallet { fn get_delegate_by_existing_account(delegate: AccountIdOf) -> DelegateInfo { let mut nominators = Vec::<(T::AccountId, Compact)>::new(); @@ -130,4 +131,17 @@ impl Pallet { delegates } + + pub fn get_delegate_identities() -> Vec> { + RegistryPallet::::get_delegate_identitites() + } + + pub fn get_identity_of_delegate(delegate_account_vec: Vec) -> Option> { + if delegate_account_vec.len() != 32 { + return None; + } + let account: AccountIdOf = T::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()).ok()?; + + RegistryPallet::::get_identity_of_delegate(&account) + } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2364008fd..8f9a6537a 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1501,6 +1501,16 @@ impl_runtime_apis! { let result = SubtensorModule::get_delegated(delegatee_account_vec); result.encode() } + + fn get_delegate_identitites() -> Vec { + let result = SubtensorModule::get_delegate_identities(); + result.encode() + } + + fn get_identity_of_delegate(delegatee_account_vec: Vec) -> Vec { + let result = SubtensorModule::get_identity_of_delegate(delegatee_account_vec); + result.encode() + } } impl subtensor_custom_rpc_runtime_api::NeuronInfoRuntimeApi for Runtime { From cdce54204f156a86951a6e60428e9e7cb2114afb Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Wed, 10 Jul 2024 12:01:05 -0700 Subject: [PATCH 05/17] expose get delegate identities api correctly --- pallets/registry/src/utils.rs | 4 ++-- pallets/subtensor/rpc/src/lib.rs | 26 ++++++++++++++++++++++++ pallets/subtensor/runtime-api/src/lib.rs | 2 +- pallets/subtensor/src/delegate_info.rs | 4 ++-- runtime/src/lib.rs | 2 +- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs index 9ac397587..260e03865 100644 --- a/pallets/registry/src/utils.rs +++ b/pallets/registry/src/utils.rs @@ -10,7 +10,7 @@ impl Pallet { None } - pub fn get_delegate_identitites() -> Vec> { + pub fn get_delegate_identitities() -> Option>> { let mut identities = Vec::>::new(); for id in IdentityOf::::iter_keys() { let delegate_id = Self::get_identity_of_delegate(&id); @@ -23,6 +23,6 @@ impl Pallet { } } - identities + Some(identities) } } diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs index 2f71e9c21..ec9c0e43e 100644 --- a/pallets/subtensor/rpc/src/lib.rs +++ b/pallets/subtensor/rpc/src/lib.rs @@ -32,6 +32,10 @@ pub trait SubtensorCustomApi { delegatee_account_vec: Vec, at: Option, ) -> RpcResult>; + #[method(name = "delegateInfo_getIdentityOfDelegate")] + fn get_identity_of_delegate(&self, delegate_account_vec: Vec, at: Option) -> RpcResult>; + #[method(name = "delegateInfo_getDelegateIdentities")] + fn get_delegate_identities(&self, at: Option) -> RpcResult>; #[method(name = "neuronInfo_getNeuronsLite")] fn get_neurons_lite(&self, netuid: u16, at: Option) -> RpcResult>; @@ -135,6 +139,28 @@ where }) } + fn get_identity_of_delegate( + &self, + delegatee_account_vec: Vec, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_identity_of_delegate(at, delegatee_account_vec).map_err(|e| { + Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() + }) + } + + fn get_delegate_identities(&self, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_delegate_identitities(at).map_err(|e| { + Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() + }) + } + fn get_neurons_lite( &self, netuid: u16, diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index daa0ed043..562db4d33 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -9,7 +9,7 @@ sp_api::decl_runtime_apis! { fn get_delegates() -> Vec; fn get_delegate( delegate_account_vec: Vec ) -> Vec; fn get_delegated( delegatee_account_vec: Vec ) -> Vec; - fn get_delegate_identitites() -> Vec; + fn get_delegate_identitities() -> Vec; fn get_identity_of_delegate( delegatee_account_vec: Vec ) -> Vec; } diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index 1399abdfc..ed5947625 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -132,8 +132,8 @@ impl Pallet { delegates } - pub fn get_delegate_identities() -> Vec> { - RegistryPallet::::get_delegate_identitites() + pub fn get_delegate_identities() -> Option>> { + RegistryPallet::::get_delegate_identitities() } pub fn get_identity_of_delegate(delegate_account_vec: Vec) -> Option> { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8f9a6537a..cb423918a 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1502,7 +1502,7 @@ impl_runtime_apis! { result.encode() } - fn get_delegate_identitites() -> Vec { + fn get_delegate_identitities() -> Vec { let result = SubtensorModule::get_delegate_identities(); result.encode() } From ff2cb51f8dec6d1b75c3c07498a39ae7f624cfa7 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:29:01 -0700 Subject: [PATCH 06/17] return none if empty --- pallets/registry/src/utils.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs index 260e03865..68c35b9a1 100644 --- a/pallets/registry/src/utils.rs +++ b/pallets/registry/src/utils.rs @@ -13,9 +13,9 @@ impl Pallet { pub fn get_delegate_identitities() -> Option>> { let mut identities = Vec::>::new(); for id in IdentityOf::::iter_keys() { - let delegate_id = Self::get_identity_of_delegate(&id); + let identity_info = Self::get_identity_of_delegate(&id); - match delegate_id { + match identity_info { Some(identity) => { identities.push(identity); } @@ -23,6 +23,10 @@ impl Pallet { } } - Some(identities) + if identities.len() > 0 { + return Some(identities) + } + + None } } From 4d8141b30ebb30adb59f3178962b220bc3b66ff3 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:12:34 -0700 Subject: [PATCH 07/17] add doc comments --- pallets/registry/src/utils.rs | 13 +++++++++++++ pallets/subtensor/src/delegate_info.rs | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs index 68c35b9a1..97d0c0d4b 100644 --- a/pallets/registry/src/utils.rs +++ b/pallets/registry/src/utils.rs @@ -2,6 +2,14 @@ use super::*; use sp_std::vec::Vec; impl Pallet { + /// Retrieves the identity information of a given delegate account. + /// + /// # Parameters + /// - `account`: A reference to the account ID of the delegate. + /// + /// # Returns + /// - `Option>`: An `Option` containing the identity information of the delegate + /// if it exists, otherwise `None`. pub fn get_identity_of_delegate(account: &T::AccountId) -> Option> { if let Some(value) = IdentityOf::::get(account) { return Some(value.info); @@ -10,6 +18,11 @@ impl Pallet { None } + /// Retrieves the identity information of all delegates. + /// + /// # Returns + /// - `Option>>`: An `Option` containing a vector of identity information + /// of all delegates if any exist, otherwise `None`. pub fn get_delegate_identitities() -> Option>> { let mut identities = Vec::>::new(); for id in IdentityOf::::iter_keys() { diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index ed5947625..7861b5dd2 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -132,10 +132,14 @@ impl Pallet { delegates } + /// Get all delegate identity info for a given delegate + /// pub fn get_delegate_identities() -> Option>> { RegistryPallet::::get_delegate_identitities() } + /// Get all delegate identities + /// pub fn get_identity_of_delegate(delegate_account_vec: Vec) -> Option> { if delegate_account_vec.len() != 32 { return None; From 4b736daee102dcba0837f0aa4ec2a20a036e3341 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 15 Jul 2024 14:04:56 -0700 Subject: [PATCH 08/17] add Swap Delegate Identity Hotkey --- pallets/registry/src/utils.rs | 29 +++++++++++++++++++++++++++++ pallets/subtensor/src/utils.rs | 7 +++++++ 2 files changed, 36 insertions(+) diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs index 97d0c0d4b..a504c0176 100644 --- a/pallets/registry/src/utils.rs +++ b/pallets/registry/src/utils.rs @@ -42,4 +42,33 @@ impl Pallet { None } + + /// Swaps the hotkey of a delegate identity from an old account ID to a new account ID. + /// + /// # Parameters + /// - `old_hotkey`: A reference to the current account ID (old hotkey) of the delegate identity. + /// - `new_hotkey`: A reference to the new account ID (new hotkey) to be assigned to the delegate identity. + /// + /// # Returns + /// - `bool`: A boolean value indicating success or failure. Returns `true` if the swap is + /// successful, otherwise returns `false`. + pub fn swap_delegate_identity_hotkey( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + ) -> bool { + // Check if the old hotkey exists in the identity map. + if let Some(identity_info) = IdentityOf::::take(old_hotkey) { + // Check if the new hotkey is already in use. + if IdentityOf::::contains_key(new_hotkey) { + // Reinsert the old hotkey back into the identity map to maintain consistency. + IdentityOf::::insert(old_hotkey, identity_info); + return false; // New hotkey is already in use. + } + IdentityOf::::insert(new_hotkey, identity_info); + return true; + } + + return false; // Old hotkey does not exist in Identities. + } + } diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 54b7818c9..b8e280ff2 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -1,6 +1,7 @@ use super::*; use crate::system::{ensure_root, ensure_signed_or_root}; use sp_core::U256; +use pallet_registry::Pallet as RegistryPallet; impl Pallet { pub fn ensure_subnet_owner_or_root( @@ -659,3 +660,9 @@ impl Pallet { NominatorMinRequiredStake::::put(min_stake); } } + +impl Pallet { + pub fn swap_delegate_identity_hotkey(old_hotkey: &T::AccountId, new_hotkey: &T::AccountId) -> bool { + RegistryPallet::::swap_delegate_identity_hotkey(old_hotkey, new_hotkey) + } +} From 576ac8cf459c241a7a11be9a3e58fc9d72c01b54 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:50:57 -0700 Subject: [PATCH 09/17] fix migration --- docs/delegate-info.json | 2 +- pallets/registry/src/migration.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/delegate-info.json b/docs/delegate-info.json index a8af6f46e..28a089d09 100644 --- a/docs/delegate-info.json +++ b/docs/delegate-info.json @@ -367,7 +367,7 @@ "address": "5HbLYXUBy1snPR8nfioQ7GoA9x76EELzEq9j7F32vWUQHm1x", "name": "Tensorplex Labs", "url": "https://twitter.com/TensorplexLabs", - "description": "Empowering humanity with decentralized intelligence — one epoch at a time.", + "description": "Empowering humanity with decentralized intelligence one epoch at a time.", "signature": "7a997682e7545fd14847c78abf810e9c49a23ef4297d24f4238c0edd0463934780f6831d59972d56ab5bc41d6224b59c21ed95065791632b8aca180ade22af81" }, { diff --git a/pallets/registry/src/migration.rs b/pallets/registry/src/migration.rs index b7fa2cbfe..766d7afec 100644 --- a/pallets/registry/src/migration.rs +++ b/pallets/registry/src/migration.rs @@ -58,7 +58,7 @@ pub fn migrate_set_hotkey_identities() -> Weight { for delegate in delegates.iter() { // Convert fields to bounded vecs let name_result = string_to_bounded_vec(&delegate.name); - let desc_result = string_to_bounded_vec(&delegate.description); + let desc_result = string_to_bounded_vec(&truncate_string(&delegate.description)); let url_result = string_to_bounded_vec(&delegate.url); // Convert string address into AccountID @@ -140,3 +140,12 @@ pub fn migrate_set_hotkey_identities() -> Weight { log::info!("Final weight: {:?}", weight); weight } + +fn truncate_string(s: &str) -> String { + let max_len: usize = 64; + if s.len() > max_len { + s.chars().take(max_len).collect() + } else { + s.to_string() + } +} From 62bbe181e6085b11ecdd6ae0a504b7d144975baa Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:01:25 -0700 Subject: [PATCH 10/17] add set_identity_for_delegate & tests --- pallets/registry/src/lib.rs | 6 ++ pallets/registry/src/utils.rs | 45 +++++++-- pallets/subtensor/src/utils.rs | 6 -- pallets/subtensor/tests/mock.rs | 48 ++++++++- pallets/subtensor/tests/registration.rs | 126 +++++++++++++++++++++++- 5 files changed, 213 insertions(+), 18 deletions(-) diff --git a/pallets/registry/src/lib.rs b/pallets/registry/src/lib.rs index 481406cb6..d5d32b502 100644 --- a/pallets/registry/src/lib.rs +++ b/pallets/registry/src/lib.rs @@ -89,6 +89,12 @@ pub mod pallet { TooManyFieldsInIdentityInfo, /// Account doesn't have a registered identity NotRegistered, + /// The old hotkey does not exist in the identity map. + OldHotkeyNotFound, + /// The new hotkey is already in use. + NewHotkeyInUse, + /// Attempting to set an Identity for a hotkey that already has one. + IdentityAlreadyExists, } /// Enum to hold reasons for putting funds on hold. diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs index a504c0176..1d430e4f9 100644 --- a/pallets/registry/src/utils.rs +++ b/pallets/registry/src/utils.rs @@ -1,5 +1,6 @@ use super::*; use sp_std::vec::Vec; +use sp_runtime::DispatchResult; impl Pallet { /// Retrieves the identity information of a given delegate account. @@ -43,6 +44,33 @@ impl Pallet { None } + + /// Sets the identity information for a given delegate account with provided values. + /// + /// # Parameters + /// - `account`: A reference to the account ID of the delegate. + /// - `info`: The identity information to set for the delegate. + /// + /// # Returns + /// - `DispatchResult`: Returns `Ok(())` if the identity is set successfully, otherwise returns + /// a `DispatchError`. + /// + /// # Errors + /// - `IdentityAlreadyExists`: Returned if the delegate already has an identity set. + pub fn set_identity_for_delegate(account: &T::AccountId, info: IdentityInfo) -> DispatchResult { + if IdentityOf::::contains_key(account) { + return Err(>::IdentityAlreadyExists.into()); + } + + let reg: Registration, T::MaxAdditionalFields> = Registration { + deposit: Zero::zero(), + info, + }; + + IdentityOf::::insert(account, reg); + Ok(()) // Identity set successfully + } + /// Swaps the hotkey of a delegate identity from an old account ID to a new account ID. /// /// # Parameters @@ -50,25 +78,24 @@ impl Pallet { /// - `new_hotkey`: A reference to the new account ID (new hotkey) to be assigned to the delegate identity. /// /// # Returns - /// - `bool`: A boolean value indicating success or failure. Returns `true` if the swap is - /// successful, otherwise returns `false`. + /// - `Result<(), SwapError>`: Returns `Ok(())` if the swap is successful. Returns `Err(SwapError)` otherwise. pub fn swap_delegate_identity_hotkey( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, - ) -> bool { + ) -> DispatchResult { // Check if the old hotkey exists in the identity map. - if let Some(identity_info) = IdentityOf::::take(old_hotkey) { + if let Some(identity) = IdentityOf::::take(old_hotkey) { // Check if the new hotkey is already in use. if IdentityOf::::contains_key(new_hotkey) { // Reinsert the old hotkey back into the identity map to maintain consistency. - IdentityOf::::insert(old_hotkey, identity_info); - return false; // New hotkey is already in use. + IdentityOf::::insert(old_hotkey, identity); + return Err(Error::::NewHotkeyInUse.into()); // New hotkey is already in use. } - IdentityOf::::insert(new_hotkey, identity_info); - return true; + IdentityOf::::insert(new_hotkey, identity); + return Ok(()); } - return false; // Old hotkey does not exist in Identities. + Err(Error::::OldHotkeyNotFound.into()) // Old hotkey does not exist in Identities. } } diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index b8e280ff2..0d254ebba 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -1,7 +1,6 @@ use super::*; use crate::system::{ensure_root, ensure_signed_or_root}; use sp_core::U256; -use pallet_registry::Pallet as RegistryPallet; impl Pallet { pub fn ensure_subnet_owner_or_root( @@ -661,8 +660,3 @@ impl Pallet { } } -impl Pallet { - pub fn swap_delegate_identity_hotkey(old_hotkey: &T::AccountId, new_hotkey: &T::AccountId) -> bool { - RegistryPallet::::swap_delegate_identity_hotkey(old_hotkey, new_hotkey) - } -} diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 9995acf84..c2ca1905e 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -1,3 +1,4 @@ +use codec::{Decode, Encode}; use frame_support::derive_impl; use frame_support::dispatch::DispatchResultWithPostInfo; use frame_support::{ @@ -14,8 +15,12 @@ use sp_runtime::{ }; use pallet_collective::MemberCount; - type Block = frame_system::mocking::MockBlock; +use sp_core::RuntimeDebug; +use frame_support::pallet_prelude::TypeInfo; +use frame_support::traits::VariantCount; +use codec::MaxEncodedLen; + // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -29,6 +34,7 @@ frame_support::construct_runtime!( SenateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event}, Utility: pallet_utility::{Pallet, Call, Storage, Event}, + Registry: pallet_registry::{Pallet, Call, Storage, Event}, } ); @@ -47,6 +53,8 @@ pub type TestRuntimeCall = frame_system::Call; parameter_types! { pub const BlockHashCount: u64 = 250; pub const SS58Prefix: u8 = 42; + pub const InitialDeposit: u32 = 10_000; + pub const FieldDeposit: u32 = 1_000; } #[allow(dead_code)] @@ -64,6 +72,42 @@ pub type Balance = u64; #[allow(dead_code)] pub type BlockNumber = u64; +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, Clone, Copy, Default, TypeInfo)] +pub struct CustomHoldReason; + +impl From for CustomHoldReason { + fn from(_: pallet_registry::HoldReason) -> Self { + CustomHoldReason + } +} + +impl VariantCount for CustomHoldReason { + const VARIANT_COUNT: u32 = 1; // Since CustomHoldReason is a single variant +} + +impl MaxEncodedLen for CustomHoldReason { + fn max_encoded_len() -> usize { + 1 // The maximum encoded length of CustomHoldReason is 1 byte. + } +} + +impl Get for CustomHoldReason { + fn get() -> u32 { + 0 + } +} + +impl pallet_registry::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = (); + type CanRegister = (); + type MaxAdditionalFields = (); + type InitialDeposit = InitialDeposit; + type FieldDeposit = FieldDeposit; + type RuntimeHoldReason = CustomHoldReason; +} + #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type Balance = Balance; @@ -76,7 +120,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = (); - type RuntimeHoldReason = (); + type RuntimeHoldReason = CustomHoldReason; type FreezeIdentifier = (); type MaxFreezes = (); } diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 5ee941f26..1aaf551d9 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -3,11 +3,12 @@ use frame_support::traits::Currency; use crate::mock::*; use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}; use frame_support::sp_runtime::{transaction_validity::InvalidTransaction, DispatchError}; -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok, BoundedVec}; use frame_system::Config; use pallet_subtensor::{AxonInfoOf, Error, SubtensorSignedExtension}; use sp_core::U256; use sp_runtime::traits::{DispatchInfoOf, SignedExtension}; +use pallet_registry::{IdentityInfo, Error as RegistryError, Data}; mod mock; @@ -2016,3 +2017,126 @@ fn test_hotkey_swap_registered_key() { ); }); } + +#[test] +fn test_swap_delegate_identity_hotkey_successful() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let display = b"Old Display".to_vec(); + let old_identity_info = create_identity_info(display.clone()); + + // Set identity for the old hotkey + assert_ok!(Registry::set_identity_for_delegate(&old_hotkey, old_identity_info)); + + // Swap the hotkey + assert_ok!(Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey)); + assert!(Registry::get_identity_of_delegate(&new_hotkey).is_some()); + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + + // Verify the identity information is correctly swapped + let identity_info = Registry::get_identity_of_delegate(&new_hotkey); + assert_eq!(identity_info.unwrap().display, Data::Raw(BoundedVec::try_from(display).unwrap())); + }); +} + +#[test] +fn test_swap_delegate_identity_hotkey_new_hotkey_already_exists() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let old_display = b"Old Display".to_vec(); + let new_display = b"New Display".to_vec(); + + let old_identity_info = create_identity_info(old_display.clone()); + let new_identity_info = create_identity_info(new_display.clone()); + + // Add identity for old hotkey and new hotkey + assert_ok!(Registry::set_identity_for_delegate(&old_hotkey, old_identity_info)); + assert_ok!(Registry::set_identity_for_delegate(&new_hotkey, new_identity_info)); + + // Attempt to swap hotkey to one that is already in use + assert_err!( + Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), + RegistryError::::NewHotkeyInUse + ); + + // Verify both identities remain unchanged + let stored_old_identity = Registry::get_identity_of_delegate(&old_hotkey).unwrap(); + assert_eq!(stored_old_identity.display, Data::Raw(BoundedVec::try_from(old_display).unwrap())); + + let stored_new_identity = Registry::get_identity_of_delegate(&new_hotkey).unwrap(); + assert_eq!(stored_new_identity.display, Data::Raw(BoundedVec::try_from(new_display).unwrap())); + }); +} + +#[test] +fn test_swap_delegate_identity_hotkey_old_hotkey_does_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + // Ensure old hotkey does not exist + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + + assert_err!(Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), RegistryError::::OldHotkeyNotFound); + assert!(Registry::get_identity_of_delegate(&new_hotkey).is_none()); + }); +} + +#[test] + fn test_set_identity_for_delegate_success() { + new_test_ext(1).execute_with(|| { + let account = U256::from(1); + let identity_info = create_identity_info(b"Test Display".to_vec()); + + // Initially, the account should not have any identity set + assert!(Registry::get_identity_of_delegate(&account).is_none()); + + // Set identity for the account + assert_ok!(Registry::set_identity_for_delegate(&account, identity_info.clone())); + + // Verify the identity is set correctly + let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); + assert_eq!(stored_identity.display, identity_info.display); + }); + } + + #[test] + fn test_set_identity_for_delegate_identity_already_exists() { + new_test_ext(1).execute_with(|| { + let account = U256::from(1); + let identity_info = create_identity_info(b"Test Display".to_vec()); + + // Set identity for the account + assert_ok!(Registry::set_identity_for_delegate(&account, identity_info.clone())); + + // Attempt to set another identity for the same account + let new_identity_info = create_identity_info(b"New Display".to_vec()); + assert_err!( + Registry::set_identity_for_delegate(&account, new_identity_info), + RegistryError::::IdentityAlreadyExists + ); + + // Verify the original identity remains unchanged + let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); + assert_eq!(stored_identity.display, identity_info.display); + }); + } + +fn create_identity_info(display: Vec) -> IdentityInfo<()> { + let display_data = Data::Raw(BoundedVec::try_from(display).unwrap()); + IdentityInfo { + additional: Default::default(), + display: display_data, + legal: Default::default(), + web: Default::default(), + riot: Default::default(), + email: Default::default(), + pgp_fingerprint: None, + image: Default::default(), + twitter: Default::default(), + } +} \ No newline at end of file From 3ca90845cff95702012e6eb570817451b97255c6 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:02:33 -0700 Subject: [PATCH 11/17] fmt --- pallets/registry/src/utils.rs | 19 ++-- pallets/subtensor/rpc/src/lib.rs | 15 ++- pallets/subtensor/src/delegate_info.rs | 11 ++- pallets/subtensor/src/utils.rs | 1 - pallets/subtensor/tests/mock.rs | 9 +- pallets/subtensor/tests/registration.rs | 118 +++++++++++++++--------- 6 files changed, 106 insertions(+), 67 deletions(-) diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs index 1d430e4f9..3548ee4db 100644 --- a/pallets/registry/src/utils.rs +++ b/pallets/registry/src/utils.rs @@ -1,6 +1,6 @@ use super::*; -use sp_std::vec::Vec; use sp_runtime::DispatchResult; +use sp_std::vec::Vec; impl Pallet { /// Retrieves the identity information of a given delegate account. @@ -11,7 +11,9 @@ impl Pallet { /// # Returns /// - `Option>`: An `Option` containing the identity information of the delegate /// if it exists, otherwise `None`. - pub fn get_identity_of_delegate(account: &T::AccountId) -> Option> { + pub fn get_identity_of_delegate( + account: &T::AccountId, + ) -> Option> { if let Some(value) = IdentityOf::::get(account) { return Some(value.info); } @@ -38,13 +40,12 @@ impl Pallet { } if identities.len() > 0 { - return Some(identities) + return Some(identities); } - + None } - /// Sets the identity information for a given delegate account with provided values. /// /// # Parameters @@ -57,7 +58,10 @@ impl Pallet { /// /// # Errors /// - `IdentityAlreadyExists`: Returned if the delegate already has an identity set. - pub fn set_identity_for_delegate(account: &T::AccountId, info: IdentityInfo) -> DispatchResult { + pub fn set_identity_for_delegate( + account: &T::AccountId, + info: IdentityInfo, + ) -> DispatchResult { if IdentityOf::::contains_key(account) { return Err(>::IdentityAlreadyExists.into()); } @@ -91,11 +95,10 @@ impl Pallet { IdentityOf::::insert(old_hotkey, identity); return Err(Error::::NewHotkeyInUse.into()); // New hotkey is already in use. } - IdentityOf::::insert(new_hotkey, identity); + IdentityOf::::insert(new_hotkey, identity); return Ok(()); } Err(Error::::OldHotkeyNotFound.into()) // Old hotkey does not exist in Identities. } - } diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs index ec9c0e43e..9b94b2ed9 100644 --- a/pallets/subtensor/rpc/src/lib.rs +++ b/pallets/subtensor/rpc/src/lib.rs @@ -33,7 +33,11 @@ pub trait SubtensorCustomApi { at: Option, ) -> RpcResult>; #[method(name = "delegateInfo_getIdentityOfDelegate")] - fn get_identity_of_delegate(&self, delegate_account_vec: Vec, at: Option) -> RpcResult>; + fn get_identity_of_delegate( + &self, + delegate_account_vec: Vec, + at: Option, + ) -> RpcResult>; #[method(name = "delegateInfo_getDelegateIdentities")] fn get_delegate_identities(&self, at: Option) -> RpcResult>; @@ -147,12 +151,13 @@ where let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); - api.get_identity_of_delegate(at, delegatee_account_vec).map_err(|e| { - Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() - }) + api.get_identity_of_delegate(at, delegatee_account_vec) + .map_err(|e| { + Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() + }) } - fn get_delegate_identities(&self, at: Option<::Hash>) -> RpcResult> { + fn get_delegate_identities(&self, at: Option<::Hash>) -> RpcResult> { let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index 7861b5dd2..47419304c 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -133,18 +133,21 @@ impl Pallet { } /// Get all delegate identity info for a given delegate - /// + /// pub fn get_delegate_identities() -> Option>> { RegistryPallet::::get_delegate_identitities() } /// Get all delegate identities - /// - pub fn get_identity_of_delegate(delegate_account_vec: Vec) -> Option> { + /// + pub fn get_identity_of_delegate( + delegate_account_vec: Vec, + ) -> Option> { if delegate_account_vec.len() != 32 { return None; } - let account: AccountIdOf = T::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()).ok()?; + let account: AccountIdOf = + T::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()).ok()?; RegistryPallet::::get_identity_of_delegate(&account) } diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 0d254ebba..54b7818c9 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -659,4 +659,3 @@ impl Pallet { NominatorMinRequiredStake::::put(min_stake); } } - diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index c2ca1905e..52970445c 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -16,11 +16,10 @@ use sp_runtime::{ use pallet_collective::MemberCount; type Block = frame_system::mocking::MockBlock; -use sp_core::RuntimeDebug; +use codec::MaxEncodedLen; use frame_support::pallet_prelude::TypeInfo; use frame_support::traits::VariantCount; -use codec::MaxEncodedLen; - +use sp_core::RuntimeDebug; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -101,8 +100,8 @@ impl pallet_registry::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type WeightInfo = (); - type CanRegister = (); - type MaxAdditionalFields = (); + type CanRegister = (); + type MaxAdditionalFields = (); type InitialDeposit = InitialDeposit; type FieldDeposit = FieldDeposit; type RuntimeHoldReason = CustomHoldReason; diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 1aaf551d9..258e05206 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -5,10 +5,10 @@ use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays use frame_support::sp_runtime::{transaction_validity::InvalidTransaction, DispatchError}; use frame_support::{assert_err, assert_noop, assert_ok, BoundedVec}; use frame_system::Config; +use pallet_registry::{Data, Error as RegistryError, IdentityInfo}; use pallet_subtensor::{AxonInfoOf, Error, SubtensorSignedExtension}; use sp_core::U256; use sp_runtime::traits::{DispatchInfoOf, SignedExtension}; -use pallet_registry::{IdentityInfo, Error as RegistryError, Data}; mod mock; @@ -2028,16 +2028,25 @@ fn test_swap_delegate_identity_hotkey_successful() { let old_identity_info = create_identity_info(display.clone()); // Set identity for the old hotkey - assert_ok!(Registry::set_identity_for_delegate(&old_hotkey, old_identity_info)); + assert_ok!(Registry::set_identity_for_delegate( + &old_hotkey, + old_identity_info + )); // Swap the hotkey - assert_ok!(Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey)); + assert_ok!(Registry::swap_delegate_identity_hotkey( + &old_hotkey, + &new_hotkey + )); assert!(Registry::get_identity_of_delegate(&new_hotkey).is_some()); assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); // Verify the identity information is correctly swapped let identity_info = Registry::get_identity_of_delegate(&new_hotkey); - assert_eq!(identity_info.unwrap().display, Data::Raw(BoundedVec::try_from(display).unwrap())); + assert_eq!( + identity_info.unwrap().display, + Data::Raw(BoundedVec::try_from(display).unwrap()) + ); }); } @@ -2054,8 +2063,14 @@ fn test_swap_delegate_identity_hotkey_new_hotkey_already_exists() { let new_identity_info = create_identity_info(new_display.clone()); // Add identity for old hotkey and new hotkey - assert_ok!(Registry::set_identity_for_delegate(&old_hotkey, old_identity_info)); - assert_ok!(Registry::set_identity_for_delegate(&new_hotkey, new_identity_info)); + assert_ok!(Registry::set_identity_for_delegate( + &old_hotkey, + old_identity_info + )); + assert_ok!(Registry::set_identity_for_delegate( + &new_hotkey, + new_identity_info + )); // Attempt to swap hotkey to one that is already in use assert_err!( @@ -2065,10 +2080,16 @@ fn test_swap_delegate_identity_hotkey_new_hotkey_already_exists() { // Verify both identities remain unchanged let stored_old_identity = Registry::get_identity_of_delegate(&old_hotkey).unwrap(); - assert_eq!(stored_old_identity.display, Data::Raw(BoundedVec::try_from(old_display).unwrap())); + assert_eq!( + stored_old_identity.display, + Data::Raw(BoundedVec::try_from(old_display).unwrap()) + ); let stored_new_identity = Registry::get_identity_of_delegate(&new_hotkey).unwrap(); - assert_eq!(stored_new_identity.display, Data::Raw(BoundedVec::try_from(new_display).unwrap())); + assert_eq!( + stored_new_identity.display, + Data::Raw(BoundedVec::try_from(new_display).unwrap()) + ); }); } @@ -2081,50 +2102,59 @@ fn test_swap_delegate_identity_hotkey_old_hotkey_does_not_exist() { // Ensure old hotkey does not exist assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); - assert_err!(Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), RegistryError::::OldHotkeyNotFound); + assert_err!( + Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), + RegistryError::::OldHotkeyNotFound + ); assert!(Registry::get_identity_of_delegate(&new_hotkey).is_none()); }); } #[test] - fn test_set_identity_for_delegate_success() { - new_test_ext(1).execute_with(|| { - let account = U256::from(1); - let identity_info = create_identity_info(b"Test Display".to_vec()); +fn test_set_identity_for_delegate_success() { + new_test_ext(1).execute_with(|| { + let account = U256::from(1); + let identity_info = create_identity_info(b"Test Display".to_vec()); - // Initially, the account should not have any identity set - assert!(Registry::get_identity_of_delegate(&account).is_none()); + // Initially, the account should not have any identity set + assert!(Registry::get_identity_of_delegate(&account).is_none()); - // Set identity for the account - assert_ok!(Registry::set_identity_for_delegate(&account, identity_info.clone())); + // Set identity for the account + assert_ok!(Registry::set_identity_for_delegate( + &account, + identity_info.clone() + )); - // Verify the identity is set correctly - let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); - assert_eq!(stored_identity.display, identity_info.display); - }); - } + // Verify the identity is set correctly + let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); + assert_eq!(stored_identity.display, identity_info.display); + }); +} - #[test] - fn test_set_identity_for_delegate_identity_already_exists() { - new_test_ext(1).execute_with(|| { - let account = U256::from(1); - let identity_info = create_identity_info(b"Test Display".to_vec()); - - // Set identity for the account - assert_ok!(Registry::set_identity_for_delegate(&account, identity_info.clone())); - - // Attempt to set another identity for the same account - let new_identity_info = create_identity_info(b"New Display".to_vec()); - assert_err!( - Registry::set_identity_for_delegate(&account, new_identity_info), - RegistryError::::IdentityAlreadyExists - ); - - // Verify the original identity remains unchanged - let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); - assert_eq!(stored_identity.display, identity_info.display); - }); - } +#[test] +fn test_set_identity_for_delegate_identity_already_exists() { + new_test_ext(1).execute_with(|| { + let account = U256::from(1); + let identity_info = create_identity_info(b"Test Display".to_vec()); + + // Set identity for the account + assert_ok!(Registry::set_identity_for_delegate( + &account, + identity_info.clone() + )); + + // Attempt to set another identity for the same account + let new_identity_info = create_identity_info(b"New Display".to_vec()); + assert_err!( + Registry::set_identity_for_delegate(&account, new_identity_info), + RegistryError::::IdentityAlreadyExists + ); + + // Verify the original identity remains unchanged + let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); + assert_eq!(stored_identity.display, identity_info.display); + }); +} fn create_identity_info(display: Vec) -> IdentityInfo<()> { let display_data = Data::Raw(BoundedVec::try_from(display).unwrap()); @@ -2139,4 +2169,4 @@ fn create_identity_info(display: Vec) -> IdentityInfo<()> { image: Default::default(), twitter: Default::default(), } -} \ No newline at end of file +} From b555c6c6933c5d6e6f34c82f953094534d40fd60 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Sun, 21 Jul 2024 12:47:51 -0700 Subject: [PATCH 12/17] add RegistryPallet implementations --- Cargo.lock | 1 + pallets/admin-utils/Cargo.toml | 2 +- pallets/admin-utils/tests/mock.rs | 95 ++++++++++++++++++- pallets/registry/src/utils.rs | 2 +- pallets/subtensor/rpc/src/lib.rs | 2 +- pallets/subtensor/runtime-api/src/lib.rs | 2 +- pallets/subtensor/src/delegate_info.rs | 25 +++-- pallets/subtensor/src/lib.rs | 17 ++++ pallets/subtensor/src/registration.rs | 4 + pallets/subtensor/tests/mock.rs | 53 ++++++++++- pallets/subtensor/tests/registration.rs | 113 ++++++++++++++++++++++- runtime/src/lib.rs | 47 ++++++++-- 12 files changed, 336 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94f54fe09..00507c67d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4897,6 +4897,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", + "pallet-registry", "pallet-subtensor", "parity-scale-codec", "scale-info", diff --git a/pallets/admin-utils/Cargo.toml b/pallets/admin-utils/Cargo.toml index 31c62c7da..1d314b4e3 100644 --- a/pallets/admin-utils/Cargo.toml +++ b/pallets/admin-utils/Cargo.toml @@ -27,7 +27,7 @@ sp-runtime = { workspace = true } log = { workspace = true } pallet-subtensor = { version = "4.0.0-dev", default-features = false, path = "../subtensor" } sp-weights = { workspace = true } - +pallet-registry= { default-features = false, path = "../registry" } [dev-dependencies] sp-core = { workspace = true } diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index c0985b010..928654b2a 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -1,13 +1,19 @@ +use codec::MaxEncodedLen; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{Everything, Hooks}, + traits::{Everything, Hooks, VariantCount}, weights, }; use frame_system as system; use frame_system::{limits, EnsureNever}; +use pallet_registry::IdentityInfo; +use pallet_subtensor::RegistryInterface; +use scale_info::TypeInfo; use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_core::U256; use sp_core::{ConstU64, H256}; +use sp_core::{Decode, Encode, Get, RuntimeDebug, U256}; +use sp_runtime::traits::PhantomData; +use sp_runtime::DispatchResult; use sp_runtime::{ traits::{BlakeTwo256, ConstU32, IdentityLookup}, BuildStorage, DispatchError, @@ -20,9 +26,10 @@ frame_support::construct_runtime!( pub enum Test { System: frame_system, - Balances: pallet_balances, + Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, AdminUtils: pallet_admin_utils, SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event}, + Registry: pallet_registry::{Pallet, Call, Storage, Event}, } ); @@ -58,6 +65,53 @@ pub type Balance = u64; #[allow(dead_code)] pub type BlockNumber = u64; +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, Clone, Copy, Default, TypeInfo)] +pub struct CustomHoldReason; + +impl From for CustomHoldReason { + fn from(_: pallet_registry::HoldReason) -> Self { + CustomHoldReason + } +} + +impl VariantCount for CustomHoldReason { + const VARIANT_COUNT: u32 = 1; // Since CustomHoldReason is a single variant +} + +impl MaxEncodedLen for CustomHoldReason { + fn max_encoded_len() -> usize { + 1 // The maximum encoded length of CustomHoldReason is 1 byte. + } +} + +impl Get for CustomHoldReason { + fn get() -> u32 { + 0 + } +} + +pub struct MockMaxAdditionalFields; +impl Get for MockMaxAdditionalFields { + fn get() -> u32 { + 1 + } +} +parameter_types! { + pub const InitialDeposit: u32 = 10_000; + pub const FieldDeposit: u32 = 1_000; +} + +impl pallet_registry::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = (); + type CanRegister = (); + type MaxAdditionalFields = MockMaxAdditionalFields; + type InitialDeposit = InitialDeposit; + type FieldDeposit = FieldDeposit; + type RuntimeHoldReason = CustomHoldReason; +} + parameter_types! { pub const InitialMinAllowedWeights: u16 = 0; pub const InitialEmissionValue: u16 = 0; @@ -111,6 +165,37 @@ parameter_types! { } +pub struct RegistryPalletImpl(PhantomData); + +impl RegistryInterface for RegistryPalletImpl +where + T: pallet_subtensor::Config, + T::AccountId: Into + Clone, +{ + /// Retrieves the identity information of a given delegate account. + fn get_identity_of_delegate( + account: &T::AccountId, + ) -> Option> { + Registry::get_identity_of_delegate(&account.clone().into()) + } + + /// Retrieves the identity information of all delegates. + fn get_delegate_identities() -> Option>> { + Registry::get_delegate_identities() + } + + /// Swaps the hotkey of a delegate identity from an old account ID to a new account ID. + fn swap_delegate_identity_hotkey( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + ) -> DispatchResult { + Registry::swap_delegate_identity_hotkey( + &old_hotkey.clone().into(), + &new_hotkey.clone().into(), + ) + } +} + impl pallet_subtensor::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -119,6 +204,8 @@ impl pallet_subtensor::Config for Test { type CouncilOrigin = EnsureNever; type SenateMembers = (); type TriumvirateInterface = (); + type MaxAdditionalFields = MockMaxAdditionalFields; + type RegistryPallet = RegistryPalletImpl; type InitialMinAllowedWeights = InitialMinAllowedWeights; type InitialEmissionValue = InitialEmissionValue; @@ -202,7 +289,7 @@ impl pallet_balances::Config for Test { type WeightInfo = (); type FreezeIdentifier = (); type MaxFreezes = (); - type RuntimeHoldReason = (); + type RuntimeHoldReason = CustomHoldReason; } pub struct SubtensorIntrf; diff --git a/pallets/registry/src/utils.rs b/pallets/registry/src/utils.rs index 3548ee4db..c4503e0b4 100644 --- a/pallets/registry/src/utils.rs +++ b/pallets/registry/src/utils.rs @@ -26,7 +26,7 @@ impl Pallet { /// # Returns /// - `Option>>`: An `Option` containing a vector of identity information /// of all delegates if any exist, otherwise `None`. - pub fn get_delegate_identitities() -> Option>> { + pub fn get_delegate_identities() -> Option>> { let mut identities = Vec::>::new(); for id in IdentityOf::::iter_keys() { let identity_info = Self::get_identity_of_delegate(&id); diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs index 9b94b2ed9..1aca45ae9 100644 --- a/pallets/subtensor/rpc/src/lib.rs +++ b/pallets/subtensor/rpc/src/lib.rs @@ -161,7 +161,7 @@ where let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); - api.get_delegate_identitities(at).map_err(|e| { + api.get_delegate_identities(at).map_err(|e| { Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() }) } diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index 562db4d33..5d123f7a2 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -9,7 +9,7 @@ sp_api::decl_runtime_apis! { fn get_delegates() -> Vec; fn get_delegate( delegate_account_vec: Vec ) -> Vec; fn get_delegated( delegatee_account_vec: Vec ) -> Vec; - fn get_delegate_identitities() -> Vec; + fn get_delegate_identities() -> Vec; fn get_identity_of_delegate( delegatee_account_vec: Vec ) -> Vec; } diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index 47419304c..aba3c831e 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -134,21 +134,32 @@ impl Pallet { /// Get all delegate identity info for a given delegate /// - pub fn get_delegate_identities() -> Option>> { - RegistryPallet::::get_delegate_identitities() + pub fn get_delegate_identities() -> Option>> + where + C: pallet::Config, + R: pallet_registry::Config, + { + RegistryPallet::::get_delegate_identities() } /// Get all delegate identities /// - pub fn get_identity_of_delegate( + pub fn get_identity_of_delegate( delegate_account_vec: Vec, - ) -> Option> { + ) -> Option> + where + C: pallet::Config, + R: pallet_registry::Config< + MaxAdditionalFields = C::MaxAdditionalFields, + AccountId = C::AccountId, + >, + { if delegate_account_vec.len() != 32 { return None; } - let account: AccountIdOf = - T::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()).ok()?; + let account: AccountIdOf = + R::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()).ok()?; - RegistryPallet::::get_identity_of_delegate(&account) + RegistryPallet::::get_identity_of_delegate(&account) } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index b590781f5..f3ec3632b 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -18,7 +18,9 @@ use frame_support::{ use codec::{Decode, Encode}; use frame_support::sp_runtime::transaction_validity::InvalidTransaction; use frame_support::sp_runtime::transaction_validity::ValidTransaction; +use pallet_registry::IdentityInfo; use scale_info::TypeInfo; +use sp_core::Get; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, transaction_validity::{TransactionValidity, TransactionValidityError}, @@ -111,6 +113,12 @@ pub mod pallet { /// Interface to allow other pallets to control who can register identities type TriumvirateInterface: crate::CollectiveInterface; + /// Docs + type MaxAdditionalFields: Get; + + /// Implementation of + type RegistryPallet: crate::RegistryInterface; + /// ================================= /// ==== Initial Value Constants ==== /// ================================= @@ -2422,3 +2430,12 @@ impl CollectiveInterface for () { Ok(true) } } + +pub trait RegistryInterface> { + fn get_identity_of_delegate(account: &AccountId) -> Option>; + fn get_delegate_identities() -> Option>>; + fn swap_delegate_identity_hotkey( + old_hotkey: &AccountId, + new_hotkey: &AccountId, + ) -> DispatchResult; +} diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/registration.rs index 88730f7c3..3035dbab0 100644 --- a/pallets/subtensor/src/registration.rs +++ b/pallets/subtensor/src/registration.rs @@ -714,6 +714,10 @@ impl Pallet { } } + if T::RegistryPallet::get_identity_of_delegate(old_hotkey).is_some() { + T::RegistryPallet::swap_delegate_identity_hotkey(old_hotkey, new_hotkey)?; + } + Self::set_last_tx_block(&coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 52970445c..fad611c07 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -10,17 +10,20 @@ use frame_system as system; use frame_system::{limits, EnsureNever, EnsureRoot, RawOrigin}; use sp_core::{Get, H256, U256}; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + traits::{BlakeTwo256, IdentityLookup, PhantomData}, + BuildStorage, DispatchResult, }; -use pallet_collective::MemberCount; -type Block = frame_system::mocking::MockBlock; use codec::MaxEncodedLen; use frame_support::pallet_prelude::TypeInfo; use frame_support::traits::VariantCount; +use pallet_collective::MemberCount; +use pallet_registry::IdentityInfo; +use pallet_subtensor::RegistryInterface; use sp_core::RuntimeDebug; +type Block = frame_system::mocking::MockBlock; + // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( pub enum Test @@ -96,12 +99,19 @@ impl Get for CustomHoldReason { } } +pub struct MockMaxAdditionalFields; +impl Get for MockMaxAdditionalFields { + fn get() -> u32 { + 1 + } +} + impl pallet_registry::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type WeightInfo = (); type CanRegister = (); - type MaxAdditionalFields = (); + type MaxAdditionalFields = MockMaxAdditionalFields; type InitialDeposit = InitialDeposit; type FieldDeposit = FieldDeposit; type RuntimeHoldReason = CustomHoldReason; @@ -352,6 +362,37 @@ impl pallet_membership::Config for Test { type WeightInfo = pallet_membership::weights::SubstrateWeight; } +pub struct RegistryPalletImpl(PhantomData); + +impl RegistryInterface for RegistryPalletImpl +where + T: pallet_subtensor::Config, + T::AccountId: Into + Clone, +{ + /// Retrieves the identity information of a given delegate account. + fn get_identity_of_delegate( + account: &T::AccountId, + ) -> Option> { + Registry::get_identity_of_delegate(&account.clone().into()) + } + + /// Retrieves the identity information of all delegates. + fn get_delegate_identities() -> Option>> { + Registry::get_delegate_identities() + } + + /// Swaps the hotkey of a delegate identity from an old account ID to a new account ID. + fn swap_delegate_identity_hotkey( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + ) -> DispatchResult { + Registry::swap_delegate_identity_hotkey( + &old_hotkey.clone().into(), + &new_hotkey.clone().into(), + ) + } +} + impl pallet_subtensor::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -360,6 +401,8 @@ impl pallet_subtensor::Config for Test { type CouncilOrigin = frame_system::EnsureSigned; type SenateMembers = ManageSenateMembers; type TriumvirateInterface = TriumvirateVotes; + type RegistryPallet = RegistryPalletImpl; + type MaxAdditionalFields = MockMaxAdditionalFields; type InitialMinAllowedWeights = InitialMinAllowedWeights; type InitialEmissionValue = InitialEmissionValue; diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 258e05206..d4fd8831a 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -2156,7 +2156,118 @@ fn test_set_identity_for_delegate_identity_already_exists() { }); } -fn create_identity_info(display: Vec) -> IdentityInfo<()> { +#[test] +fn test_hotkey_swap_fail_same_hotkey() { + new_test_ext(1).execute_with(|| { + let coldkey_account_id = U256::from(667); + let old_hotkey = U256::from(1); + + let netuid = 1; + let burn_cost = 10; + let tempo = 1; + + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000u64); + + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + old_hotkey + )); + + assert_noop!( + SubtensorModule::swap_hotkey( + <::RuntimeOrigin>::signed(coldkey_account_id), + old_hotkey, + old_hotkey + ), + Error::::NewHotKeyIsSameWithOld + ); + }); +} + +#[test] +fn test_hotkey_swap_fail_not_enough_balance() { + new_test_ext(1).execute_with(|| { + let coldkey_account_id = U256::from(667); + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let netuid = 1; + let burn_cost = 10; + let tempo = 1; + + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000u64); + + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + old_hotkey + )); + + assert_err!( + SubtensorModule::swap_hotkey( + <::RuntimeOrigin>::signed(coldkey_account_id), + old_hotkey, + new_hotkey + ), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + }); +} + +#[test] +fn test_hotkey_swap_delegate_identity_updated() { + new_test_ext(1).execute_with(|| { + let coldkey_account_id = U256::from(667); + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let netuid = 1; + let burn_cost = 10; + let tempo = 1; + + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000_000); + + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + old_hotkey + )); + + let display = b"The Display".to_vec(); + let identity_info: IdentityInfo = + create_identity_info(display.clone()); + + assert_ok!(Registry::set_identity_for_delegate( + &old_hotkey, + identity_info.clone() + )); + + assert_ok!(SubtensorModule::swap_hotkey( + <::RuntimeOrigin>::signed(coldkey_account_id), + old_hotkey, + new_hotkey + )); + + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + assert!(Registry::get_identity_of_delegate(&new_hotkey).is_some()); + assert_eq!( + Registry::get_identity_of_delegate(&new_hotkey).unwrap(), + identity_info + ); + }); +} + +fn create_identity_info(display: Vec) -> IdentityInfo { let display_data = Data::Raw(BoundedVec::try_from(display).unwrap()); IdentityInfo { additional: Default::default(), diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index cb423918a..77a674d53 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -21,7 +21,8 @@ use pallet_commitments::CanCommit; use pallet_grandpa::{ fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; -use pallet_registry::CanRegisterIdentity; +use pallet_registry::{CanRegisterIdentity, IdentityInfo}; +use pallet_subtensor::RegistryInterface; use scale_info::TypeInfo; use smallvec::smallvec; use sp_api::impl_runtime_apis; @@ -30,10 +31,11 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata, RuntimeDebug}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ - AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, + AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, + PhantomData, Verify, }, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + AccountId32, ApplyExtrinsicResult, DispatchResult, MultiSignature, }; use sp_std::cmp::Ordering; use sp_std::prelude::*; @@ -819,6 +821,37 @@ parameter_types! { pub const SubtensorInitialTargetStakesPerInterval: u16 = 1; } +pub struct RegistryPalletImpl(PhantomData); + +impl RegistryInterface for RegistryPalletImpl +where + T: pallet_subtensor::Config, + T::AccountId: Clone + Into, +{ + /// Retrieves the identity information of a given delegate account. + fn get_identity_of_delegate( + account: &T::AccountId, + ) -> Option> { + Registry::get_identity_of_delegate(&account.clone().into()) + } + + /// Retrieves the identity information of all delegates. + fn get_delegate_identities() -> Option>> { + Registry::get_delegate_identities() + } + + /// Swaps the hotkey of a delegate identity from an old account ID to a new account ID. + fn swap_delegate_identity_hotkey( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + ) -> DispatchResult { + Registry::swap_delegate_identity_hotkey( + &old_hotkey.clone().into(), + &new_hotkey.clone().into(), + ) + } +} + impl pallet_subtensor::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SudoRuntimeCall = RuntimeCall; @@ -826,6 +859,8 @@ impl pallet_subtensor::Config for Runtime { type CouncilOrigin = EnsureMajoritySenate; type SenateMembers = ManageSenateMembers; type TriumvirateInterface = TriumvirateVotes; + type RegistryPallet = RegistryPalletImpl; + type MaxAdditionalFields = MaxAdditionalFields; type InitialRho = SubtensorInitialRho; type InitialKappa = SubtensorInitialKappa; @@ -1502,13 +1537,13 @@ impl_runtime_apis! { result.encode() } - fn get_delegate_identitities() -> Vec { - let result = SubtensorModule::get_delegate_identities(); + fn get_delegate_identities() -> Vec { + let result = SubtensorModule::get_delegate_identities::(); result.encode() } fn get_identity_of_delegate(delegatee_account_vec: Vec) -> Vec { - let result = SubtensorModule::get_identity_of_delegate(delegatee_account_vec); + let result = SubtensorModule::get_identity_of_delegate::(delegatee_account_vec); result.encode() } } From 4ea7d401378dff9be79b56c7c0f4b06ef40cf981 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Sun, 21 Jul 2024 17:42:01 -0700 Subject: [PATCH 13/17] replace bad char --- docs/delegate-info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/delegate-info.json b/docs/delegate-info.json index 28a089d09..bda41b48e 100644 --- a/docs/delegate-info.json +++ b/docs/delegate-info.json @@ -297,7 +297,7 @@ "address": "5FFM6Nvvm78GqyMratgXXvjbqZPi7SHgSQ81nyS96jBuUWgt", "name": "PRvalidator", "url": "www.prvalidator.com", - "description": "A professional media validator dedicated to securing top-tier coverage in the world’s most recognized publications building Bittensor’s brand equity and creating global awareness of $TAO.", + "description": "A professional media validator dedicated to securing top-tier coverage in the world's most recognized publications building Bittensor's brand equity and creating global awareness of $TAO.", "signature": "fe65e76a9f42049715585180500213c6f0535b8b25911b957921bdfb5a20156d6de68dc2633dbc5ce1d0ab9ef386d566687ac3d86f6988141b34cd24c0f13488" }, { From 60fab8c24ccc02680d5dceb74139335319b32969 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:02:29 -0700 Subject: [PATCH 14/17] fix merge --- pallets/admin-utils/tests/mock.rs | 31 ------------------------- pallets/subtensor/src/delegate_info.rs | 2 +- pallets/subtensor/tests/mock.rs | 1 - pallets/subtensor/tests/registration.rs | 18 +++++++------- 4 files changed, 10 insertions(+), 42 deletions(-) diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index 18499840b..9bb12a1fc 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -202,37 +202,6 @@ where } } -pub struct RegistryPalletImpl(PhantomData); - -impl RegistryInterface for RegistryPalletImpl -where - T: pallet_subtensor::Config, - T::AccountId: Into + Clone, -{ - /// Retrieves the identity information of a given delegate account. - fn get_identity_of_delegate( - account: &T::AccountId, - ) -> Option> { - Registry::get_identity_of_delegate(&account.clone().into()) - } - - /// Retrieves the identity information of all delegates. - fn get_delegate_identities() -> Option>> { - Registry::get_delegate_identities() - } - - /// Swaps the hotkey of a delegate identity from an old account ID to a new account ID. - fn swap_delegate_identity_hotkey( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - ) -> DispatchResult { - Registry::swap_delegate_identity_hotkey( - &old_hotkey.clone().into(), - &new_hotkey.clone().into(), - ) - } -} - impl pallet_subtensor::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index ecee473bc..9b8f6ad34 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -21,7 +21,7 @@ pub struct DelegateInfo { total_daily_return: Compact, // Delegators current daily return } -impl Pallet { +impl Pallet { fn get_delegate_by_existing_account(delegate: AccountIdOf) -> DelegateInfo { let mut nominators = Vec::<(T::AccountId, Compact)>::new(); diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index bc5a9943c..ef6475053 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -22,7 +22,6 @@ use sp_runtime::{ use codec::MaxEncodedLen; use frame_support::pallet_prelude::TypeInfo; use frame_support::traits::VariantCount; -use pallet_collective::MemberCount; use pallet_registry::IdentityInfo; use pallet_subtensor::RegistryInterface; use sp_core::RuntimeDebug; diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index e533196b3..32ddb4b7a 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -2180,10 +2180,10 @@ fn test_hotkey_swap_fail_same_hotkey() { )); assert_noop!( - SubtensorModule::swap_hotkey( + SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(coldkey_account_id), - old_hotkey, - old_hotkey + &old_hotkey, + &old_hotkey ), Error::::NewHotKeyIsSameWithOld ); @@ -2213,10 +2213,10 @@ fn test_hotkey_swap_fail_not_enough_balance() { )); assert_err!( - SubtensorModule::swap_hotkey( + SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(coldkey_account_id), - old_hotkey, - new_hotkey + &old_hotkey, + &new_hotkey ), Error::::NotEnoughBalanceToPaySwapHotKey ); @@ -2254,10 +2254,10 @@ fn test_hotkey_swap_delegate_identity_updated() { identity_info.clone() )); - assert_ok!(SubtensorModule::swap_hotkey( + assert_ok!(SubtensorModule::do_swap_hotkey( <::RuntimeOrigin>::signed(coldkey_account_id), - old_hotkey, - new_hotkey + &old_hotkey, + &new_hotkey )); assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); From b7ebf96cc0ab219e3bbb3802a1938734eaf3864e Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:16:25 -0700 Subject: [PATCH 15/17] swap identity during hotkey swap --- pallets/subtensor/src/swap.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 8e4ca5cc9..f1535b929 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -89,6 +89,11 @@ impl Pallet { Self::swap_total_hotkey_coldkey_stakes_this_interval(old_hotkey, new_hotkey, &mut weight); + // Swap identity if the old hotkey has one. + if T::RegistryPallet::get_identity_of_delegate(old_hotkey).is_some() { + T::RegistryPallet::swap_delegate_identity_hotkey(old_hotkey, new_hotkey)?; + } + Self::set_last_tx_block(&coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); From 1f92907f795fe7bf2d60dc732bd8e7f4ba56e6ec Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:24:31 -0700 Subject: [PATCH 16/17] move tests --- pallets/subtensor/tests/registration.rs | 267 +-------------------- pallets/subtensor/tests/swap.rs | 306 +++++++++++++++++++++++- 2 files changed, 306 insertions(+), 267 deletions(-) diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 32ddb4b7a..bd95ae3b1 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -5,9 +5,8 @@ use frame_support::traits::Currency; use crate::mock::*; use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}; use frame_support::sp_runtime::{transaction_validity::InvalidTransaction, DispatchError}; -use frame_support::{assert_err, assert_noop, assert_ok, BoundedVec}; +use frame_support::{assert_err, assert_noop, assert_ok}; use frame_system::Config; -use pallet_registry::{Data, Error as RegistryError, IdentityInfo}; use pallet_subtensor::{AxonInfoOf, Error, SubtensorSignedExtension}; use sp_core::U256; use sp_runtime::traits::{DispatchInfoOf, SignedExtension}; @@ -2019,267 +2018,3 @@ fn test_registration_disabled() { // ); // }); // } - -#[test] -fn test_swap_delegate_identity_hotkey_successful() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - - let display = b"Old Display".to_vec(); - let old_identity_info = create_identity_info(display.clone()); - - // Set identity for the old hotkey - assert_ok!(Registry::set_identity_for_delegate( - &old_hotkey, - old_identity_info - )); - - // Swap the hotkey - assert_ok!(Registry::swap_delegate_identity_hotkey( - &old_hotkey, - &new_hotkey - )); - assert!(Registry::get_identity_of_delegate(&new_hotkey).is_some()); - assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); - - // Verify the identity information is correctly swapped - let identity_info = Registry::get_identity_of_delegate(&new_hotkey); - assert_eq!( - identity_info.unwrap().display, - Data::Raw(BoundedVec::try_from(display).unwrap()) - ); - }); -} - -#[test] -fn test_swap_delegate_identity_hotkey_new_hotkey_already_exists() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - - let old_display = b"Old Display".to_vec(); - let new_display = b"New Display".to_vec(); - - let old_identity_info = create_identity_info(old_display.clone()); - let new_identity_info = create_identity_info(new_display.clone()); - - // Add identity for old hotkey and new hotkey - assert_ok!(Registry::set_identity_for_delegate( - &old_hotkey, - old_identity_info - )); - assert_ok!(Registry::set_identity_for_delegate( - &new_hotkey, - new_identity_info - )); - - // Attempt to swap hotkey to one that is already in use - assert_err!( - Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), - RegistryError::::NewHotkeyInUse - ); - - // Verify both identities remain unchanged - let stored_old_identity = Registry::get_identity_of_delegate(&old_hotkey).unwrap(); - assert_eq!( - stored_old_identity.display, - Data::Raw(BoundedVec::try_from(old_display).unwrap()) - ); - - let stored_new_identity = Registry::get_identity_of_delegate(&new_hotkey).unwrap(); - assert_eq!( - stored_new_identity.display, - Data::Raw(BoundedVec::try_from(new_display).unwrap()) - ); - }); -} - -#[test] -fn test_swap_delegate_identity_hotkey_old_hotkey_does_not_exist() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - - // Ensure old hotkey does not exist - assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); - - assert_err!( - Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), - RegistryError::::OldHotkeyNotFound - ); - assert!(Registry::get_identity_of_delegate(&new_hotkey).is_none()); - }); -} - -#[test] -fn test_set_identity_for_delegate_success() { - new_test_ext(1).execute_with(|| { - let account = U256::from(1); - let identity_info = create_identity_info(b"Test Display".to_vec()); - - // Initially, the account should not have any identity set - assert!(Registry::get_identity_of_delegate(&account).is_none()); - - // Set identity for the account - assert_ok!(Registry::set_identity_for_delegate( - &account, - identity_info.clone() - )); - - // Verify the identity is set correctly - let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); - assert_eq!(stored_identity.display, identity_info.display); - }); -} - -#[test] -fn test_set_identity_for_delegate_identity_already_exists() { - new_test_ext(1).execute_with(|| { - let account = U256::from(1); - let identity_info = create_identity_info(b"Test Display".to_vec()); - - // Set identity for the account - assert_ok!(Registry::set_identity_for_delegate( - &account, - identity_info.clone() - )); - - // Attempt to set another identity for the same account - let new_identity_info = create_identity_info(b"New Display".to_vec()); - assert_err!( - Registry::set_identity_for_delegate(&account, new_identity_info), - RegistryError::::IdentityAlreadyExists - ); - - // Verify the original identity remains unchanged - let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); - assert_eq!(stored_identity.display, identity_info.display); - }); -} - -#[test] -fn test_hotkey_swap_fail_same_hotkey() { - new_test_ext(1).execute_with(|| { - let coldkey_account_id = U256::from(667); - let old_hotkey = U256::from(1); - - let netuid = 1; - let burn_cost = 10; - let tempo = 1; - - SubtensorModule::set_burn(netuid, burn_cost); - add_network(netuid, tempo, 0); - - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000u64); - - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - old_hotkey - )); - - assert_noop!( - SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey_account_id), - &old_hotkey, - &old_hotkey - ), - Error::::NewHotKeyIsSameWithOld - ); - }); -} - -#[test] -fn test_hotkey_swap_fail_not_enough_balance() { - new_test_ext(1).execute_with(|| { - let coldkey_account_id = U256::from(667); - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - - let netuid = 1; - let burn_cost = 10; - let tempo = 1; - - SubtensorModule::set_burn(netuid, burn_cost); - add_network(netuid, tempo, 0); - - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000u64); - - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - old_hotkey - )); - - assert_err!( - SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey_account_id), - &old_hotkey, - &new_hotkey - ), - Error::::NotEnoughBalanceToPaySwapHotKey - ); - }); -} - -#[test] -fn test_hotkey_swap_delegate_identity_updated() { - new_test_ext(1).execute_with(|| { - let coldkey_account_id = U256::from(667); - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - - let netuid = 1; - let burn_cost = 10; - let tempo = 1; - - SubtensorModule::set_burn(netuid, burn_cost); - add_network(netuid, tempo, 0); - - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000_000); - - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - old_hotkey - )); - - let display = b"The Display".to_vec(); - let identity_info: IdentityInfo = - create_identity_info(display.clone()); - - assert_ok!(Registry::set_identity_for_delegate( - &old_hotkey, - identity_info.clone() - )); - - assert_ok!(SubtensorModule::do_swap_hotkey( - <::RuntimeOrigin>::signed(coldkey_account_id), - &old_hotkey, - &new_hotkey - )); - - assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); - assert!(Registry::get_identity_of_delegate(&new_hotkey).is_some()); - assert_eq!( - Registry::get_identity_of_delegate(&new_hotkey).unwrap(), - identity_info - ); - }); -} - -fn create_identity_info(display: Vec) -> IdentityInfo { - let display_data = Data::Raw(BoundedVec::try_from(display).unwrap()); - IdentityInfo { - additional: Default::default(), - display: display_data, - legal: Default::default(), - web: Default::default(), - riot: Default::default(), - email: Default::default(), - pgp_fingerprint: None, - image: Default::default(), - twitter: Default::default(), - } -} diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 21c3a983a..f2e130925 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -2,12 +2,13 @@ use codec::Encode; use frame_support::weights::Weight; -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok, BoundedVec}; use frame_system::{Config, RawOrigin}; mod mock; use mock::*; use pallet_subtensor::*; use sp_core::U256; +use pallet_registry::{Data, Error as RegistryError, IdentityInfo}; #[test] fn test_do_swap_hotkey_ok() { @@ -1887,3 +1888,306 @@ fn test_coldkey_delegations() { assert_eq!(Stake::::get(delegate, coldkey), 0); }); } + + +#[test] +fn test_swap_delegate_identity_hotkey_successful() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let display = b"Old Display".to_vec(); + let old_identity_info = create_identity_info(display.clone()); + + // Set identity for the old hotkey + assert_ok!(Registry::set_identity_for_delegate( + &old_hotkey, + old_identity_info + )); + + // Swap the hotkey + assert_ok!(Registry::swap_delegate_identity_hotkey( + &old_hotkey, + &new_hotkey + )); + assert!(Registry::get_identity_of_delegate(&new_hotkey).is_some()); + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + + // Verify the identity information is correctly swapped + let identity_info = Registry::get_identity_of_delegate(&new_hotkey); + assert_eq!( + identity_info.unwrap().display, + Data::Raw(BoundedVec::try_from(display).unwrap()) + ); + }); +} + +#[test] +fn test_swap_delegate_identity_hotkey_new_hotkey_already_exists() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let old_display = b"Old Display".to_vec(); + let new_display = b"New Display".to_vec(); + + let old_identity_info = create_identity_info(old_display.clone()); + let new_identity_info = create_identity_info(new_display.clone()); + + // Add identity for old hotkey and new hotkey + assert_ok!(Registry::set_identity_for_delegate( + &old_hotkey, + old_identity_info + )); + assert_ok!(Registry::set_identity_for_delegate( + &new_hotkey, + new_identity_info + )); + + // Attempt to swap hotkey to one that is already in use + assert_err!( + Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), + RegistryError::::NewHotkeyInUse + ); + + // Verify both identities remain unchanged + let stored_old_identity = Registry::get_identity_of_delegate(&old_hotkey).unwrap(); + assert_eq!( + stored_old_identity.display, + Data::Raw(BoundedVec::try_from(old_display).unwrap()) + ); + + let stored_new_identity = Registry::get_identity_of_delegate(&new_hotkey).unwrap(); + assert_eq!( + stored_new_identity.display, + Data::Raw(BoundedVec::try_from(new_display).unwrap()) + ); + }); +} + +#[test] +fn test_swap_delegate_identity_hotkey_old_hotkey_does_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + // Ensure old hotkey does not exist + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + + assert_err!( + Registry::swap_delegate_identity_hotkey(&old_hotkey, &new_hotkey), + RegistryError::::OldHotkeyNotFound + ); + assert!(Registry::get_identity_of_delegate(&new_hotkey).is_none()); + }); +} + +#[test] +fn test_set_identity_for_delegate_success() { + new_test_ext(1).execute_with(|| { + let account = U256::from(1); + let identity_info = create_identity_info(b"Test Display".to_vec()); + + // Initially, the account should not have any identity set + assert!(Registry::get_identity_of_delegate(&account).is_none()); + + // Set identity for the account + assert_ok!(Registry::set_identity_for_delegate( + &account, + identity_info.clone() + )); + + // Verify the identity is set correctly + let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); + assert_eq!(stored_identity.display, identity_info.display); + }); +} + +#[test] +fn test_set_identity_for_delegate_identity_already_exists() { + new_test_ext(1).execute_with(|| { + let account = U256::from(1); + let identity_info = create_identity_info(b"Test Display".to_vec()); + + // Set identity for the account + assert_ok!(Registry::set_identity_for_delegate( + &account, + identity_info.clone() + )); + + // Attempt to set another identity for the same account + let new_identity_info = create_identity_info(b"New Display".to_vec()); + assert_err!( + Registry::set_identity_for_delegate(&account, new_identity_info), + RegistryError::::IdentityAlreadyExists + ); + + // Verify the original identity remains unchanged + let stored_identity = Registry::get_identity_of_delegate(&account).unwrap(); + assert_eq!(stored_identity.display, identity_info.display); + }); +} + +#[test] +fn test_hotkey_swap_fail_same_hotkey() { + new_test_ext(1).execute_with(|| { + let coldkey_account_id = U256::from(667); + let old_hotkey = U256::from(1); + + let netuid = 1; + let burn_cost = 10; + let tempo = 1; + + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000u64); + + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + old_hotkey + )); + + assert_noop!( + SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey_account_id), + &old_hotkey, + &old_hotkey + ), + Error::::NewHotKeyIsSameWithOld + ); + }); +} + +#[test] +fn test_hotkey_swap_fail_not_enough_balance() { + new_test_ext(1).execute_with(|| { + let coldkey_account_id = U256::from(667); + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let netuid = 1; + let burn_cost = 10; + let tempo = 1; + + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000u64); + + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + old_hotkey + )); + + assert_err!( + SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey_account_id), + &old_hotkey, + &new_hotkey + ), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + }); +} + +#[test] +fn test_hotkey_swap_delegate_identity_updated() { + new_test_ext(1).execute_with(|| { + let coldkey_account_id = U256::from(667); + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let netuid = 1; + let burn_cost = 10; + let tempo = 1; + + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000_000); + + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + old_hotkey + )); + + let display = b"The Display".to_vec(); + let identity_info: IdentityInfo = + create_identity_info(display.clone()); + + assert_ok!(Registry::set_identity_for_delegate( + &old_hotkey, + identity_info.clone() + )); + + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey_account_id), + &old_hotkey, + &new_hotkey + )); + + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + assert!(Registry::get_identity_of_delegate(&new_hotkey).is_some()); + assert_eq!( + Registry::get_identity_of_delegate(&new_hotkey).unwrap(), + identity_info + ); + }); +} + +#[test] +fn test_hotkey_swap_no_identity_no_changes() { + new_test_ext(1).execute_with(|| { + let coldkey_account_id = U256::from(667); + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + + let netuid = 1; + let burn_cost = 10; + let tempo = 1; + + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000_000); + + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + old_hotkey + )); + + // Ensure the old hotkey does not have an identity before the swap + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + + // Perform the hotkey swap + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey_account_id), + &old_hotkey, + &new_hotkey + )); + + // Ensure no identities have been changed + assert!(Registry::get_identity_of_delegate(&old_hotkey).is_none()); + assert!(Registry::get_identity_of_delegate(&new_hotkey).is_none()); + }); +} + +fn create_identity_info(display: Vec) -> IdentityInfo { + let display_data = Data::Raw(BoundedVec::try_from(display).unwrap()); + IdentityInfo { + additional: Default::default(), + display: display_data, + legal: Default::default(), + web: Default::default(), + riot: Default::default(), + email: Default::default(), + pgp_fingerprint: None, + image: Default::default(), + twitter: Default::default(), + } +} From b81dee32dbde996e2d37c900dc131c5353709af7 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:25:42 -0700 Subject: [PATCH 17/17] fmt --- pallets/subtensor/tests/swap.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index f2e130925..e92e7383e 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -6,9 +6,9 @@ use frame_support::{assert_err, assert_noop, assert_ok, BoundedVec}; use frame_system::{Config, RawOrigin}; mod mock; use mock::*; +use pallet_registry::{Data, Error as RegistryError, IdentityInfo}; use pallet_subtensor::*; use sp_core::U256; -use pallet_registry::{Data, Error as RegistryError, IdentityInfo}; #[test] fn test_do_swap_hotkey_ok() { @@ -1889,7 +1889,6 @@ fn test_coldkey_delegations() { }); } - #[test] fn test_swap_delegate_identity_hotkey_successful() { new_test_ext(1).execute_with(|| {