2023-04-25 19:05:58 +00:00
|
|
|
# Tributary
|
|
|
|
|
|
|
|
A tributary is a side-chain, created for a specific multisig instance, used
|
|
|
|
as a verifiable broadcast layer.
|
|
|
|
|
|
|
|
## Transactions
|
|
|
|
|
|
|
|
### Key Gen Commitments
|
|
|
|
|
|
|
|
`DkgCommitments` is created when a processor sends the coordinator
|
|
|
|
`key_gen::ProcessorMessage::Commitments`. When all validators participating in
|
|
|
|
a multisig publish `DkgCommitments`, the coordinator sends the processor
|
2023-08-13 06:21:56 +00:00
|
|
|
`key_gen::CoordinatorMessage::Commitments`, excluding the processor's own
|
|
|
|
commitments.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
|
|
|
### Key Gen Shares
|
|
|
|
|
|
|
|
`DkgShares` is created when a processor sends the coordinator
|
2023-08-14 10:08:55 +00:00
|
|
|
`key_gen::ProcessorMessage::Shares`. The coordinator additionally includes its
|
|
|
|
own pair of MuSig nonces, used in a signing protocol to inform Substrate of the
|
|
|
|
key's successful creation.
|
|
|
|
|
|
|
|
When all validators participating in a multisig publish `DkgShares`, the
|
|
|
|
coordinator sends the processor `key_gen::CoordinatorMessage::Shares`, excluding
|
|
|
|
the processor's own shares and the MuSig nonces.
|
|
|
|
|
|
|
|
### Key Gen Confirmation
|
|
|
|
|
|
|
|
`DkgConfirmed` is created when a processor sends the coordinator
|
|
|
|
`key_gen::ProcessorMessage::GeneratedKeyPair`. The coordinator takes the MuSig
|
|
|
|
nonces they prior associated with this DKG attempt and publishes their signature
|
|
|
|
share.
|
|
|
|
|
|
|
|
When all validators participating in the multisig publish `DkgConfirmed`, an
|
|
|
|
extrinsic calling `validator_sets::pallet::set_keys` is made to confirm the
|
|
|
|
keys.
|
|
|
|
|
|
|
|
Setting the keys on the Serai blockchain as such lets it receive `Batch`s,
|
|
|
|
provides a BFT consensus guarantee, and enables accessibility by users. While
|
|
|
|
the tributary itself could offer both the BFT consensus guarantee, and
|
|
|
|
verifiable accessibility to users, they'd both require users access the
|
|
|
|
tributary. Since Substrate must already know the resulting key, there's no value
|
|
|
|
to usage of the tributary as-such, as all desired properties are already offered
|
|
|
|
by Substrate.
|
|
|
|
|
|
|
|
Note that the keys are confirmed when Substrate emits a `KeyGen` event,
|
|
|
|
regardless of if the Tributary has the expected `DkgConfirmed` transactions.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
Replace ExternalBlock with Batch
The initial TODO was simply to use one ExternalBlock per all batches in the
block. This would require publishing ExternalBlock after the last batch,
requiring knowing the last batch. While we could add such a pipeline, it'd
require:
1) Initial preprocesses using a distinct message from BatchPreprocess
2) An additional message sent after all BatchPreprocess are sent
Unfortunately, both would require tweaks to the SubstrateSigner which aren't
worth the complexity compared to the solution here, at least, not at this time.
While this will cause, if a Tributary is signing a block whose total batch data
exceeds 25 kB, to use multiple transactions which could be optimized out by
'better' local data pipelining, that's an extreme edge case. Given the temporal
nature of each Tributary, it's also an acceptable edge.
This does no longer achieve synchrony over external blocks accordingly. While
signed batches have synchrony, as they embed their block hash, batches being
signed don't have cryptographic synchrony on their contents. This means
validators who are eclipsed may produce invalid shares, as they sign a
different batch. This will be introduced in a follow-up commit.
2023-09-01 02:48:02 +00:00
|
|
|
### Batch
|
2023-04-25 19:05:58 +00:00
|
|
|
|
Replace ExternalBlock with Batch
The initial TODO was simply to use one ExternalBlock per all batches in the
block. This would require publishing ExternalBlock after the last batch,
requiring knowing the last batch. While we could add such a pipeline, it'd
require:
1) Initial preprocesses using a distinct message from BatchPreprocess
2) An additional message sent after all BatchPreprocess are sent
Unfortunately, both would require tweaks to the SubstrateSigner which aren't
worth the complexity compared to the solution here, at least, not at this time.
While this will cause, if a Tributary is signing a block whose total batch data
exceeds 25 kB, to use multiple transactions which could be optimized out by
'better' local data pipelining, that's an extreme edge case. Given the temporal
nature of each Tributary, it's also an acceptable edge.
This does no longer achieve synchrony over external blocks accordingly. While
signed batches have synchrony, as they embed their block hash, batches being
signed don't have cryptographic synchrony on their contents. This means
validators who are eclipsed may produce invalid shares, as they sign a
different batch. This will be introduced in a follow-up commit.
2023-09-01 02:48:02 +00:00
|
|
|
When *TODO*, a `Batch` transaction is provided. This is used to have the group
|
|
|
|
acknowledge and synchronize around a batch, without the overhead of voting in
|
|
|
|
its acknowledgment.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
Replace ExternalBlock with Batch
The initial TODO was simply to use one ExternalBlock per all batches in the
block. This would require publishing ExternalBlock after the last batch,
requiring knowing the last batch. While we could add such a pipeline, it'd
require:
1) Initial preprocesses using a distinct message from BatchPreprocess
2) An additional message sent after all BatchPreprocess are sent
Unfortunately, both would require tweaks to the SubstrateSigner which aren't
worth the complexity compared to the solution here, at least, not at this time.
While this will cause, if a Tributary is signing a block whose total batch data
exceeds 25 kB, to use multiple transactions which could be optimized out by
'better' local data pipelining, that's an extreme edge case. Given the temporal
nature of each Tributary, it's also an acceptable edge.
This does no longer achieve synchrony over external blocks accordingly. While
signed batches have synchrony, as they embed their block hash, batches being
signed don't have cryptographic synchrony on their contents. This means
validators who are eclipsed may produce invalid shares, as they sign a
different batch. This will be introduced in a follow-up commit.
2023-09-01 02:48:02 +00:00
|
|
|
When a `Batch` transaction is included, participants are allowed to publish
|
|
|
|
transactions to produce a threshold signature for the batch synchronized over.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
|
|
|
### Substrate Block
|
|
|
|
|
|
|
|
`SubstrateBlock` is provided when the processor sends the coordinator
|
|
|
|
`substrate::ProcessorMessage::SubstrateBlockAck`.
|
|
|
|
|
|
|
|
When a `SubstrateBlock` transaction is included, participants are allowed to
|
|
|
|
publish transactions for the signing protocols it causes.
|
|
|
|
|
|
|
|
### Batch Preprocess
|
|
|
|
|
|
|
|
`BatchPreprocess` is created when a processor sends the coordinator
|
Replace ExternalBlock with Batch
The initial TODO was simply to use one ExternalBlock per all batches in the
block. This would require publishing ExternalBlock after the last batch,
requiring knowing the last batch. While we could add such a pipeline, it'd
require:
1) Initial preprocesses using a distinct message from BatchPreprocess
2) An additional message sent after all BatchPreprocess are sent
Unfortunately, both would require tweaks to the SubstrateSigner which aren't
worth the complexity compared to the solution here, at least, not at this time.
While this will cause, if a Tributary is signing a block whose total batch data
exceeds 25 kB, to use multiple transactions which could be optimized out by
'better' local data pipelining, that's an extreme edge case. Given the temporal
nature of each Tributary, it's also an acceptable edge.
This does no longer achieve synchrony over external blocks accordingly. While
signed batches have synchrony, as they embed their block hash, batches being
signed don't have cryptographic synchrony on their contents. This means
validators who are eclipsed may produce invalid shares, as they sign a
different batch. This will be introduced in a follow-up commit.
2023-09-01 02:48:02 +00:00
|
|
|
`coordinator::ProcessorMessage::BatchPreprocess` and an `Batch` transaction
|
|
|
|
allowing the batch to be signed has already been included on chain.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
2023-08-13 06:21:56 +00:00
|
|
|
When `t` validators have published `BatchPreprocess` transactions, if the
|
|
|
|
coordinator represents one of the first `t` validators to do so, a
|
|
|
|
`coordinator::ProcessorMessage::BatchPreprocesses` is sent to the processor,
|
|
|
|
excluding the processor's own preprocess.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
|
|
|
### Batch Share
|
|
|
|
|
|
|
|
`BatchShare` is created when a processor sends the coordinator
|
Replace ExternalBlock with Batch
The initial TODO was simply to use one ExternalBlock per all batches in the
block. This would require publishing ExternalBlock after the last batch,
requiring knowing the last batch. While we could add such a pipeline, it'd
require:
1) Initial preprocesses using a distinct message from BatchPreprocess
2) An additional message sent after all BatchPreprocess are sent
Unfortunately, both would require tweaks to the SubstrateSigner which aren't
worth the complexity compared to the solution here, at least, not at this time.
While this will cause, if a Tributary is signing a block whose total batch data
exceeds 25 kB, to use multiple transactions which could be optimized out by
'better' local data pipelining, that's an extreme edge case. Given the temporal
nature of each Tributary, it's also an acceptable edge.
This does no longer achieve synchrony over external blocks accordingly. While
signed batches have synchrony, as they embed their block hash, batches being
signed don't have cryptographic synchrony on their contents. This means
validators who are eclipsed may produce invalid shares, as they sign a
different batch. This will be introduced in a follow-up commit.
2023-09-01 02:48:02 +00:00
|
|
|
`coordinator::ProcessorMessage::BatchShare`. The relevant `Batch`
|
2023-04-25 19:05:58 +00:00
|
|
|
transaction having already been included on chain follows from
|
|
|
|
`coordinator::ProcessorMessage::BatchShare` being a response to a message which
|
|
|
|
also has that precondition.
|
|
|
|
|
|
|
|
When the `t` validators who first published `BatchPreprocess` transactions have
|
2023-08-13 06:21:56 +00:00
|
|
|
published `BatchShare` transactions, if the coordinator represents one of the
|
|
|
|
first `t` validators to do so, a `coordinator::ProcessorMessage::BatchShares`
|
|
|
|
with the relevant shares (excluding the processor's own) is sent to the
|
|
|
|
processor.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
|
|
|
### Sign Preprocess
|
|
|
|
|
|
|
|
`SignPreprocess` is created when a processor sends the coordinator
|
|
|
|
`sign::ProcessorMessage::Preprocess` and a `SubstrateBlock` transaction
|
|
|
|
allowing the transaction to be signed has already been included on chain.
|
|
|
|
|
2023-08-13 06:21:56 +00:00
|
|
|
When `t` validators have published `SignPreprocess` transactions, if the
|
|
|
|
coordinator represents one of the first `t` validators to do so, a
|
|
|
|
`sign::ProcessorMessage::Preprocesses` is sent to the processor,
|
|
|
|
excluding the processor's own preprocess.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
|
|
|
### Sign Share
|
|
|
|
|
|
|
|
`SignShare` is created when a processor sends the coordinator
|
|
|
|
`sign::ProcessorMessage::Share`. The relevant `SubstrateBlock` transaction
|
|
|
|
having already been included on chain follows from
|
|
|
|
`sign::ProcessorMessage::Share` being a response to a message which
|
|
|
|
also has that precondition.
|
|
|
|
|
|
|
|
When the `t` validators who first published `SignPreprocess` transactions have
|
2023-08-13 06:21:56 +00:00
|
|
|
published `SignShare` transactions, if the coordinator represents one of the
|
|
|
|
first `t` validators to do so, a `sign::ProcessorMessage::Shares` with the
|
|
|
|
relevant shares (excluding the processor's own) is sent to the processor.
|
2023-04-25 19:05:58 +00:00
|
|
|
|
2023-07-30 10:44:55 +00:00
|
|
|
### Sign Completed
|
|
|
|
|
|
|
|
`SignCompleted` is created when a processor sends the coordinator
|
|
|
|
`sign::ProcessorMessage::Completed`. As soon as 34% of validators send
|
|
|
|
`Completed`, the signing protocol is no longer further attempted.
|
|
|
|
|
2023-04-25 19:05:58 +00:00
|
|
|
## Re-attempts
|
|
|
|
|
2023-07-30 10:44:55 +00:00
|
|
|
Key generation protocols may fail if a validator is malicious. Signing
|
|
|
|
protocols, whether batch or transaction, may fail if a validator goes offline or
|
|
|
|
takes too long to respond. Accordingly, the tributary will schedule re-attempts.
|
|
|
|
These are communicated with `key_gen::CoordinatorMessage::GenerateKey`,
|
2023-04-25 19:05:58 +00:00
|
|
|
`coordinator::CoordinatorMessage::BatchReattempt`, and
|
|
|
|
`sign::CoordinatorMessage::Reattempt`.
|
|
|
|
|
|
|
|
TODO: Document the re-attempt scheduling logic.
|