Novel Voting Mechanism - SPK Network Team Meeting
We're buttoning up the next iteration of the SPK Network. Before we get there, we're discussing our new voting mechanism and hoping to get your feedback. This meeting is approaching an hour long, and below is all the code referenced directly in the video... with some additional //comments.
exports.spk_vote = (json, from, active, pc) => { //the contract json:payload, from:@hiveaccount, active: active key used, pc:promise chain(for contract ordering)
var ops = [] //holds raw memory instructions
if (active) { //ensures active key
// memory reads
var powp = getPathNum(["spow", from]), // @from's powered spk
tpowp = getPathNum(["spow", "t"]), // the total powered spk
dpowp = getPathObj(["spowd", from]), // @from's downpower operations pointer
votebp = getPathObj(['spkVote', from]), // @from's last vote information
pstats = getPathNum(['stats']) // current network parameters
Promise.all([powp, tpowp, dpowp, votebp, pstats]).then((mem) => {
var stats = mem[4]
const DAOString = mem[3].substring(mem[3].indexOf(",")),
lastVote = Base64.toNumber(mem[3].split(",")[0])
? Base64.toNumber(mem[3].split(",")[0])
: json.block_num - parseInt(stats.spk_cycle_length),
thisVote =
Base64.fromNumber(json.block_num) + "," + (DAOString ? DAOString : ""), //decoding terse memory
ago = json.block_num - lastVote
total = mem[1],
power = mem[0]
downs = Object.keys(mem[2])
var effective_power = power, effective_total, aValidator = false
if(stats.validators?.[from]){ //determine if @from is a validator
aValidator = true
var powerVoted = 0
for (block of stats.power_voted){
powerVoted += stats.power_voted[block]
}
power = (total - powerVoted)/20 //or number of validators
}
if (!power){
ops.push({
type: "put",
path: ["feed", `${json.block_num}:${json.transaction_id}`],
data: `@${from}| Attempted SPK vote with no voting power`,
});
store.batch(ops, pc);
} else if(downs.length && !aValidator){
getPathObj(['chrono', downs[0]]).then(down =>{ // additional step to recover downpower information from pointer
finish(down)
})
} else {
finish()
}
function finish(down_obj) {
if(down_obj?.amount){
effective_power = power - down_obj.amount
}
if (ago < parseFloat(stats.spk_cycle_length))effective_power = parseInt(effective_power * (ago / stats.spk_cycle_length))
else if (ago > parseFloat(stats.spk_cycle_length) && ago < stats.spk_cycle_length * 2)effective_power = effective_power* parseInt(
effective_power *
(1 - ((ago - stats.spk_cycle_length) / stats.spk_cycle_length) / 2)
)
else if (ago >= stats.spk_cycle_length * 2)effective_power = parseInt(effective_power/2)
effective_total = effective_total - effective_power
const voteWeight = parseFloat(effective_power/effective_total).toFixed(8)
const decayWeight = parseFloat(
(effective_total - effective_power) / effective_total
).toFixed(8);
//verify inputs, adjust constants
if(json.spk_cycle_length < 28800)json.spk_cycle_length = 28800
if(json.spk_cycle_length > 3000000)json.spk_cycle_length = 3000000
if(json.dex_fee < 0)json.dex_fee = 0
if(json.dex_fee > 0.1)json.dex_fee = "0.1"
if(json.dex_max < 0)json.dex_max = 0
if(json.dex_max > 100)json.dex_max = 100
if(json.dex_slope < 0)json.dex_slope = 0
if(json.dex_slope > 100)json.dex_slope = 100
if(json.spk_rate_lpow < 0)json.spk_rate_lpow = 0
if(json.spk_rate_lpow > stats.spk_rate_ldel)json.spk_rate_lpow = stats.spk_rate_ldel
if(json.spk_rate_ldel > stats.spk_rate_lgov)json.spk_rate_lpow = stats.spk_rate_lgov
if(json.spk_rate_ldel < stats.spk_rate_lpow)json.spk_rate_ldel = stats.spk_rate_lpow
if(json.spk_rate_lgov > 0.1)json.spk_rate_lgov = "0.1"
if(json.spk_rate_lgov < stats.spk_rate_ldel)json.spk_rate_lpow = stats.spk_rate_ldel
if(json.max_coll_members > 100)json.max_coll_members = 100
if(json.max_coll_members < 15)json.max_coll_members = 15
json.max_coll_members = parseInt(json.max_coll_members)
//stats.item = (json.vote * voteWeight) + (decayWeight * stats.item)
stats.spk_cycle_length = (json.spk_cycle_length * voteWeight) + (decayWeight * parseFloat(stats.spk_cycle_length)) > 28800 ? parseFloat((json.spk_cycle_length * voteWeight) + (decayWeight * stats.spk_cycle_length).toFixed(6)) : 28800
stats.dex_fee = parseFloat((json.dex_fee * voteWeight) + (decayWeight * parseFloat(stats.dex_fee))).toFixed(6)
stats.dex_max = parseFloat((json.dex_max * voteWeight) + (decayWeight * parseFloat(stats.dex_max))).toFixed(2)
stats.dex_slope = parseFloat((json.dex_slope * voteWeight) + (decayWeight * parseFloat(stats.dex_slope))).toFixed(2)
stats.spk_rate_ldel = parseFloat((json.spk_rate_ldel * voteWeight) + (decayWeight * parseFloat(stats.spk_rate_ldel))).toFixed(6)
stats.spk_rate_lgov = parseFloat((json.spk_rate_lgov * voteWeight) + (decayWeight * parseFloat(stats.spk_rate_lgov))).toFixed(6)
stats.spk_rate_lpow = parseFloat((json.spk_rate_lpow * voteWeight) + (decayWeight * parseFloat(stats.spk_rate_lpow))).toFixed(6)
stats.max_coll_members = (json.max_coll_members * voteWeight) + (decayWeight * parseFloat(stats.max_coll_members)) < 25 ? 25 : ((json.max_coll_members * voteWeight) + (decayWeight * stats.max_coll_members) > 79 ? 79 : parseFloat((json.max_coll_members * voteWeight) + (decayWeight * stats.max_coll_members)).toFixed(6))
//useful-votes-calc
if(!aValidator)stats.power_voted[stats.lastIBlock] = effective_power + (typeof stats.power_voted[stats.lastIBlock] == "number" ? stats.power_voted[stats.lastIBlock] : 0)
ops.push({
type: "put",
path: ["stats"],
data: stats,
});
ops.push({
type: "put",
path: ["spkVote", from],
data: thisVote,
});
ops.push({
type: "put",
path: ["feed", `${json.block_num}:${json.transaction_id}`],
data: `@${from}| Has updated their votes.`,
});
store.batch(ops, pc);
}
});
} else {
ops.push({
type: "put",
path: ["feed", `${json.block_num}:${json.transaction_id}`],
data: `@${from}| Attempted SPK vote with posting key`,
});
store.batch(ops, pc);
}
}
Thank you for participating in our development process and participating in these early stages.
Vote for our Witness:
About the SPK Network:
The SPK Network is a decentralized Web 3.0 protocol that rewards value creators and infrastructure providers appropriately and autonomously by distributing reward tokens so that every user, creator, and platform, will be able to earn rewards on a level playing field.
Check out the SPK Network Light Paper: https://peakd.com/hive/@spknetwork/spk-network-light-paper
Our Website: https://spk.network/
Telegram Group: https://t.me/spknetwork
Discord Server: https://discord.gg/JbhQ7dREsP
SPK Network Linktree: https://linktr.ee/spknetwork
▶️ 3Speak
https://twitter.com/1161694792604164097/status/1623339969803694080
https://twitter.com/1533652315152044033/status/1623341014453714946
The rewards earned on this comment will go directly to the people( @yeckingo1 ) sharing the post on Twitter as long as they are registered with @poshtoken. Sign up at https://hiveposh.com.
Congratulations @spknetwork! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)
Your next target is to reach 50 posts.
You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP
To support your work, I also upvoted your post!
Check out our last posts:
Support the HiveBuzz project. Vote for our proposal!
TLDR: The code may be fine but the voting rulebook is demonstrably flawed.
At 12:30, the speaker (disregardfiat?) shows the variable voting is apparently done by [stake-weighted] averaging (a voter with 1% stake changes 200k to 1M and the result moves up 8k) and explains "no big fluctuations" as the advantage of this system, apparently compared to (stake-weighted) median. (a system that I understand to be used on Hive to decide consensus witnesses' vote for HBD Savings APR).
While that may be true, the method only (somewhat) works as long as the voters stay naive (=ignorant of the rules and their practical consequences) and enter their preferred value as their vote.
Let's say all other voters want instant powerdown so 99% of the stake is voting for 0 on that variable. End result: 10k (blocks). In my book, that's a failure (I want the ruleset to declare the result as 0).
Am I allowed to "correct" and vote a negative number? (minus 1M if I have 1% stake in this particular case)
In practice someone has to set an upper and lower bound to valid votes. Often an arbitrary one. Although at times there are natural boundaries that work out poor - such as the zero lower bound here - those may favour one side (the long powerdown camp in this example).
Do we vote on the bounds first? Do we settle the vote with averages?
Wait, why is that? Well, most voters should vote for the minimum/maximum allowed unless they either (1) possess a large stake or (2) are lucky to have the current result close enough their optimal value. If you are this rare voter, you can calculate a value to get your dream result but you need to follow any changes and recalculate when a vote is changed. Total mess.
There is a correct way. Keep using median. The way to deal with rapid changes is to look at the current value in addition to the vote result and mildly push the new value in the direction of the result of the vote. Think of an ELO rating changing after a game - towards the 1-game performance rating but no overreactions.
You're mostly right here, but at the end of the day I don't think it matters. Staking didn't stop the Sun takeover, and median values are exceptionally unlikely to be ideal values. The moving average here is done to give the most number of people the ability to vote, as a system that calculates median values would need to store and calculate all accounts votes at every vote, which won't scale. What seems like a median on Hive really is the median of 20 accounts who have a few key votes, a barely decentralized plutocracy.
The number of people who have left Hive is just shy of all them. Let's not stretch our imagination too much and think 90% of accounts hold 20% of the stake. On Hive there is nothing they could do even together to get a single witness voted from outside the top. At least with this system they could exercise 20% of the vote toward governance. The top 20 in this paradigm are the people who vote for all the apathetic accounts... which would have prevented the Sun takeover. It also disallows the biggest accounts from exercising more than 5%(hopefully closer to 2.5% with 50% apathy) votes as well, which addresses the last point: Any single vote won't effect a variable more than 5% in the arbitrary range.
The code does have vote range limits, so a negative vote will just be counted as a minimum. At this stage at least most of the range limits are fairly natural. Interest rates can't be negative, key holders are limited by Hive code, power-down voting range is something like 1 to 100 days... (which translates to 4 to 400 days for a full powerdown). The flip side is the 13 week power down on Hive is almost kinda voted on when there is a hardfork... but as much as people want it to drop in line with the rest of the market, there isn't even a path to do so.
To sum
Pros:
Cons:
I appreciate your response but I am going to mindfully ignore the most of it as it deals with voting the consensus witnesses and we might as well join/bump the discussion in Dan's post for that. I am sticking to variable voting here.
I am going to quote my premises. As someone who cannot read the code, I can be easily misguided there so anyone is welcome to point out any misconceptions I have.
Even when the number of validators goes through the roof, it is still like hundreds or thousands, not millions (of all token holders).
Even if you want to avoid using all witnesses' input, it is probably easy to pick up Top 50 or 100 instead of Top 20 (the further you go, the more important is to weight).
If storage were a problem, imagine a system that only allows you to vote for (1) increase the current value OR (2) decrease the current value (plus an option to stop voting and abstain if the value is right). That's equivalent for all rational voters and you can have 3rd party tools that voters enter their dream value in and have it monitor the results to see if a change of vote is needed.
Recalculating under such system is easy. It seems to me that at least under the non-weighted system the median can be recalculated in a similar fashion. The old vote was either UNDER the old resulting value or OVER. If the new vote stayed the same, result stands. If it changes camps, you lookup the new result as the neighbouring vote value (probably not cool for weighted votes if that means recaluclation a few million "vests" the changed vote represents).
BTW, if you still prefer averaging over medians, you can at least save some space by storing vote values as one of (min, max, something_wierd_pls_look_it_up_over_here) if it is validators voting (as opposed to general public voting naively).
This is actually not subject to the prove-me-wrong request. It is a personal political view. If you change my 99% of zero, 1% of 1M example to 80-20, different people will have substantially diferent legitimate opinions on what the result should be. What a challenge!
While I am not trying to change anyone else's view, I think it is useful to know what the spirit of the SPK Network is. If negating stake-weighting is as basic part of the project as negating DVs is for Blurt, I want to know (foot voting is legit and not necessarily an all-or-nothing dilemma on blockchain as compared to IRL). FTR, I have never noticed other core personalities positioning themselves where you seem to.
People do not leave Hive as a consequence of losing an election and therefore having no say on DEX fee size. If it was like that, their "20% say on governance" would not help at all. That can prevent extreme values being voted in. Unfortunately, "exercising your 20% vote towards governance" can totally override the other 80% at times (using the bounds you call "fairly natural"). It does not sound a well-thought concept to me. I could write a full post to illustrate but I do not see any audience ITT.
Anyway, on Hive, dissent leaves because the winners can execute a financial penalty on them for voting wrong.
Again, lots of great points. So I'm going to respond to your premise's here to get a little closer to a consensus.
This isn't true. We are trying to build a system where everybody CAN exercise their stake. Hive stake is exercised through delegates and this simplifies many of the problems of scaling. 20 accounts or 20 million accounts will only ever have 20 recent witnesses to average votes across. This also means that @ blocktrades with millions of hive power and @ guiltyparties with only couple thousand have an equal vote in the governance.
In the proposed system we still have this max influence built in by having the top 20 (who are also responsible for other things) vote with 1/20th of the apathetic stake... and not their own. This bicameral scheme should limit many of the attacks for pushing a variables one way or another.
This is a relatively arbitrary number of validators. As the content storage network scales, it is likely that we can have the number of validators scale in a votable range as well. 20 to a max of something limited by a number of highly scored accounts... this is a first step and this future consideration has also been discussed.
What is stored in this paradigm above is the time of your last vote. Nothing else. This is 5 bytes per account. And this number goes into the weighting calculation to prevent a vote from driving averages thru multiple immediate votes. So the memory required here is a global current variable, a global total stake weight, the accounts stake, and a last time vote per account. The calculation will always be a few cycles per vote; scaling at O(1), while space scales at N.
I almost completely agree here. However, there is a minimum decentralization that we are trying to achieve. What happens when the account that holds 20.1 buys 30 more. This is actually an attack of any decentralized system. This paradigm allows the 20% to exercise their vote... at full weight; Which is more decentralized than the current paradigm. Unfortunately you can Sybil accounts to overcome any limitation we place here, perfection isn't achievable and any system is nothing more than a hopeful compromise. But if anyone is hard set on 1 token 1 vote, the stock market and traditional finance might be your thing.
OK, now I have caught up on the introductory post that I missed. Thanks for your patience with me.
As a fan of multicameralism (I happened to bitch about it on dCity Discord just last week), I have some issues with calling the scheme bicameral. It is an effort to fit a two-dimensional space in a single dimension which is always shaky. It is cool when asset A governs B, B governs C and Z governs A. Here we fit A voting on X and B voting on X into a single number. The weighting used looks interesting although I still need some time to digest if it has some hidden strengths.
The sweet part is I finally understood why staked LARYNX earns more SPK for validators than non-validators. OTOH, I am still missing a part of the picture as I understand we are talking SPK Power based voting here (not LARYNX Power based) so there is still an incentive to concentrate LARYNX on validator's accounts and power up the mined SPK to a non-validator alt as much as possible.
Before I start quoting myself straight from my head again, I want to share a marginal position of mine:
That account can make everyone's life miserable until they move out. I am OK with that and I am going to try and sell my assets to them while they are worth more than zero. I'll leave a note on my way out and I hope you do as well, I want to follow you to the next project.
Not with the laws protecting everyone from the ugly 51% sharks.
So my current recap of the development:
I have already criticised the average thing. I might elaborate if needed.
I applaud that step.
I just keep in mind that approximating a flawed system often leads to a flawed system (but you can get lucky).
I disapprove but I can change my mind if anyone fills in the gap to explain properly.
My counterproposals to refrain from confusing people (I myself fell for the trap despite paying more attention than average user):
3A: Keep the current implementation of the system but add a Voting Advisor.
Taking the example from the video (Voter has 1% stake, current value 200k):
Voter A (enters 208k)
Voting Advisor: Hello, thank you for voting for the SPK Powerdown variable.
Given your current voting power, you can adjust the value to 208,000 if you cast your vote as: 1,000,000
If you cast your vote as 208,000 the resulting value is going to be 200,080.
Please confirm your choice pressing one of the following buttons.
Voter B (enters 1M)
Voting Advisor: Hello, thank you for voting for the SPK Powerdown variable.
Given your current voting power, you would need to vote for 80,200,000 to adjust the value to 1,000,000. The maximum allowed vote value is ___ which would adjust the value to ___.
If you cast your vote as 1,000,000 the resulting value is going to be 208,000.
Please confirm your choice pressing one of the following buttons.
3B: Redesign the system
Look at the Voter C standing at the machine. Compute how much power Voter C has to see how far they can move the value if they vote now. Give them ArrowUp button (add 14,251 resulting in 214,251), ArrowDown button (substract 14,251 resulting in 185,749), Check button (keep 200,000 but cast vote to prevent going apathetic) and Edit button (if they want a specific value in the 185,749-214,251 range, they can type it in).
I obviously prefer 3B and I could go on with technicals on how much power Voter C actually has (I like to approach it from the Voting mana viewpoint) but I assume thats academic until we go over consequences such as "If majority wants to set Variable X at Y value, there is nothing the 20% minority can do about it."
Clarification: under the current system, majority can force a non-extreme value but if they try and set a value close to one of the bounds, minority can veto it - 3B allows majority to force any value including the min/maxvalue if they wish
Clarification of the clarification: the current system is toast because boring mainstream values can get treated as extreme. 3B can be tweaked so that a vote towards boundary shits fewer points than a vote towards centre but that approach runs to the limited version of the same issue. (could be lesser evil in practice)
Nice. I think we're all pretty close in understanding. We will absolutely have some user interface that tried to help people understand their votes, and given that it's decentralized there may be all 3 and even more ways to interact with the system.
There may be a reason to spread SPK over alt accounts if you own more than the 1/20 limit, but we're hoping that's less of a problem going forward. Considering we started from an airdrop, Larynx earns SPK when it's used toward the community goals, while we still have plans to devalue anything held to approximate inflows to traditional mining and keep some skin in the game when there are so many ways to betray the system with non-action and illegal content. We are actively hoping for "lesser evil in practice." We already know we can't trust some people, how do we make sure the people we can keep that some in check... Having governance tokens being earned thru services seems like a decent enough way to encourage the good behaviors in even in non-governance.
Really appreciate your input! Feel free to challenge us any time.
Challenge accepted!
Before I write the full post, let me ask a few quick questions:
Does that include 3A and 3B? 3A is fine. 3B is not. That's not a different way to interact, that's a code change propostion.
1/20 limit of what? Apathy votes? Total votes? Validator votes?
I might misunderstand voting with apathy - it sounded as if validators never vote with their own SPK Power. But even if they vote with max(their own SPK power; assigned apathy vote) it is stll better to have all power somewhere else.
Natural lower bound is zero. Natural upper bound is 1 (translating to 100%). Upper bound is dumb in practice (actually not only dumb, it's demonstrably malicious) but still natural in the sense of the process of picking the value. What is the curently implemented upper bound and what makes it natural if it is not 1?
I do not think there is a natural upper bound value. What is the implemented upper bound?
Ah, I see what you mean now in step 3. I also agree an upper bound isn't necessary for for many things... but if you let people vote for wildish values, as you know, they can effect things up much faster than they can effect them down. To that end I'll rewrite some code to allow changes up to a certain value...
This will likely be 10%... so if the current fee is .005 then you could vote for 0.00495 or 0.00505. Surely something like this would keep values more constant and ensure greater than changes take longer than the power down period.
1/20th of of apathy votes. As mentioned it wouldn't prevent somebody from exercising a huge stake, but ethos would be there... that nobody could vote themselves more than a community elected person.
I think the 10% (or some other arbitrary value) would generally limit dex fees from approaching 1, as well as the power down interval from growing to quickly. 1 day seems like a fine place to draw the lower line.. but even a year is a silly upper limit when 30 year bonds are a thing.
No, my point is actually kinda opposite - I am going to demonstrate that even the most reasonable upper bound still carries the imbalance you described.
That is an invitation to split a large stake between multiple accounts. More of a request, actually.
Cool. Now I can formulate my actual question. Do validators always vote with 1/20 of apathy votes regardless of their SPK Power?
I totally agree. This particular variable looks tough to vote on. Logarithmic scale perhaps?
Yes, those voted into the top would always vote with the same weight regardless of their stake. The calculation as written would effectively make the "apathetic" stake the total of the non-votes and the cumulative stake of those also elected.
OK.
Why would any validator power up SPK on their account rather than alt?
Why did you say powering up on alt can be beneficial for someone owning more than 1/20 of apathetic stake?
The account will earn Broca for it's powered SPK. So for instance spknetwork will want to consolidate their stake to enable running their services. This accumulation should make people want to vote for them as a validator. If you must exercise a >5% stake powering it over 2 accounts would allow you to vote with a bigger stake, but most people would be wondering why an account like @ ranchorelaxo votes identically to haejin; possibly enough to not be voted as a validator... but not like it would matter, you can still exercise your stake with the extra step.
That's not what I am confused about - I am asking why you differentiate the under 1/20 scenario from the over 1/20 one.
Say there is 1M apathy tokens and Alice controls @ alice.main validator and @ alice.alt non-validator.
If Alice owns 10k tokens (below 1/20), powered up on @ alice.main, she votes with 20k (main) + 0 (alt). Had she powered up on @ alice.alt, she would vote with 20k (main) + 10k (alt).
Obviously, dead zero SPK Power on validator account looks weird, so that's why I added "as much as possible" disclaimer.
(I understand that validators and non-validators earn BROCA at the same rate).
The Broca market is a little weird. It's like food assistance where you get them but you have to use on certain goods. They can't just be redeemed for Hive/SPK/HBD/etc... Of course people will sell them and they should have some fungible uses; @ spknetwork for instance will place their Broca in contracts for their users to have free access to their platform... but for precisely this reason I'm hoping not to build direct Broca sales... but continue to utilize service contracts to transform Broca into tokens that pay for the service providers.
This does get into some roles of the validators. Say @ alice.alt has her 10K SPK powered, and builds self directed contracts to upload and store some data. @ alice.alt is providing additional services like upload and storage. If she fails to perform services for the wider market and is only interesting in cleaning broca her accounts reputation will go down, and her pass thru rate will suffer.
Alternatively, if she has an elected validator she'll be more capable of earning with her powered SPK as the good standing she has will carry over to other services she provides.
It's a hard problem and we're here hoping to plug these holes to the best of our collective ability and hearing these questions has already changed some of the code for the better. In short, aligning incentives should help everybody build this network together... Voting and reputation are tied a bit together and the validators will earn more ready-to-redeem broca through validating the contracts that are assigned to them... this will have a SPK weight to it as well.
All good, I like the sentiment. I felt I was missing something but it turns out I probably wasn't so there s no need to dig into one loose statement any longer. TBH, I do not even think this is a hole, just a nuisance. I am not sure if there is any point to motivate validators to exhibit collecting non-voting SPK Power but I do not really care because I can see the setup allows the water to find its natural way eventually.
FTR, I am fine with Alice. When she picked the name for her @ alice.alt account, she demonstrated that she is going to run the business honestly and openly. She only follows a practice that the code dictates. I will gladly unvote anyone trying to collect votes by criticising her.
is really hard to follow, sound is not that clear :)