Embedded Governance Design

Following up from: #10: A Short-Term Roadmap

This thread will be used to facilitate the open and incentivized planning and design phase to enable the community to do things such as use pillar votes to create/activate sporks and take over admin functions for the bridge and liquidity embedded contracts. I hope to timebox this for 2 weeks ending July 4th.

I welcome all to participate: developers and non-developers. I have created an AZ proposal to ask the pillars to set aside 5k ZNN, 50k QSR for this planning and design phase. I need to work out the specifics, but at the end of the timebox, I will ask the pillars to assign votes to contributors so that we can fairly distribute those funds.

I don’t want to dominate the discussion and want to allow others to make a contribution first, so I will wait until tomorrow before I start posting my thoughts.

Please refrain from adding comments of support or disagreement that do not further the conversation. I will likely moderate these out. For example, “Great idea!”. If there is an approach you like, the best way to show support is to further develop the conversation in that direction.

5 Likes

I’m debating with myself whether or not to facilitate this initial process trial run for free or not.
I will let the community decide.
If the process is successful I will ask for 10% of the earmarked funds.
500 ZNN, 5000 QSR.

Regardless of the vote however, I will see this through.

1 Like

Thanks for kicking off this topic, George. Here are some of my thoughts.


What is the governance model trying to achieve?

  • The ability to manage runtime variables and call embedded functions as the administrator
  • This includes creating and activating sporks, and executing functions related to the bridge and liquidity contracts

Scope of change

  • go-zenon – write/test the governance embedded contract
  • go-zenon
    – update all variables that we wish to define dynamically
    – consider variables that are defined by a combination of other variables → may need to simplify
  • SDKs – update all the same variables to dynamically source values from contract’s db
  • clients – update any remaining variable references the same way as the SDKs
  • clients – ability to interact with the governance contract
    – Syrius implementation will be different from znn-cli

Governance contract interface

  • Functions
    createPoll()
    endPoll()
    getPolls()
    getVariable()
    updateVariable() – includes creating/deleting variables
    executeFunction(function, params, execution height)

  • Variables
    variableDb
    pollDb
    pollFee
    pollOptions
    pollDuration
    pollQuorum

Incentives
Since we’re discussing the implementation for a new voting system, I propose that we consider updating participant incentives.
I’ve written a post about this, but it didn’t garner much attention.
I’ll summarize the arguments here:

  • Poll spammers should be penalized
  • Pillars should be rewarded for casting votes
  • Valid poll submissions should not incur penalties

We can achieve these objectives with the following policy adjustments:

  1. Poll initiators must lock pollFee ZNN in the contract
  2. Spam polls meet the following criteria:
    • if spamVotes > sum(yes, no, abstain) after pollDuration or if spamVotes == pollQuorum
      • donate locked ZNN to AZ
      • delete the poll from pollDb
  3. All other poll outcomes are valid —> refund the initiator when the poll completes

Pillar yields or some other reward can be subject to a voting participation multiplier, but I think this point should be reserved for a separate discussion.
Pillars will already be incentivized to vote if they want changes applied to mainnet.

Execution Flow

A user will submit a poll to the governance contract

  • They will enter a json payload that the contract executes if the poll is accepted
  • The poll costs pollFee to submit, locking the funds for pollDuration
  • The poll ends after pollDuration

Pillars will submit their votes.

  • Options for the poll will include: Yes, No, Abstain, Spam
  • They may re-cast their votes while the poll is still active.

After pollDuration, the poll will finish.

  • If pollQuorum is met and yesVotes > sum(no, abstain, spam) → execute the json payload
Example of a json payload for a poll
{
  "<poll-id>": {
    "variables": [
      {
        "pollDuration": "604800",
        "activationHeight": "4321000"
      },
      {
        "pollFee": "30000000",
        "activationHeight": "4321000"
      },
      {
        "bridgeAdministrator": "z1qxemdeddedxg0vernancexxxxxxxxxxxklyh23",
        "activationHeight": "4321000"
      },
      {
        "liquidityAdministrator": false,
        "activationHeight": "4321000"
      }
    ],
    "functions": [
      {
        "function": "embedded.spork.CreateSpork",
        "parameters": [
          "<spork name>",
          "<spork description>"
        ],
        "executionHeight": "4200040"
      },
      {
        "function": "embedded.spork.ActivateSpork",
        "parameters": [
          "<spork id>"
        ],
        "executionHeight": "4321000"
      }
    ]
  }
}

In this example, we would be:

  • updating four runtime variables – three value changes and one deletion
  • creating a spork and activating it two weeks later
    Note: realistically, we may want two separate votes for spork creation and activation.

