dtr-org / unit-e

A digital currency for a new era of decentralized trust
https://unit-e.io
MIT License
45 stars 15 forks source link

Validator permissioning. Data structure proposal #73

Closed AM5800 closed 5 years ago

AM5800 commented 6 years ago

Latest version of this specification - Spec v2

This issue is going to cover only the way whitelist is stored in the blockchain. Acquisition/relaying of this data will be discussed separately. For now, our goal is to be able to hardcode white list in the genesis block and have a way to change it later.

The idea is as follows: 1) First set of administrator keys is stored in the genesis block 2) Whitelist is just a list of public keys that are allowed to be validators 3) Each node stores entire white list 4) Administrator issues special kinds of commands that order nodes to add or remove validator pubkeys to/from the white list 6) Those commands are stored in a new dedicated output of a CoinBase/CoinStake transaction

CoinBase is already a special type of transaction and validation rules are unique for it. So it seems natural to add this kind of data to it. It will also allow us to give a reward for including commands into a block. Plus we don't need to check all the transactions in the block - we always know where admin command can appear.

So the entire thing is going to be stored in the output locking script, which will look like following: <OP_RETURN> <CommandsIndicator> <CommandsBatch> CommandsIndicator - is a flag indicating the that administrator commands will follow.

Administrator commands batch Commands come in batches of one or several commands.

Field Description Type/Size
Batch Index Auto incremented batch index VarInt
Commands # Number of commands to follow VarInt
Commands List see below variable
Signature(s) Administrator signature(s) variable

Index serves 2 purposes: first, if there are several command batches present in the system - nodes will be able to order them correctly (order is important). Second, always incrementing this value forces signature to be different each time.

In order to sign something we usually need a signature and a public key. But in this case public keys are already known to the system. So I think we only need to provide the signature. However, if this batch is in the genesis block - there are no admins pubkeys yet. So I guess we can skip the signatures or use zeros.

To increase security of the system I propose to use 2-of-3 multisig scheme. So we would need to provide at least 2 signatures with each message and have 3 administrator public keys.

Reset administrators command

Field Description Type/Size
Command id Identifies the command. =1 BYTE
Pubkeys List of new admin pubkeys (amount should be constant) variable

This command provides a new set of administrator key(s). And after this entire output is handled - old keys should be forgotten. It is possible, though, to include the same key again if you don't want to replace all of them.

This command is useful in two ways: first, included into the genesis block it will set initial administrators(instead of hardcoding them). Second, if one of the administrator keys is compromised - we could replace it with other two(assuming we use 2-of-3 scheme).

Add to white list command

Field Description Type/Size
Command id Identifies the command. =2 BYTE
Pubkeys # Number of pubkeys to follow VarInt
Pubkeys List of pubkeys to whitelist variable

Remove from white list command

Field Description Type/Size
Command id Identifies the command. =3 BYTE
Pubkeys # Number of pubkeys to follow VarInt
Pubkeys List of pubkeys to remove from white list variable

Disable permissioning Tells the system that permissioning system is now disabled forever.

Field Description Type/Size
Command id Identifies the command. =4 BYTE

Open questions:

UPD: initial admin keys are now set in genesis block instead of hardcoding them. It is also possible to reset current admin keys with special command. Added command that disables permissioning. Rephrased to avoid confusion with p2p messages

AM5800 commented 6 years ago

@amiller could you please share your opinion on this?

scravy commented 6 years ago

I have a couple of questions:

(1) Why not have the administrator public key encoded in the genesis block?

That way it is part of the blockchain and part of the consensus. The genesis block is already special, so I would not mind to have the initial transaction also have an output which has a script that sets the admin key.

(2) How would we eventually move away from permissioning?

Like, is there a command that can be issued by the administrator which finally allows us to open the blockchain for everyone?

(3) How does the administrator issue these commands?

I am trying to decipher form the description what is part of P2P and what is part of the structure in a block. Please clarify.

