Closed AM5800 closed 5 years ago
@amiller could you please share your opinion on this?
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.
@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?
@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?
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?
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)
@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?
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.
@AM5800 @Gnappuraz The introduction of SegWit also came with a versioning improvement which could maybe come in quite handy here.
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.
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.
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.
@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?
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"
@scravy thanks!
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
This looks great! I really like this proposal and the rest of the discussion.
How about having a dead-man switch? If some number of blocks go by without any command taking place, then the permissioning system also turns off. This way if 2 of the admin keys are lost, there is still an eventual end to the permissioning
Refreshing the public keys is a good idea. On the other hand I also like the idea of the protocol making things easiest for ending the permissioning rather than easier for the administrator to continue. If the administrators can't hold on to their keys then they should be kicked out :p Not sure what the right answer is on balance.
I'm less clear on how the P2P version of this will work. I think your proposal is to have a new kind of transaction, which is like a coinbase transaction in that it has no input, but is like an ordinary tx in that it is added to mempool, relayed, etc., by peers just like other transactions, and eventually included in a block. Can we do something as similar to the Esperanza voting transactions as possible? There @Gnappuraz also ran into several issues of what is easiest regarding validation of special transactions. If we make the transaction have inputs like ordinary, then validation and propagation will be easier I think
Emptying the whitelist to signal ending permissioning would be strange. Because the closer you get to empty, the fewer people are permissioned, it's somehow not continuous. Having an explicit disable is better.
@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?
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?
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
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.
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
IsStandard
:
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
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.
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.
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
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.
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.
Field | Description | Type/Size |
---|---|---|
Batch Index | Auto incremented batch index | VarInt |
Commands # | Number of commands to follow | VarInt |
Commands List | see below | variable |
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.
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 |
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 |
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 |
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
@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.
@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.
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.
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
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).
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.
Thanks again everyone. I will remove batching and batch index completely.
@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?
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
Fixed with https://github.com/dtr-org/unit-e/pull/127
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.
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
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
Remove from white list command
Disable permissioning Tells the system that permissioning system is now disabled forever.
Open questions:
CommandsIndicator
should be? Or how else we can distinguish admin commands among outputs?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