Embedded Governance Design

We already have this feature.

If you move certain variables on-chain, you need to sync the chain first to read those variables. And I mean sync the entire chain first before processing it, because you need to be sure that you’re not on a fork.

Can you give me an example of on-chain variable vs binary hardcoded?

Constant = “eternally” hardcoded constant values that appear in the codebase (another example is the COINBASE_MATURITY constant that is hardcoded to 100 - I highly doubt it will ever change to another value in the future)

Mutable = the Plasma example you showed earlier; they are marked as constants but in reality they should be mutable (for dynamic Plasma)

The deployment status idea can be interesting, too.

It’s hard to say what is eternally hardcoded for our network. We have design direction from Kaine that implies big changes, likely that will introduce new values and obsolete others.

Sporks are flexible in that they can allow for any type of logic change. But the cost of this flexibility is the off-chain upgrade process and losing nodes that haven’t upgraded when the spork is activated.

Once the dynamic on-chain variable subsystem is setup, changes to variables that have existing logic won’t need changes to the binary. So there won’t be any off-chain upgrade process required. The process will be entirely on-chain.

This is true of verifying any on-chain data. You can’t confirm any transaction unless you’re synced to its height.

So what matters is backwards compatibility with the protocol.
Meaning, that all validators at any given height, agree on the set of valid and invalid transactions.

To the protocol, what data is stored in the code/binary (program’s memory allocation at runtime) vs what data is stored locally on disk/level db is irrelevant. That’s an implementation detail.

One thing we might want to change in the future is the emission rate.
(Whether we actually want to is a different discussion)
Right now emission rate is defined in the code/binary. We can change this with the spork process every time we want to change emissions, but it is cumbersome since each change requires adding new if/else logic to the binary in order to remain backwards compatible. And binary upgrades require the off-chain upgrade process.

What we can do instead is introduce a new system in the codebase to check the value of a dynamic variable at a given height it knows about. The current hardcoded values can be moved to genesis config to seed the associated database. We then modify the protocol for a new UpdateVariable contract method on the governance module which nodes see on-chain and use to modify the associated local database. Putting the initial config values in genesis would also allow testnets to use different values without requiring a patched binary.

3 Likes

Should our Embedded Governance Design take into account the need for our project to be able to enter into agreements with 3rd parties in the real world. For example, we need an apple developer account in order to notarize our macOS code.

Should we form a Wyoming DAO LLC on behalf of the pillars so that entity can open an Apple Developer account?

Should the embedded governance contract include a voting mechanism to grant individual pillars the authority to take action on behalf of the DAO, like open an Apple Developer Account on behalf of an Organization?

If we do not consider this possibility, the burden could fall on individuals for critical infrastructure.

This is bounding us to U.S.A shchizophrenic regulators so why bothering. If Zenon succeed, they’ll come after us all through your LLC. Don’t make it easier for them. I’m not for this kind of risk. It’s unnecessary, even if you’re old self love regulators.

1 Like

Agree the US is not a good place to start this. I’m not familiar with other international jurisdictions. I did research Singapore yesterday and you need a local presence and director. I’m assuming that will be the case with all of them.

But maybe not the Bahamas or others. Has anyone formed an international crypto entity without a local presence?

Why do we need a LLC to put a governance contract in place anyway?

We need an LLC for the network. Like to open an Apple Developer Account. I’m proposing that this responsibility should not fall on an individual (like me). I’m not even writing the code.

So the only logical “organization” to do this assuming no individual wants that responsibility should (could) be the pillars. Needing an LLC will continue to come up. Each one of these app stores will want an LLC. So the issue is not going away soon unfortunately.

1 Like

Sure but don’t bring all pillars into it. I’d, for exemple, wish to opt out.

1 Like

We can learn from others who had a similar issue:

https://forum.sushi.com/t/recommendation-for-sushi-legal-structure/11158

Or how to make it centralized

I guess from a high level it just seems so important to keep the whole model minimized and simple but obviously it’s a tough balance with many variables and scenarios to account for. I also agree that the AZ model is a simple base for this process to build on, in particular if we are just going to focus on getting community spork activation out the door asap.