Limitations

  • Only predefined functions in the governance contract can be executed.
    A spork would be required to change these.
    This is because I don’t see a way to define a variable with another variable.
    • The challenge I faced here:
      instead of passing abstracted function names and params, can we pass the parameters to build AccountBlocks directly in the poll?
    • Seems like we also need to pass the ABI for the specific method we’re calling.
      Perhaps we can rely on clients to pre-format these data values?
    • I can’t dynamically define these function -> ABI method associations so they will need to be manually configured in the contract.

Other considerations

  • We’ll need to sanitize the json payload input to ensure only valid characters are passed to the rest of the system.

PS: I think 5k/50k is expensive for any discussion/planning phase.

Thanks for being the first to contribute!
I am still holding off until tomorrow to begin sharing my ideas.

So I guess I will first ask for leniency given that this is a trial run of the process.
I want to make sure that there are enough incentives to go around for anyone who has a good or interesting idea to share.

As mentioned in my ZenonZealot post, in the future we’ll need some way to determine what the appropriate amount to earmark for planning/design should be. Of course, it should be variable based on how important the work is. Since these funds are not earmarked for me, but will be subject to pillar vote, even if we are possibly overpaying for this trial, I don’t think it will be towards anyone in particular. I’m optimistic about participation.

Next, I will directly challenge the idea that it won’t ever be worth that amount. A thorough design phase goes a long way in ensuring that we get the best price for implementation, and in better timeframes.

At least from personal experience, a lot of my hesitation when it comes to development, comes from a fear that I’ll have to scrap it later on. Removing this hesitation gets us faster deliveries.

And without a open process, there is incentive/pressure to “claim” work by producing some semblance of code for it. In that situation, I highly doubt that the design will be what is best for the community. In some cases, the cost of correcting or improving the design in the future, will far outweigh any investment into upfront open and collaborative design.

There are likely also many contributors, especially newer or potential community members, who can’t do the end-to-end delivery, but who can deliver a well defined piece of work. A good planning/design phase opens up the door to much greater competition.

I can envision scenarios where work that a single team would ask for 2 or more AZ proposals to cover could instead first undergo a proposal for open design and then end up with a competitive set of implementation proposals that overall saves us money.

On a longer horizon, as code generation/AI assisted development becomes more mature, the line between design and implementation will blur. In the future, design will be the brunt of the work.

After this first trial run, I think it will be a good idea to open up a discussion on how to determine the right amount to set aside for planning/design.

1 Like

I am grateful for the thoughtful and insightful discussions taking place and the services provided by the hc1 crew. I would like to contribute some of my thoughts, which, while not groundbreaking and probably already accounted for, have not been mentioned yet:

  1. Transparency and Accountability: It’s crucial that our governance model is both transparent and accountable. To ensure this, I am sure to be just echoing our intent to:
  • Maintain a comprehensive log of all changes enacted through the governance contract.
  • Make these logs easily accessible to all members of our community, enabling any member to review past decisions and understand the rationale behind them.
  1. Delay Period: We should consider implementing a delay period between when a proposal is accepted and when the changes are implemented. I think this should be different than the time until the activation height. The benefits of this delay would include:
  • Allowing community members time to digest and respond to approved proposals.
  • Ensuring that decisions are made collectively and aren’t rushed.
  • Act as a time-constraint security measure, similar to what sumamu implemented in the bridge.

In regards to Sol’s points, here are some more thoughts:

  1. Variable Management: Sol proposed the updateVariable() function, which implies creating and deleting variables. My understanding is that we are planning to replace hardcoded values with variables that we can later adjust through on-chain voting, not introduce new variables. This approach keeps our system flexible while mitigating the risks associated with adding new variables and/or logic.

  2. Naming Conventions: Sol’s proposed names are concise, but I suggest we prioritize clarity, even if it means slightly longer names. For instance:

  • pollDb could be renamed to pollDatabase.
  • pollFee could be renamed to pollSubmissionFee.

I’ll let the on-chain experts decide if this is worth it in terms of chain/binary bloat. Makes me wonder, is there even a thing as minifying the go contract like what they do with js for websites?

  1. Defining Governance Framework: While Sol clearly addressed the module interface and what it’s trying to achieve i.e creating sporks, altering runtime variables, changing the bridge admin key. I think that rather than focusing on the specific actions or functions, it might be beneficial to take a step back and define the theoretical objectives of our governance module. To this end, it could be worthwhile to work on outlining a clear governance framework that describes the principles, goals, and limitations of what the module should and should not be able to achieve. This framework would serve as a guiding document for the design and implementation of our governance module and could be adjusted over time as the needs of the community evolve. I believe this is what George is kinda trying to achieve with the discussions, and not just the technical implementation details.

Looking forward to hearing your thoughts on these suggestions and continuing the productive dialogue.

3 Likes

There are too many things to build. That’s why we need to carefully plan and prioritize any amount of work. I’ve already mentioned in the other forum that the Governance Embedded should be a top priority for everyone.