AM5800 commented 6 years ago

@scravy 1) We can do this, yes. But we will need another set of rules/formats/whatever for this one-time initialization, won't we? 2) Sure, we can add such command. If it needed 3) This whole issue is only about block structure. Maybe word 'message' is confusing?

scravy commented 6 years ago

@AM5800 The word message is confusing (I am thinking about a P2P message when I read it). In a block you have a header, and a list of transactions (...segwit, proof-of-stake signature, okay...). But typically everything is either in the header or in a transaction. So I would like to know what the transaction looks like. Will you rely on the transaction type we introduced in unit-e?

scravy commented 6 years ago

Regarding 2 - command for ending the permissioned network and opening it up.

I do believe that such a command is necessary and should be there from the beginning. I believe that in order for this to become completely decentralized and to be accepted by the community as a truly decentralized network we will have to go there eventually and it should be indicated from the beginning of the design that we do want to go there and will go there.

(4) Another question just pops in my mind: What if that admin key is leaked?

Maybe there should be a mechanism to revoke even this key. I am thinking. Maybe initially there could be three keys. Two of which can revoke a key and bless a new one. WDYT?

AM5800 commented 6 years ago

Will you rely on the transaction type we introduced in unit-e?

I am not going to introduce new transaction type. Just add one more output to CoinStake transaction. And how to understand that this is exactly admin 'message' - yet an open question.

(2) Ok, thanks. Could you, by the way, explain how validators will be selected after whitelist is removed? I know that validator must make deposit, but are we going to allow anyone to make deposits? And what if everyone will want to be a validator? Is there some voting or...?

(4) > What if that admin key is leaked? Initial Idea was to use 2-of-3 multisig for signing admin messages. So if one key is leaked attacker still couldn't sign anything. But your idea is cool too! We could have a command that updates set of admin keys, for example. Stacks very good with (1)

AM5800 commented 6 years ago

@scravy by the way, to (2): instead of creating a command for this, we could just state that empy white list means there are no restrictions. What do you think?

scravy commented 6 years ago

Empty Whitelist = No Restrictions. Interesting idea. Would that also mean that the permissioning is technically still active, that is, an admin could move the network into permissioned mode again if she wanted to?

I think that might have bad repercussions with the community, because effectively control is still in the hands of the few. Apart from that: I think it would be quite a celebration, actually a public event, "unit-e opens up to everyone" etc.

Yes, ultimately the idea is to have anyone able to assume any role in the network. @amiller @Gnappuraz @thothd correct me if I'm wrong. There is no voting, no validator selection. You deposit some stake, you're a validator – but being a validator might be associated with some cost, so factually not everyone can be a validator. But is still eligible to conceptually.

scravy commented 6 years ago

@AM5800 @Gnappuraz The introduction of SegWit also came with a versioning improvement which could maybe come in quite handy here.

AM5800 commented 6 years ago

I think it would be quite a celebration, actually a public event, "unit-e opens up to everyone" etc.

In that case we indeed need a special command to be explicit.

Gnappuraz commented 6 years ago

Why not have the administrator public key encoded in the genesis block

That is an excellent idea I think. I would actually define in the genesis the first command creating the first set of validators. Hardcoding stuff in the codebase would require soft-forks if we want to change and also when we go open and we then remove the code that part will not be obvious anymore but the special outputs will still be in the blocks.

The introduction of SegWit also came with a versioning improvement which could maybe come in quite handy here.

Since the output will not bear any value using a custom witness script or not does not make much difference. I although consider cleaner using a specific witness script version though than prepending the OP_RETURN.

Gnappuraz commented 6 years ago

Empty Whitelist = No Restrictions. Interesting idea. Would that also mean that the permissioning is technically still active, that is, an admin could move the network into permissioned mode again if she wanted to?

I believe that the opening should be a non-revertable event. If we open we cannot close again. Otherwise our rationale for being permissioned (because of a testing/roll out period) is weak.