So i’m clear, is there anything this model/process cannot do with respect to changing the codebase? The replies around constants sounds like there are no actual hard coded values in the code, is this a fair conclusion? If something is going to be eternally constant is that in reality purely up to the governance?

Gotta say I strongly agree with the idea of an incentivized design process as a step in the building. Rewarding those who make the effort to share their ideas and get feedback in public should negate some of the knee jerk reactions by the peanut gallery. There is clearly a need for more discussion, depending on the topic, so the amount of funding/motivation would reflect the magnitude and direction of the proposal. Then even without rewards, having a polling mechanism for community wide discussion could be valuable, maybe even be a job for sentinels.

Right now we reward the top 30 pillars heavily but there is no real feedback loop for the discussion on governance so I have to say that the model seems like an opportunity to have some signalling built in to show the views from other network actors.
For V1.0 would it be realistic for the embedded contract to include some function for polling other layers and/or participants of the network? Maybe it’s a future iteration but it also seems like a strong step from day one to have some capability for this scalable/layered governance set up. George, is this one direction related to your comment expanding the model to other applications? The network is meant to scale in layers, though we are not there yet, it would be valuable imo to see the governance have some capability to match.

Another thing I was looking for clarity on is where/how the line is drawn for the guardians/admin functions. Bridge contracts, Liquidity contracts and future extension chains seem to need some flexible reaction times and ability to address edge cases, unlike the more deliberate process of a Spork Approval/Activation. I see with the Bridge Contract there are specific functions that the admin is able to call. Is this the way all embedded contracts will work? Are these capabilities only ever predefined? Wondering about the odds of future capture of this admin role and what sort of vulnerabilities could be exposed through it. If we are setting up a multi sig address for this type of responsibility does it include an election process to decide the individuals to take this role? Is it as simple as a nomination and voting process every fixed time interval to keep things relevant?

Basically, I have a respect for the QSR burn by pillar operators but also wonder about the role other participants in the network could offer on chain to add resilience or support to the decisions being made, maybe this is a focus for future iterations though.

As far as the voting process goes, I will also add to the growing consensus that masked voting is an important step based on the way pillars have voted in the past. Next, thinking about voting parameters…

Thanks for the ongoing effort to include people in this work

2 Likes

Sentinels

1 Like

Okay, so we have 1 week left for our timebox.
Let’s try and put together a full spec for the embedded contract.

(I’ll make a post later, just been a bit busy today)

3 Likes

So my goal is to have a system that can quickly fill our short terms needs while also providing enough of a framework to scale for future needs.

At a high level, I think we want to have a comprehensive and flexible Proposal datatype which can account for the nuances of governance. And we want our voting process to use the parameters of the Proposal regarding things such as vote duration, quorum, majority vs super-majority.

If we get that right, we can then iterate on the methods that can create proposals.
For the most flexible methods, we should have the most restrictive voting parameters.
But the governance system may want to allow itself more lenient voting for certain pre-approved items, which is where a templating system can be used.

For transactions we use the ABI for performance, but for low frequency items that require flexibility, a json data structure might be easier. In theory we could do this by defining new ABI, but not sure it’s worth it.

So let’s first start with a wrapper ABI to store our proposal json and some relevant fields for update/vote checking.

		{"type":"variable", "name":"proposalInfo", "inputs":[
			{"name":"id", "type":"hash"},
			{"name":"proposal", "type":"bytes"},
			{"name":"creationTimestamp","type":"int64"},
			{"name":"updatedTimestamp","type":"int64"},
			{"name":"status","type":"uint8"},
		]},

Let’s then define a json schema for a Proposal datatype
We will have some fields for the voting parameters.
And another for the transactions to be sent.
We can come up with a json-schema later for client validation, but here’s an example.

{
  "voteType" : 0,
  "voteParams" : {
    "duration": 14,
    "quorum": 0,
    "threshold": 50
  },
  "transactions": [
    {
      "address": "z1qxemdeddedxsp0rkxxxxxxxxxxxxxxxx956u48",
      "tokenStandard": "zts1znnxxxxxxxxxxxxx9z4ulx",
      "amount": "0",
      "data": "SporkCreationDataInBase64"
    },
    {
      "address": "z1qxemdeddedxg0vernancexxxxxxxxxxxvmwpcx",
      "tokenStandard": "zts1znnxxxxxxxxxxxxx9z4ulx",
      "amount": "0",
      "data": "UpdateVariableDataInBase64"
    }
  ]
}