The Governance Embedded should be simple and follow the principles behind AZ’s embedded.

I think at this stage we need to iterate pretty fast. We are still lacking many critical components that can drive value to the network.

2 Likes

I think we’ll have to iterate on the governance embedded.
But I want us to be conscious and transparent about what we are putting off until later.
My personal goal is to have the first iteration ready to ship by end of July.

Scopes

So I want to first delineate 3 different scopes:

  1. We currently have existing centralized admin functions. We need to quickly mitigate the possible harm without getting rid of any possible benefits.

  2. It is likely that future embedded contracts will adopt an admin pattern as well so that it doesn’t have to duplicate governance logic. We should think about what a scalable solution looks like and consider different options in terms of sophistication vs delivery time.

  3. A good on-chain governance system could be extended to many areas and applications. For example, as reflected in Sol’s post, we have had discussions before about how we can turn what are currently hard-coded constants into dynamic on-chain values which can be subject to governance. I’m also thinking with extension chains and chain relay that higher layers can utilize governance from the root chain.

Governance Framework: Theory

In terms of theory and a governance framework, we can look at real world governance systems and the balance of power. We have the legislative branch which writes the law, the executive branch which applies the law, and the judicial branch which interprets the law.

I think it’s useful to think about how these concepts and concerns translate to decentralized networks overall and in particular to NoM. Maybe later, we can talk about pillar burn vs delegation in terms of governance.

But in terms of actionable discussion, I want to point out that legislatures are often slow to act, if they can come to agreement to at all. However in many situations, e.g. war, quick and decisive action is needed. So legislatures often have means to grant additional temporary executive power.

And I think we will have to design with this as a consideration, especially given the maturity of our current pillar set.

Possible Implementations

z1qxemdeddedxg0vernancexxxxxxxxxxxvmwpcx

To solve for the first scope, we can very quickly create an embedded contract with a set of pass through functions, for each admin interface.
For example, an embedded governance contract that has a CreateSpork, ActivateSpork, bridge/liq methods, which creates proposals for voting and that calls the relevant downstream functions if the proposal passes.
The main design question here would be what are the specific parameters for voting? E.g. time period, quorum, majority vs super-majority. Do different methods have different voting params?

Some possible concerns/limitations:
It gets into a slightly different topic of inactive pillars, but what happens if proposal can never reach quorum?
What if there’s an urgent bugfix where the time period doesn’t make sense?
Here, some sort of admin could make sense, likely the existing spork address to start.

As alluded to by scope 2, a possible downside to this simple approach is that every new embedded contract requiring admin functionality requires an extension of the governance contract interface.

A generic approach could be having the governance embedded expose one method “SendTx” which takes in the arguments of destination and downstream data. Maybe also fields to attach ZTS to the transaction.

However, this would make it more challenging to have different voting parameters for different types of transactions.

The most sophisticated and scalable option imho, is a templating system. It could expose two functions: ProposeTemplate, SendTemplate

The propose template method would take in a data structure defining a tx template, which fields are variable, and voting parameters. It’s like another layer of ABI.
The template would then undergo a vote for acceptance by the pillars. This voting threshold is defined by the governance contract.
If accepted, the template is stored on-chain/in the local db and given an ID.

The send template function would take in a template id and the parameters to render the template. It would then undergo a vote for acceptance by the pillars. This voting threshold is defined by the template.

A system like this likely would not need to be adjusted as new governance capabilities became available.

In terms of the the third scope, I have some ideas on how to migrate hardcoded constants to be on-chain data. But I want to first develop the first two scopes and get a sense of how much harder a sophisticated but scalable system would be over the simple option.

2 Likes

At the very least I want to enable the pillars to take over Spork Creation/Activation asap if they are ready for it. Once we have that, we can iterate at whatever pace the pillars want.

So maybe getting a simple pass through of spork methods, with hardcoded voting params, deployed as quickly as possible should be the first iteration.

For bridge and liquidity, we have the guardian system in place for some level of mitigation so I don’t think it’s as urgent. Although as I’ve said elsewhere, the guardian clients don’t exist yet.

1 Like

Would rather have non-embedded smart contract enabled first tbh

Pretty sure Kaine is not going to prevent any sporks if they offer benefits to the community

Or sentinels too

I just remembered that we’ve done some exploration on the ZIP process before which covers some possible voting parameters.
Linking for reference

Indeed, will be critical to have eventually for sure. But is the community ready to cut the umbilical cord?

Maybe @aliencoder can expound on why he believes this is a top priority.
Here is the other thread he mentioned for reference

I think for the HyperCore One developers, we are in agreement that this is a priority.
There is an aspect of risk mitigation, e.g compromised spork address key can halt the network right now.
But I believe more consequentially, greater community ownership, real and perceived, will drive higher levels of collaboration and ultimately productive output.