AM5800 commented 6 years ago

@scravy @Gnappuraz thanks for your comments, I have changed spec according to suggestions(well, except SegWit stuff - because I still need to read more about it). What do you think?

scravy commented 6 years ago

I like the reset administrators command and how that elegantly solves how to put it in the genesis block. That's the way!

I think the multisig is good and necessary, especially for exiting the permissioned mode! Since you're basically just appending data to a script (it does not look to actually be a script, it is really just data after OP_RETURN, right?) I think you can just define that as a rule "command is accepted as valid in the blockchain only if there are two (or more) valid signatures"

AM5800 commented 6 years ago

@scravy thanks!

thothd commented 6 years ago

Looks good, regarding storing the admin keys on-chain (in the genesis block). First of all it's anyway hardcoded since the genesis block is created by code. There's no issue to have it on-chain but we'll anyway need a mechanism to handle a disaster where we're losing all the admin private keys and can't sign any whitelist message. Which will be something like - from height X on accept those keys - at this point we can also inject it to a specific block if we wanna have it on-chain

amiller commented 6 years ago

This looks great! I really like this proposal and the rest of the discussion.

AM5800 commented 6 years ago

@amiller, @thothd thank you guys!

Emptying the whitelist to signal ending permissioning would be strange...

Yeah, already discarded this idea

I'm less clear on how the P2P version of this will work.

Haven't investigated p2p too deep yet. But a few days ago we had a discussion and decided that we don't want to have inputs for this transaction. Because it logically has no input. We just post a message to chain, what might be the input anyway?

How about having a dead-man switch?

Sounds cool! Though I am not sure how to pick this constant... Does anyone have any estimate on how long we would need a permissioning system?

AM5800 commented 6 years ago

What @thothd mentions is a serious issue I think. So I will try to summarize. We are now choosing between storing admin pubkeys in the chain or simply hardcoding them.

Storing in the chain: + Part of the consensus. All nodes know what active keys are and it's impossible for some nodes to have different keys. - In a disastrous event of loosing all keys it is quite hard to do hardfork. - Stores slightly more data in the chain

Hardcode pubkeys: + Very simple. Requires less commands and less code that 'infers' active pubkeys + Stores slightly less data in the blockchain + Hardfork is straightforward - Not part of the consensus. In theory there might be nodes with different hardcoded admin keys. But I don't see what harm they might make

Am I missing something?

AM5800 commented 6 years ago

So let's review all possible bad things that could happen with admin keys (2-of-3 multisig):

1 key is lost System is still under our control. No harm can be done to the network. However, we might want to secure ourselves from losing another key.

Overall, this scenario is possible

1 key is stolen Like previous, but I would say that probability is muuuch lower. In the end, you usually protect private keys with passwords, encryption etc

>= 2 keys are lost Losing one key is independent event, so joint probability of losing several is very low. However if that happens: Control over network is lost(but still no harm can be done). We can't change white list, we can't end permissioning.

1 key is lost, 1 key is stolen Not much a difference from previous.

>= 2 keys are stolen This time events are not independent. It is most likely a targeted attack. But it is still extremely unlikely to succeed. Countermeasures are the same as above. But let's think what actual harm can be done:

Another attack vector might be just spam - attacker will generate a lot of huge admin messages. One more attack idea: attacker validators might just always make system alway disagree on voting.

Anyway, in case this happens we need to do hard fork as fast as we can

AM5800 commented 6 years ago

Thanks everyone for the discussion! The spec is more or less agreed as it is in the first post. I am now switching on p2p part.

AM5800 commented 6 years ago

I have decided not to create another issue for p2p. Because I think it was a mistake in the first place to separate them. So here are my ideas on p2p:

Relay commands inside a usual transactions

Bottomline: + No need to implement relaying - Need to change lots of stuff in random places - In my opinion looks like a bunch of very dirty hacks

Relay commands in a custom p2p messages

Bottomline: + Straightforward. Doesn't look like a dirty hack to me - Definitely much more work