This is actually pretty similar to the example payload that Sol explored.
His example supported dynamic constants and contract method calls as first class concepts.
His example also mixed voting params with dynamic variables.

I think we should separate out the voting parameters as that cannot be set by the proposer.
And we should treat transactions as the first class concept. It is much more flexible.
Contract methods are just used to render tx data, and dynamic constants can be done with a transaction interface.

In this example, we have a proposal for the embedded governance address send two transactions, one to the spork address, and another to itself. We need to understand the consequences of sending to itself, and the risks of recursion, so we may need to limit what can be sent to itself. Or we handle self sends with special internal logic instead of actually creating transactions.

Let’s go over the different fields.

transactions is obvious.
An earlier post of mine describes a layer of indirection between rendered transactions and proposals.
That is really only useful to save bandwidth if rendered transactions are going to be reused. I think transaction templates will be reused, and these operations will be infrequent in either case.

voteType is used to signify which ruleset to use to evaluate if a proposal has passed.
For example, a voteType of 0 can be used to indicate pillar vote, and voteType of 1 could be used for single address admin vote.

Different voteTypes have different voteParam requirements.
In the case of a pillar vote, we need the duration, threshold, and maybe quorum.
Quorum is a little strange because even with hidden votes, there are incentives to not vote to possibly prevent an otherwise successful vote from meeting quorum.

A quorum makes sense in systems where you need to gather enough voters into a session together to all vote at once. In a distributed system, it seems to make less sense. So I think we should allow a 0 value for no quorum.

One modification we should consider where quorum actually becomes useful is a layered voting system. Instead of:

  "voteType" : 0,
  "voteParams" : {
    "duration": 14,
    "quorum": 0,
    "threshold": 50
  },

We could do something like:

