The idea of this pallet is to be a part of a larger system with the objective of coordinating commands to a decentralized infrastructure running Large Language Models (LLMs) training and inference.
AI models have grown quite large in their computing and memory requirements, and for both the samll business and individual it has increasingly become impossible to experiment with them in any practical manner. Paying for a cloud instance is indeed possible, but comes at a high cost for an individual who may be using it for a fraction of the time and computing power payed.
It is beneficial for them that they pool their resources to a single instance which can be managed them and used proportionally to the invested capital used to pay computing power. In this context, it is likely that web 3 can help solving this coordination issue.
In the idea proposed by this pallet, a creator of a computing instance (here called community) would make the off-chain preparations for it and register said community in this pallet. In a bootstrapping period, N amount of members can join this community freely. It is expected that this part relies heavily on the individuals making preparations off chain. The key detail is that this instance must ONLY listen to events of the chain and interact with it, but not be accessible via "regular" means. This off-chain on-chain technology is key to the correct viability of the proposed idea.
Once the specified amount of bootstrapping members N have joined on-chain to the community, it will only accept new members that are whitelisted also in this pallet. We can call this whitelist threshold W. This will be also defined upon instanciation of the community.
The idea behind this is that when the community grows larger and more powerfull (in terms of controlling computing power), there exists the necessity to filter individuals that want to make several accounts and control the system. It is expected that it is in the best interest of the initiators to filter out this type of individuals in place of known persons (friends, fellow academics, co-workers, verified online persona, etc). Once inside the community and filtered, it is also in the interest of the newly entered members to do the same and not jeopardize the community, assuming they were properly selected as "good" players.
Once the community is up and running, members can use the voting system to propose and vote on the commands that the instance should run. This can come in the form of binary (yes or no) propolsas where commands are encoded as bytes. When 50 percent + 1 of the members have voted yes to a proposal and it is closed, the chain will emit an event about the result with the metadata. This will be fetched, parsed and run by the computing instance, therefore meeting the requirements of a decentrilized computing instance controlled by this DAO.
The native token in the chain represents in this case computing power access and voting rights, and members of the community may obtain it by providing the economic asset used to pay for the computing instance off-chain. This part of the system is intended to be handled by another pallet (or several), and requires the reception of some common, well known token (like DOT) that can be used to pay for the instance. Already some cloud providers provide the possibilty to pay this way. Key on-chain pieces are a treasury that manages the payment of the instance and tracks how much a person has provided, and returns tokens that represent a proportional of this amount.
Users are incentivized to pay for the instance so they can use it more, in a linear fashion. The more one contributes to pay the costs of the instance, the more access rights one have to query the services of the instance. Nevertheless, this pallet implements quadratic voting to "steer" the model's training, and eventual shutdown or modification.
The thinking behind this comes from another problem we see with the current landscape of AI, in which more economic power can leave individuals completely out of the decision of how this models are trained and with what data. It is a superlinear relation between economic means and decision, which is contrary to what we should expect for a technology so influential.
In this simple implementation, users can propose several voting proposals (commands) at the same time, yet the economic costs of a certain amount of votes is squared.
Also, the native token balances of users is frozen throughout the pallet, so that users with large amount of tokens have to choose on which proposals to use their balance. If not, it is likely that whales in the system will spam it with proposals where they put little but not neglible amounts.
Nevertheless, once users pay for one instance they will recieve tokens that allow for use in any instance (community) in the pallet.
For this proof of concept, it is assumed that the native token freeze is only used for this pallet, therefore the setting of the freeze is absolute with respect to the FreezeId. As mentioned before, inside the pallet, the voting power cost is counted and stacks up. For example, if the user starts with 100 native tokens and votes on proposal 1 with 3 votes (9 tokens frozen) and for proposal 2 with 6 votes (36 tokens frozen), the user will have only 55 tokens remaining to pay for any other proposals.
If in the future some other pallet in the runtime were to use the freezable trait, it would be required to properly set up the FreezeId in the configuration, or handle differently the balances in the voting pallet.
The following is a list of extrinsicts a user can call to interact with this pallet, and a brief description. This will also shed some light into the inner workins of the logic of the pallet.
-
- Insert Community: This allows to insert a community in the first place, with corresponding id, Bootstrapping limit (limit of memebers in which below it people can join freely), and Whitelist Minimum (threshold required for an interested party to enter the community).
-
- Join Community: as mentioned above, if the bootstrapping limit has not yet been met, the person can enter freely. After that limit, the person requires an amount of votes in favor of that account to get in. This "whitelist" vote can be done in extrinsic number 8.
-
- Push Proposal: Any member can push a proposal with associated metadata (the command to be run), as long as max number of proposals has not been reached. Proposals can be voted immediatly, but can only be closed after some block number X has passed, after which they can be closed and voting and other modifications are forbidden. A proposal can only be pushed once the community exists the bootstrapping state (when reaches > number of users than that limit)
-
- Vote: User this extrinsic, users can vote yes, no for a given proposal, which some voting power where it's cost in native balance is voting_power^2. By cost is meant freeze of native token until either the close of the voting, or a retraction of the user. Important to remind that although freeze can be overlapped along this pallet, for this pallet this amount stacks on each proposal vote, to avoid big players having too much power into many proposals which would defeat partially the quadratic voting scheme.
-
- Modify Vote: This extrinsic is a conviniance for the user. It can modify either putting more or less voting power, by providing more tokens to be frozen or unfreezeng some, respectively. Users cannot modify vote to 0.
-
- Close Proposal: This extrinsic can be called by anyone. It emmits an event with the result and deletes from storage some elements. It is important to note again that for the Yes to pass, 50% + 1 votes are needed, if in stale-mate, no wins.
-
- Retract Vote: Allows the user to undo the voting if before block deadline.
-
- Unfreeze: to avoid iterations in the runtime, each user needs to call this extrinsic to unfreeze it's native tokens, by providing the community id and proposal id. It goes without saying that the voting must be closed before.
-
- Whitelist Account: allows a member of a community to provide an ok vote to a interested party trying to enter said community. The ammount of whitelist votes required is defined upon creation of community.
-
- Deregister: Allows a user to exit a community, only if he is not in any non-closed voting session.
Root extrinsics. Mainly for testing and interface compliance.
-
- Start proposing: changes the state of the community to allow proposals, without regards of the amount of members and bootstrapping limit.
-
- Force member into community: Inserts a member into a community without taking into account whitelisting limits and votes.
-
- Force close: Forces a close of a proposal without taking into account the block number.
As explained in the main section above, this system assumes that there exists an instance of infrastructure running which ONLY listens to events emited by this pallet. This in itself it is challenging and would require either a third trusted party to run the instance or an instance that starts running normally on the cloud, lifts up a node and then programmatically cuts its connections to the outside except for the node. This is a key piece required for the idea to even considered be a reality.
Another piece that is left untoched is the "treasury" part, in charge of funding the computing instance on chain, and managing the native token to the community users.
As well as the decentralize infrastructure, more time has to be taken into consideration for the tokenomics. How exactly do users obtain and spend their tokens for compute power, and how this is enacted in a decentralized manner.
Some optimizations in storage could easily be done when accessing voting power used. If it is 0, this could just be set to None and handle that logic. Due to lack of time this optimization could not be programmed.
Finally, only 5 extrinsics were benchmarked again due to time constraints. A more comprehensive benchmark is needed to deploy into production.
Allowing users to buy computing power and use it throughout all the instances, can transform as sytem like this into a marketplace, where communities in charge of each AI model can charge an extra fee for "outsiders" to utilize it. This may or may not be a feature that people want, so it would be wise to leave it as an optional set of parameters in the future.
To test while developing, without a full build (thus reduce time to results):
cargo t -p pallet-voting
To test with benchmarking test included:
cargo test -p pallet-voting --features runtime-benchmarks
Build the node without launching it, with release
optimizations:
cargo build --release
Build and launch the node, with release
optimizations:
cargo r -r -- --dev
First we need to compile with benchmarks feature activated:
cargo build --release --features runtime-benchmarks
Then we can run the following command to perform benchmarks:
cargo run --release --features=runtime-benchmarks \
benchmark \
pallet \
--steps=50 \
--repeat=20 \
--pallet=pallet_voting \
--extrinsic="*" \
--wasm-execution=compiled \
--heap-pages=4096 \
--output=./pallets/voting/src/weights.rs