AM5800 commented 6 years ago

All the stuff above feels like an over-complication to me. We have quite simple task and implementation must be simple too. So I started digging in other ways. We have already considered idea of UTXO-way. But it was discarded because we didn't wanted to spend anything (i.e. not having inputs). And we also wanted to be able to give rewards for including commands to blocks(CoinBase looked like a perfect place for it)

But what if we return to this model and actually pay for our transactions out of our pocket? This idea gave birth to the spec v2.

Spec v2. UTXO-way

Abstract

During the initial stage we would like to limit who can be a validator. For this purpose we define a whitelist of validators. If a validator's pubkey is present in this whitelist - he can login. If not - login transaction should be marked invalid. Whitelist is stored in the blockchain and available to all nodes. Contents of whitelist can only be updated by trusted administrators with special transactions.

Specification

To confirm administrators identity we will always be using 2-of-3 multisignature scheme

First set of administrator pubkeys will be hardcoded into the genesis block

Administrators issue special commands that:

Commands are stored in an OP_RETURN output of a spacial transactions - admin transactions

Once command is in the blockchain - it is in effect. Not earlier

Admin transactions must spend an UTXO. This UTXO will be used to validate admin identity and also to pay for issuing a command. To clarify - we are paying real money for including our commands into the blockchain

Output that is being spent:

Admin transaction:

If a transaction has version of admin transaction, but anything from above is not true - we should consider entire transaction invalid. All standard transaction checks are employed too.

It is also worth noting that data in OP_RETURN might get quite large. And there are lots of strict restrictions on its size in existing code. So we will definitely have to change them.

Commands

In order to reduce commands overhead on the network we pack multiple commands in batches. One transaction - one batch. Order in which batches are included in the blockchain might be important. So they will also have an auto incremented index. Proposers should take care to include batches in this particular order. Otherwise their blocks will be considered invalid.

Batch structure

Field Description Type/Size
Batch Index Auto incremented batch index VarInt
Commands # Number of commands to follow VarInt
Commands List see below variable

Reset admins command

Field Description Type/Size
Command id Identifies the command. =1 BYTE
Pubkeys List of new admin pubkeys (amount should be constant) variable

This command provides a new set of administrator keys. And after this entire output is handled - old keys should be forgotten. It is possible, though, to include the same key again if you don't want to replace all of them.

This command is useful in two ways: first, included into the genesis block it will set initial administrators. Second, if one of the administrator keys is compromised - we could replace it with using the other two.

Add to white list command

Field Description Type/Size
Command id Identifies the command. =2 BYTE
Pubkeys # Number of pubkeys to follow VarInt
Pubkeys List of pubkeys to whitelist variable

Remove from white list command

Field Description Type/Size
Command id Identifies the command. =3 BYTE
Pubkeys # Number of pubkeys to follow VarInt
Pubkeys List of pubkeys to remove from white list variable

Disable permissioning command

Tells the system that permissioning system is now disabled forever. Any admin transaction that comes after this is invalid. For a better finality effect we might also set batch index to a maximum value

Field Description Type/Size
Command id Identifies the command. =4 BYTE

Admin keys safety

In the unfortunate event of losing/compromising one of admin private keys, we should issue a 'reset admins' command and sign it with the other two keys. This is quite possible case and we are ready for it.

Losing/compromising 2 keys is very unlikely. In order to do that we need to first lose one and NOT issue 'reset admins' command. But still, if that happens - we must do a hardfork

Open questions

AM5800 commented 6 years ago

@thothd @amiller @Gnappuraz @scravy I would very like to know what you think about it. I think that this approach is the best so far. It is very simple, yet flexible. Existing code changes are minimal. It also addresses an incentivization issue in a way that it can be easily changed later.

Gnappuraz commented 6 years ago

@AM5800 are paying real money, more likely real tokens ;) As for the open points:

  • What happens if we remove an active validator from the white list?