"governanceChain": [
  {
    "voteType" : 0,
    "voteParams" : {
      "duration": 14,
      "quorum": 33,
      "threshold": 50
    },
  {
    "voteType" : 1,
    "voteParams" : {
      "duration": 7,
      "address": "z1qpxswrfnlll355wrx868xh58j7e2gu2n2u5czv"
    },
]

For each sequence in the governance chain, there are 3 outcomes, PASS, FAIL, INVALID
If the sequence is INVALID, it initiates the next vote type in the sequence.
What this system doesn’t capture is the possibility for parallel voting, but not sure if we want that.

In the above example, there would first be a pillar vote for 2 weeks. If it reached quorum of >33% of pillars, that result would count. If it didn’t reach the quorum it would then move to an admin vote by a single address.

Okay now that we have our flexible proposal datatype which can be voted on, we need a way to create these. Let’s first start with simplest ones.

		{"type":"function","name":"ProposeTransaction","inputs":[
			{"name":"address", "type":"address"},
			{"name":"tokenStandard", "type":"tokenStandard"},
			{"name":"amount", "type":"uint256"},
			{"name":"data", "type":"bytes"},
		]}
		{"type":"function","name":"ProposeTransactions","inputs":[
			{"name":"txs", "type":"bytes"},
		]}

ProposeTransaction is simpler and somewhat redundant if ProposeTransactions (plural) exists.
Both methods would create a proposalInfo variable, with a hardcoded governance chain and the relevant tx(s) in the transaction list. In the case of ProposeTransactions, the txs field would directly map to the transactions field of the proposal data.

To actually make this contract work of course as before we need the actual methods for voting, updating, and probably a way to fund/donate fund the contract as well.

In terms of scaling and allowing for ohter governanceChains, in the future we can have other methods such as, ProposeTemplate, ProposeTemplateDeletion, ProposeRenderedTemplates

ProposeTemplate and ProposeTemplate deletion would be meta-proposals that use a strict (e.g supermajority) vote to allow for different/more flexible governance chains for certain types of proposed transactions.

Ideas such as Sol’s spam prevention mechanism can be added as well, but that is just another instance of FAIL outcome with different rules.

3 Likes

So for example if you called the ProposeTransaction method with the following parameters

      "address": "z1qxemdeddedxsp0rkxxxxxxxxxxxxxxxx956u48",
      "tokenStandard": "zts1znnxxxxxxxxxxxxx9z4ulx",
      "amount": "0",
      "data": "SporkCreationDataInBase64"

And our default governance chain was

"governanceChain": [
  {
    "voteType" : 0,
    "voteParams" : {
      "duration": 14,
      "quorum": 33,
      "threshold": 50
    },
  {
    "voteType" : 1,
    "voteParams" : {
      "duration": 7,
      "address": "z1qpxswrfnlll355wrx868xh58j7e2gu2n2u5czv"
    },
]

It would create a proposalInfo variable in database state
where the proposal field would be

{
"governanceChain": [
  {
    "voteType" : 0,
    "voteParams" : {
      "duration": 14,
      "quorum": 33,
      "threshold": 50
    },
  {
    "voteType" : 1,
    "voteParams" : {
      "duration": 7,
      "address": "z1qpxswrfnlll355wrx868xh58j7e2gu2n2u5czv"
    },
],
"transactions": [
    {
      "address": "z1qxemdeddedxsp0rkxxxxxxxxxxxxxxxx956u48",
      "tokenStandard": "zts1znnxxxxxxxxxxxxx9z4ulx",
      "amount": "0",
      "data": "SporkCreationDataInBase64"
    }
]
2 Likes

I don’t think it’s a good idea to connect any sort of legal entity to the network as a whole.
Having a legal entity doesn’t remove the burden on individuals. Someone still has to keep it in compliance.

The best way to handle this is through AZ.
We can provide incentives to community members and teams who take on this risk.

1 Like

Having some sort of legal structure for HyperCore.One is something I’m still thinking about.

The free and open source licenses should give us some level of protection when it comes to the codebase. But exactly for the purposes of publishing apps on gated ecosystems, we should consider it.

However, I think that is out of scope for the embedded governance design which is mainly about on-chain authority. Any generic polling mechanism could be used to signal “off-chain” authority. But it’s meaningless unless it’s recognized.

4 Likes

Agree. This was a bad idea.

My goal is to have something shippable by end of July which covers our initial simple use cases.
I don’t want to get into proposals yet though until the design phase is over.

Hmm so the spork creation/activation process is about changes to the consensus protocol. This protocol sits on top of other protocols such as the p2p communication protocol. Mr Kaine has mentioned a switch to libp2p, but this isn’t really something related to consensus. I think the way to handle this would be to have a transition phase where nodes are broadcasting to the old p2p network and the new p2p network.

In terms of consensus, I think the spork process is very flexible.
Consensus is just about what txs are valid/invalid. Individuals node can do whatever they want locally as long they set of valid transactions stay the same.
So changes to stuff like internal database and rpc, don’t really need a spork.

Hopefully the community finds it valuable as well.
If not, I will just do this exercise internally for HyperCore.One proposals as part of our own implementations. And the costs will be bundled into a larger proposal.
It’s actually more of a competitive advantage at this stage if I do that and I don’t think I will design for free anymore.
But I want the best result for our community and am willing to try and create collaboration and competition where appropriate even if it’s against myself.

My personal view is that for an efficient L1, polls that do nothing but signal don’t really belong. We’re using AZ for that purpose right now but it’s not the best tool for the job. We need a strong ecosystem of off-chain communication. (I maybe have some work related to this in progress.)
But the extension chain conversation makes this harder to judge.

If we have extension chains, then polls that only signal on L1, might have very strong consequences on higher layers if there is a tight integration (e.g chain relay)

The design I posted above goes into layered voting.
But what you are describing is more like parallel voting, separation of powers, checks and balances. In my design all that logic could be built into a new voteType, but having a way to define building blocks and compose them might be nice.

In terms of pure pure of stake weight vs pillar burn, this is similar in my view to states’ rights vs direct democracy in irl. The way we balance it right now is by having momentum production based on delegation while votes based on burn.
In term of other participants such as sentinels, if they are a core part of network resilience, then they definitely need to have an influence. What that influence should look like, I’m not sure.
In terms of my design above, maybe we need a future voteType that requires a pillar and sentinel vote to both pass.

I’m not sure if we need to handle masked voting specifically for governance or if we can handle it generically for the entire network with threshhold encryption. Governance is not the only area where we’ll want this capability.

3 Likes