3 Likes

Decentralization. Mr Kaine already said that this is one of the top priorities among dynamic plasma and extension chains.

2 Likes

For reference:

1 Like

I think we should start planning the Syirus interface.
If there are any design decisions that need to be made upfront, we should identify what those are.
Otherwise, there’s no reason why clients and embedded can’t be worked on in parallel.

I’m starting to reconcile your thoughts with my own now:

So I like the idea of being able to batch multiple changes together in one vote. I hadn’t considered that. I was mostly thinking about a single downstream function call since this can allow for a very generic interface. But it’s very likely that some changes only make sense when done together.

In terms of where to store the variable. As in which address’s database.
It’s probably easiest in the governance contract itself. Part of me thinks it makes more sense to store it with the relevant embedded contracts that will be using the variable, but then every embedded contract needs an UpdateVariable method callable by an admin (the governance) address.

One thing I had considered was being able to define some sort of “workflow” or different state machines for different processes. But this seems like we would have to tailor it for every single process. (or define the state machine as on-chain data) That’s one reason why I liked the idea of voting on generic transaction sending.

This is what my templating idea is meant to address.
A two tiered system. First vote on what can be governed and their parameters
Then vote on specific executions

For simple passthrough voting, the governance contract likely does not even need to interpret the data at all. It will just store the bytes and use it when it makes then downstream tx. It can be interpreted client side for UI purposes.

1 Like

Happy to see your participation!

On-chain is public, so just like with AZ you’ll be able to see who votes for what.
In terms of rationale and , not sure that data belongs on chain. Feeless doesn’t mean that blockspace doesn’t have value.
Of course we are certainly finding ways to be able to put it on chain. I’m just saying from the perspective of process, not sure putting rationale on chain should be part of it.

So regarding transparency, I guess it would mostly be around the transparency for off-chain governance processes. Open Planning and Design processes (this thread) hopefully addresses what you’re asking for.

So I imagine, unless it’s for a critical bug, we’ll want to have a minimum voting durations. In my templating system, this could be defined as a parameter. At least when it comes to sporks, especially if it’s under pillar governance, I equate Spork creation to acceptance, and activation obviously as activation.

The spork creation/activation process is needed to allow clients to modify the binary to activate using the spork id. For something like changing a variable, where clients already know how to use the value, a create / activation process is not strictly needed. But agree that changes should provide time for the community to digest.

For stuff like variables in code, the compiler’s job is to put it into efficient machine language.
For on-chain data, you’re starting to get into things like gRPC and leveldb compression. Sol and I touched upon it during htlc work I think, but not something we need to worry about right now.

This process should definitely include both the WHY and the HOW.
As mentioned in a previous post, when it comes to governance, we have a lot of historical ideas and concerns we can draw from. We’ll have to apply them to our context, but human behavior is pretty consistent across contexts.

2 Likes

Let’s outline some of the obvious functions and discuss the different requirements.

  • Activate Spork (acceptance implies spork creation)
  • Update variable – some may be more critical than others
  • There are many admin functions for the Bridge and Liquidity contracts, I won’t list them all here yet
    • Bridge: Set Token Pair
    • Bridge: Unhalt
    • Bridge: Set Allow Keygen
    • Liquidity: Set Additional Rewards
    • Liquidity: Set Is Halted
    • Liquidity: Set Token Tuple

Disaster scenario: half the pillars are unable to access the global internet.
Should we limit quorum to those that signed momentums in the last x period?

Could we eventually create a multisig address that acts as an admin?
We could adopt the guardians concept, but network-wide. A group of individuals that would respond quickly to an urgent situation.

An emergency poll is created and if a low threshold of non-guardian pillars vote in favor, it will temporarily give executive power to the multisig, which could require half or more of the guardians to sign transactions.

I was trying to describe this but I don’t have enough experience with go-zenon to articulate the right suggestion.

I don’t understand how this is possible. Are there any examples in go-zenon or would this be new functionality?

I would prefer the template solution but I understand if we want to solve the immediate problem with haste.

I envision a similar process to AZ submissions.
Title, brief description, link to external discussion topic, along with the function calls/data changes payload.

Yeah, I’m not sure which way is best. Are there any really good reasons for either storage method?

As for the Syrius UI, it might be better to delay that conversation a little bit.
I propose that we flesh out most of the gov contract details/functionality first, then try to design UI/UX. We wasted a ton of cycles when we worked on HTLC because the contract changed a few times.

1 Like

Maybe radical but what about penalization for pillars that do not vote.

Im trying to get all the bad ideas out so the good ones will come later

This is tough because the pillar tracker would suggest there are a handful of people with multiple pillars. Conviction voting could offset this but what is conviction based on? Delegated weight another option?

I like the idea of masking results until time has expired to offset voting based on momentum

2 Likes