We simply start rejecting any deposit or vote transactions. They can still logout and withdraw. In reality since I expect that the whitelist management will be transparent, all the parts involved will be notified on time, and validators will have all the interest in logging out before being removed.

  • What would genesis admin transaction look like? It needs to spend something. But what?

I think this is also easy to solve. During the genesis allocation the foundation will have plenty of funds to be used for different goals (grants to devs, marketing, running costs etc...). I expect that the foundation will cover this cost easily using part of those funds.

scravy commented 6 years ago

Let's check whether I am understanding this correctly:

According to this new specification:

Some questions:

My gut feeling is that this approach is more complicated actually. But I do think there is a need to pay for a transaction to have an incentive for proposers to include them in a block. Just there should be some restrictions in place for admin transactions I guess.

I don't know about this batching. Collecting transactions in a block is a form of batching already. It feels like it tries to solve a problem which doesn't exist. Also we have quite a rapid block time. The admin-commands are not issued frequently or in rapid succession. Some of them are ideally (reset admin) never used, and some (end permissioning) are only ever used once.

AM5800 commented 6 years ago

Actually, where does "admin-utxo"s come from and where do outputs of admin transactions are sent to - is not part of this spec.

Does the proposer proposing a block containing an admin transaction get fees from an admin transaction?

Yes

Who does an admin spend to?

In the simplest scenario all input goes to fee. So the only output is data

Can an admin transaction have multiple inputs and does it suffice if any input referes to an admin-utxo or do all have to refer to an admin-utxo?

I would like to avoid such scenarios by limiting inputs to exactly one. But maybe I am too strict...

does anyone you spend to become an admin then?

Why? In order to validate admin command we must ensure that unlocking script contains admin public keys. If we spend to someone else - there will be different keys

Oh, forgot to mention that batching also helps to make add/remove operations atomic. For example if you want to replace 10 out of 100 validators with someone else. If there will be two separate operations then between them total number of validators won't be equal to 100. Like 100->90->100 or 100->110->100. Guess this is not desirable

scravy commented 6 years ago

Thank you for the clarifications. This way it makes sense to me. I would actually limit the degrees of freedom for those admin transactions to keep things simple:

The atomicity of the commands is a nice trait, although I doubt we really need it. I'm envisioning the whole permissioning process more a "Hey guys, university of Tacka Tucka decided to start running a validator, I'll add them to the whitelist, you cool with that?". But I'm in no way against it, seems to be reasonably straight forward also (but conceptually maybe a tiny bit simpler if just have 1 transaction = 1 command).

amiller commented 6 years ago

My preference would be simplifying the description/implementation of the permissioning system, even if it means more effort for the admins. So having 1 transaction = 1 command fits with this. Batching is pretty simple though too, just have multiple valid OP_RETURN outputs processed in order.

Also, I would prefer not having a rule that makes proposer's blocks invalid if they don't respect transaction order. It's true that applying commands out of order could be a problem. But admins should be able to use UTXO ordering (spend an input that's the output of the previous command) to ensure they're sequenced. A possible gap in the above spec is that if you only define an ordering (batch index must be greater) then a proposer could skip a command, e.g. command 1 2 4 and skip 3. This is actually a reason to allow multiple outputs, since it enables such sequencing.

AM5800 commented 6 years ago

Thanks again everyone. I will remove batching and batch index completely.

AM5800 commented 6 years ago

@amiller on the other hand... If we rely completely on a UTXO ordering, won't we need to remove limitation on number of inputs/outputs of admin transactions?

amiller commented 6 years ago

I think we should not impose additional restrictions that nodes have to enforce by consensus on the admin transactions. Instead we should impose limitations on how the admin transactions are interpreted. For example, only the first transaction input is checked for having 2/3 multisig input containing all admin addresses. And only the first output is interpreted as an op_return admin command

AM5800 commented 5 years ago

Fixed with https://github.com/dtr-org/unit-e/pull/127