2025-01-08 16:41:11 -05:00
|
|
|
use core::{marker::PhantomData, fmt::Debug, future::Future};
|
2024-07-16 16:42:15 -07:00
|
|
|
use std::{sync::Arc, io};
|
2023-04-13 18:43:03 -04:00
|
|
|
|
|
|
|
|
use zeroize::Zeroizing;
|
|
|
|
|
|
|
|
|
|
use ciphersuite::{Ciphersuite, Ristretto};
|
|
|
|
|
|
|
|
|
|
use scale::Decode;
|
2023-12-10 19:32:43 -05:00
|
|
|
use futures_channel::mpsc::UnboundedReceiver;
|
|
|
|
|
use futures_util::{StreamExt, SinkExt};
|
2023-04-13 18:43:03 -04:00
|
|
|
use ::tendermint::{
|
2023-04-14 14:11:19 -04:00
|
|
|
ext::{BlockNumber, Commit, Block as BlockTrait, Network},
|
2023-04-24 02:44:21 -04:00
|
|
|
SignedMessageFor, SyncedBlock, SyncedBlockSender, SyncedBlockResultReceiver, MessageSender,
|
|
|
|
|
TendermintMachine, TendermintHandle,
|
2023-04-13 18:43:03 -04:00
|
|
|
};
|
2023-04-11 10:18:31 -04:00
|
|
|
|
2023-11-05 07:04:41 +03:00
|
|
|
pub use ::tendermint::Evidence;
|
|
|
|
|
|
2023-04-14 14:11:19 -04:00
|
|
|
use serai_db::Db;
|
|
|
|
|
|
2023-04-23 23:15:15 -04:00
|
|
|
use tokio::sync::RwLock;
|
2023-04-23 16:56:23 -04:00
|
|
|
|
2023-04-11 13:42:18 -04:00
|
|
|
mod merkle;
|
|
|
|
|
pub(crate) use merkle::*;
|
|
|
|
|
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
pub mod transaction;
|
|
|
|
|
pub use transaction::{TransactionError, Signed, TransactionKind, Transaction as TransactionTrait};
|
|
|
|
|
|
|
|
|
|
use crate::tendermint::tx::TendermintTx;
|
2023-04-11 13:42:18 -04:00
|
|
|
|
2023-04-11 20:24:27 -04:00
|
|
|
mod provided;
|
2023-04-12 16:06:14 -04:00
|
|
|
pub(crate) use provided::*;
|
2023-04-14 15:03:01 -04:00
|
|
|
pub use provided::ProvidedError;
|
2023-04-11 20:24:27 -04:00
|
|
|
|
2023-04-11 13:42:18 -04:00
|
|
|
mod block;
|
|
|
|
|
pub use block::*;
|
|
|
|
|
|
2023-04-12 11:13:48 -04:00
|
|
|
mod blockchain;
|
2023-04-13 20:35:55 -04:00
|
|
|
pub(crate) use blockchain::*;
|
2023-04-12 11:13:48 -04:00
|
|
|
|
2023-04-12 12:15:38 -04:00
|
|
|
mod mempool;
|
2023-04-13 20:35:55 -04:00
|
|
|
pub(crate) use mempool::*;
|
2023-04-12 12:15:38 -04:00
|
|
|
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
pub mod tendermint;
|
2023-04-13 18:43:03 -04:00
|
|
|
pub(crate) use crate::tendermint::*;
|
2023-04-12 16:06:14 -04:00
|
|
|
|
2023-04-11 19:04:53 -04:00
|
|
|
#[cfg(any(test, feature = "tests"))]
|
|
|
|
|
pub mod tests;
|
|
|
|
|
|
2023-04-13 20:35:55 -04:00
|
|
|
/// Size limit for an individual transaction.
|
One Round DKG (#589)
* Upstream GBP, divisor, circuit abstraction, and EC gadgets from FCMP++
* Initial eVRF implementation
Not quite done yet. It needs to communicate the resulting points and proofs to
extract them from the Pedersen Commitments in order to return those, and then
be tested.
* Add the openings of the PCs to the eVRF as necessary
* Add implementation of secq256k1
* Make DKG Encryption a bit more flexible
No longer requires the use of an EncryptionKeyMessage, and allows pre-defined
keys for encryption.
* Make NUM_BITS an argument for the field macro
* Have the eVRF take a Zeroizing private key
* Initial eVRF-based DKG
* Add embedwards25519 curve
* Inline the eVRF into the DKG library
Due to how we're handling share encryption, we'd either need two circuits or to
dedicate this circuit to the DKG. The latter makes sense at this time.
* Add documentation to the eVRF-based DKG
* Add paragraph claiming robustness
* Update to the new eVRF proof
* Finish routing the eVRF functionality
Still needs errors and serialization, along with a few other TODOs.
* Add initial eVRF DKG test
* Improve eVRF DKG
Updates how we calculcate verification shares, improves performance when
extracting multiple sets of keys, and adds more to the test for it.
* Start using a proper error for the eVRF DKG
* Resolve various TODOs
Supports recovering multiple key shares from the eVRF DKG.
Inlines two loops to save 2**16 iterations.
Adds support for creating a constant time representation of scalars < NUM_BITS.
* Ban zero ECDH keys, document non-zero requirements
* Implement eVRF traits, all the way up to the DKG, for secp256k1/ed25519
* Add Ristretto eVRF trait impls
* Support participating multiple times in the eVRF DKG
* Only participate once per key, not once per key share
* Rewrite processor key-gen around the eVRF DKG
Still a WIP.
* Finish routing the new key gen in the processor
Doesn't touch the tests, coordinator, nor Substrate yet.
`cargo +nightly fmt && cargo +nightly-2024-07-01 clippy --all-features -p serai-processor`
does pass.
* Deduplicate and better document in processor key_gen
* Update serai-processor tests to the new key gen
* Correct amount of yx coefficients, get processor key gen test to pass
* Add embedded elliptic curve keys to Substrate
* Update processor key gen tests to the eVRF DKG
* Have set_keys take signature_participants, not removed_participants
Now no one is removed from the DKG. Only `t` people publish the key however.
Uses a BitVec for an efficient encoding of the participants.
* Update the coordinator binary for the new DKG
This does not yet update any tests.
* Add sensible Debug to key_gen::[Processor, Coordinator]Message
* Have the DKG explicitly declare how to interpolate its shares
Removes the hack for MuSig where we multiply keys by the inverse of their
lagrange interpolation factor.
* Replace Interpolation::None with Interpolation::Constant
Allows the MuSig DKG to keep the secret share as the original private key,
enabling deriving FROST nonces consistently regardless of the MuSig context.
* Get coordinator tests to pass
* Update spec to the new DKG
* Get clippy to pass across the repo
* cargo machete
* Add an extra sleep to ensure expected ordering of `Participation`s
* Update orchestration
* Remove bad panic in coordinator
It expected ConfirmationShare to be n-of-n, not t-of-n.
* Improve documentation on functions
* Update TX size limit
We now no longer have to support the ridiculous case of having 49 DKG
participations within a 101-of-150 DKG. It does remain quite high due to
needing to _sign_ so many times. It'd may be optimal for parties with multiple
key shares to independently send their preprocesses/shares (despite the
overhead that'll cause with signatures and the transaction structure).
* Correct error in the Processor spec document
* Update a few comments in the validator-sets pallet
* Send/Recv Participation one at a time
Sending all, then attempting to receive all in an expected order, wasn't working
even with notable delays between sending messages. This points to the mempool
not working as expected...
* Correct ThresholdKeys serialization in modular-frost test
* Updating existing TX size limit test for the new DKG parameters
* Increase time allowed for the DKG on the GH CI
* Correct construction of signature_participants in serai-client tests
Fault identified by akil.
* Further contextualize DkgConfirmer by ValidatorSet
Caught by a safety check we wouldn't reuse preprocesses across messages. That
raises the question of we were prior reusing preprocesses (reusing keys)?
Except that'd have caused a variety of signing failures (suggesting we had some
staggered timing avoiding it in practice but yes, this was possible in theory).
* Add necessary calls to set_embedded_elliptic_curve_key in coordinator set rotation tests
* Correct shimmed setting of a secq256k1 key
* cargo fmt
* Don't use `[0; 32]` for the embedded keys in the coordinator rotation test
The key_gen function expects the random values already decided.
* Big-endian secq256k1 scalars
Also restores the prior, safer, Encryption::register function.
2024-08-16 11:26:07 -07:00
|
|
|
// This needs to be big enough to participate in a 101-of-150 eVRF DKG with each element taking
|
|
|
|
|
// `MAX_KEY_LEN`. This also needs to be big enough to pariticpate in signing 520 Bitcoin inputs
|
|
|
|
|
// with 49 key shares, and signing 120 Monero inputs with 49 key shares.
|
|
|
|
|
// TODO: Add a test for these properties
|
|
|
|
|
pub const TRANSACTION_SIZE_LIMIT: usize = 2_000_000;
|
2023-04-13 20:35:55 -04:00
|
|
|
/// Amount of transactions a single account may have in the mempool.
|
|
|
|
|
pub const ACCOUNT_MEMPOOL_LIMIT: u32 = 50;
|
|
|
|
|
/// Block size limit.
|
One Round DKG (#589)
* Upstream GBP, divisor, circuit abstraction, and EC gadgets from FCMP++
* Initial eVRF implementation
Not quite done yet. It needs to communicate the resulting points and proofs to
extract them from the Pedersen Commitments in order to return those, and then
be tested.
* Add the openings of the PCs to the eVRF as necessary
* Add implementation of secq256k1
* Make DKG Encryption a bit more flexible
No longer requires the use of an EncryptionKeyMessage, and allows pre-defined
keys for encryption.
* Make NUM_BITS an argument for the field macro
* Have the eVRF take a Zeroizing private key
* Initial eVRF-based DKG
* Add embedwards25519 curve
* Inline the eVRF into the DKG library
Due to how we're handling share encryption, we'd either need two circuits or to
dedicate this circuit to the DKG. The latter makes sense at this time.
* Add documentation to the eVRF-based DKG
* Add paragraph claiming robustness
* Update to the new eVRF proof
* Finish routing the eVRF functionality
Still needs errors and serialization, along with a few other TODOs.
* Add initial eVRF DKG test
* Improve eVRF DKG
Updates how we calculcate verification shares, improves performance when
extracting multiple sets of keys, and adds more to the test for it.
* Start using a proper error for the eVRF DKG
* Resolve various TODOs
Supports recovering multiple key shares from the eVRF DKG.
Inlines two loops to save 2**16 iterations.
Adds support for creating a constant time representation of scalars < NUM_BITS.
* Ban zero ECDH keys, document non-zero requirements
* Implement eVRF traits, all the way up to the DKG, for secp256k1/ed25519
* Add Ristretto eVRF trait impls
* Support participating multiple times in the eVRF DKG
* Only participate once per key, not once per key share
* Rewrite processor key-gen around the eVRF DKG
Still a WIP.
* Finish routing the new key gen in the processor
Doesn't touch the tests, coordinator, nor Substrate yet.
`cargo +nightly fmt && cargo +nightly-2024-07-01 clippy --all-features -p serai-processor`
does pass.
* Deduplicate and better document in processor key_gen
* Update serai-processor tests to the new key gen
* Correct amount of yx coefficients, get processor key gen test to pass
* Add embedded elliptic curve keys to Substrate
* Update processor key gen tests to the eVRF DKG
* Have set_keys take signature_participants, not removed_participants
Now no one is removed from the DKG. Only `t` people publish the key however.
Uses a BitVec for an efficient encoding of the participants.
* Update the coordinator binary for the new DKG
This does not yet update any tests.
* Add sensible Debug to key_gen::[Processor, Coordinator]Message
* Have the DKG explicitly declare how to interpolate its shares
Removes the hack for MuSig where we multiply keys by the inverse of their
lagrange interpolation factor.
* Replace Interpolation::None with Interpolation::Constant
Allows the MuSig DKG to keep the secret share as the original private key,
enabling deriving FROST nonces consistently regardless of the MuSig context.
* Get coordinator tests to pass
* Update spec to the new DKG
* Get clippy to pass across the repo
* cargo machete
* Add an extra sleep to ensure expected ordering of `Participation`s
* Update orchestration
* Remove bad panic in coordinator
It expected ConfirmationShare to be n-of-n, not t-of-n.
* Improve documentation on functions
* Update TX size limit
We now no longer have to support the ridiculous case of having 49 DKG
participations within a 101-of-150 DKG. It does remain quite high due to
needing to _sign_ so many times. It'd may be optimal for parties with multiple
key shares to independently send their preprocesses/shares (despite the
overhead that'll cause with signatures and the transaction structure).
* Correct error in the Processor spec document
* Update a few comments in the validator-sets pallet
* Send/Recv Participation one at a time
Sending all, then attempting to receive all in an expected order, wasn't working
even with notable delays between sending messages. This points to the mempool
not working as expected...
* Correct ThresholdKeys serialization in modular-frost test
* Updating existing TX size limit test for the new DKG parameters
* Increase time allowed for the DKG on the GH CI
* Correct construction of signature_participants in serai-client tests
Fault identified by akil.
* Further contextualize DkgConfirmer by ValidatorSet
Caught by a safety check we wouldn't reuse preprocesses across messages. That
raises the question of we were prior reusing preprocesses (reusing keys)?
Except that'd have caused a variety of signing failures (suggesting we had some
staggered timing avoiding it in practice but yes, this was possible in theory).
* Add necessary calls to set_embedded_elliptic_curve_key in coordinator set rotation tests
* Correct shimmed setting of a secq256k1 key
* cargo fmt
* Don't use `[0; 32]` for the embedded keys in the coordinator rotation test
The key_gen function expects the random values already decided.
* Big-endian secq256k1 scalars
Also restores the prior, safer, Encryption::register function.
2024-08-16 11:26:07 -07:00
|
|
|
// This targets a growth limit of roughly 30 GB a day, under load, in order to prevent a malicious
|
2023-04-13 20:35:55 -04:00
|
|
|
// participant from flooding disks and causing out of space errors in order processes.
|
One Round DKG (#589)
* Upstream GBP, divisor, circuit abstraction, and EC gadgets from FCMP++
* Initial eVRF implementation
Not quite done yet. It needs to communicate the resulting points and proofs to
extract them from the Pedersen Commitments in order to return those, and then
be tested.
* Add the openings of the PCs to the eVRF as necessary
* Add implementation of secq256k1
* Make DKG Encryption a bit more flexible
No longer requires the use of an EncryptionKeyMessage, and allows pre-defined
keys for encryption.
* Make NUM_BITS an argument for the field macro
* Have the eVRF take a Zeroizing private key
* Initial eVRF-based DKG
* Add embedwards25519 curve
* Inline the eVRF into the DKG library
Due to how we're handling share encryption, we'd either need two circuits or to
dedicate this circuit to the DKG. The latter makes sense at this time.
* Add documentation to the eVRF-based DKG
* Add paragraph claiming robustness
* Update to the new eVRF proof
* Finish routing the eVRF functionality
Still needs errors and serialization, along with a few other TODOs.
* Add initial eVRF DKG test
* Improve eVRF DKG
Updates how we calculcate verification shares, improves performance when
extracting multiple sets of keys, and adds more to the test for it.
* Start using a proper error for the eVRF DKG
* Resolve various TODOs
Supports recovering multiple key shares from the eVRF DKG.
Inlines two loops to save 2**16 iterations.
Adds support for creating a constant time representation of scalars < NUM_BITS.
* Ban zero ECDH keys, document non-zero requirements
* Implement eVRF traits, all the way up to the DKG, for secp256k1/ed25519
* Add Ristretto eVRF trait impls
* Support participating multiple times in the eVRF DKG
* Only participate once per key, not once per key share
* Rewrite processor key-gen around the eVRF DKG
Still a WIP.
* Finish routing the new key gen in the processor
Doesn't touch the tests, coordinator, nor Substrate yet.
`cargo +nightly fmt && cargo +nightly-2024-07-01 clippy --all-features -p serai-processor`
does pass.
* Deduplicate and better document in processor key_gen
* Update serai-processor tests to the new key gen
* Correct amount of yx coefficients, get processor key gen test to pass
* Add embedded elliptic curve keys to Substrate
* Update processor key gen tests to the eVRF DKG
* Have set_keys take signature_participants, not removed_participants
Now no one is removed from the DKG. Only `t` people publish the key however.
Uses a BitVec for an efficient encoding of the participants.
* Update the coordinator binary for the new DKG
This does not yet update any tests.
* Add sensible Debug to key_gen::[Processor, Coordinator]Message
* Have the DKG explicitly declare how to interpolate its shares
Removes the hack for MuSig where we multiply keys by the inverse of their
lagrange interpolation factor.
* Replace Interpolation::None with Interpolation::Constant
Allows the MuSig DKG to keep the secret share as the original private key,
enabling deriving FROST nonces consistently regardless of the MuSig context.
* Get coordinator tests to pass
* Update spec to the new DKG
* Get clippy to pass across the repo
* cargo machete
* Add an extra sleep to ensure expected ordering of `Participation`s
* Update orchestration
* Remove bad panic in coordinator
It expected ConfirmationShare to be n-of-n, not t-of-n.
* Improve documentation on functions
* Update TX size limit
We now no longer have to support the ridiculous case of having 49 DKG
participations within a 101-of-150 DKG. It does remain quite high due to
needing to _sign_ so many times. It'd may be optimal for parties with multiple
key shares to independently send their preprocesses/shares (despite the
overhead that'll cause with signatures and the transaction structure).
* Correct error in the Processor spec document
* Update a few comments in the validator-sets pallet
* Send/Recv Participation one at a time
Sending all, then attempting to receive all in an expected order, wasn't working
even with notable delays between sending messages. This points to the mempool
not working as expected...
* Correct ThresholdKeys serialization in modular-frost test
* Updating existing TX size limit test for the new DKG parameters
* Increase time allowed for the DKG on the GH CI
* Correct construction of signature_participants in serai-client tests
Fault identified by akil.
* Further contextualize DkgConfirmer by ValidatorSet
Caught by a safety check we wouldn't reuse preprocesses across messages. That
raises the question of we were prior reusing preprocesses (reusing keys)?
Except that'd have caused a variety of signing failures (suggesting we had some
staggered timing avoiding it in practice but yes, this was possible in theory).
* Add necessary calls to set_embedded_elliptic_curve_key in coordinator set rotation tests
* Correct shimmed setting of a secq256k1 key
* cargo fmt
* Don't use `[0; 32]` for the embedded keys in the coordinator rotation test
The key_gen function expects the random values already decided.
* Big-endian secq256k1 scalars
Also restores the prior, safer, Encryption::register function.
2024-08-16 11:26:07 -07:00
|
|
|
pub const BLOCK_SIZE_LIMIT: usize = 2_001_000;
|
2023-04-13 20:35:55 -04:00
|
|
|
|
2023-04-24 02:44:21 -04:00
|
|
|
pub(crate) const TENDERMINT_MESSAGE: u8 = 0;
|
2024-04-28 04:04:53 -04:00
|
|
|
pub(crate) const TRANSACTION_MESSAGE: u8 = 1;
|
2023-04-13 18:43:03 -04:00
|
|
|
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
#[allow(clippy::large_enum_variant)]
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
|
pub enum Transaction<T: TransactionTrait> {
|
|
|
|
|
Tendermint(TendermintTx),
|
|
|
|
|
Application(T),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: TransactionTrait> ReadWrite for Transaction<T> {
|
|
|
|
|
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
|
|
|
|
let mut kind = [0];
|
|
|
|
|
reader.read_exact(&mut kind)?;
|
|
|
|
|
match kind[0] {
|
|
|
|
|
0 => {
|
|
|
|
|
let tx = TendermintTx::read(reader)?;
|
|
|
|
|
Ok(Transaction::Tendermint(tx))
|
|
|
|
|
}
|
|
|
|
|
1 => {
|
|
|
|
|
let tx = T::read(reader)?;
|
|
|
|
|
Ok(Transaction::Application(tx))
|
|
|
|
|
}
|
2023-11-19 18:01:13 -05:00
|
|
|
_ => Err(io::Error::other("invalid transaction type")),
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
|
|
|
|
match self {
|
|
|
|
|
Transaction::Tendermint(tx) => {
|
|
|
|
|
writer.write_all(&[0])?;
|
|
|
|
|
tx.write(writer)
|
|
|
|
|
}
|
|
|
|
|
Transaction::Application(tx) => {
|
|
|
|
|
writer.write_all(&[1])?;
|
|
|
|
|
tx.write(writer)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: TransactionTrait> Transaction<T> {
|
|
|
|
|
pub fn hash(&self) -> [u8; 32] {
|
|
|
|
|
match self {
|
|
|
|
|
Transaction::Tendermint(tx) => tx.hash(),
|
|
|
|
|
Transaction::Application(tx) => tx.hash(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-31 12:14:32 -05:00
|
|
|
pub fn kind(&self) -> TransactionKind {
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
match self {
|
|
|
|
|
Transaction::Tendermint(tx) => tx.kind(),
|
|
|
|
|
Transaction::Application(tx) => tx.kind(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-11 13:42:18 -04:00
|
|
|
/// An item which can be read and written.
|
|
|
|
|
pub trait ReadWrite: Sized {
|
|
|
|
|
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self>;
|
|
|
|
|
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()>;
|
|
|
|
|
|
|
|
|
|
fn serialize(&self) -> Vec<u8> {
|
|
|
|
|
// BlockHeader is 64 bytes and likely the smallest item in this system
|
|
|
|
|
let mut buf = Vec::with_capacity(64);
|
|
|
|
|
self.write(&mut buf).unwrap();
|
|
|
|
|
buf
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-13 18:43:03 -04:00
|
|
|
|
2025-01-08 17:40:32 -05:00
|
|
|
pub trait P2p: 'static + Send + Sync + Clone {
|
2023-10-12 22:14:42 -04:00
|
|
|
/// Broadcast a message to all other members of the Tributary with the specified genesis.
|
|
|
|
|
///
|
|
|
|
|
/// The Tributary will re-broadcast consensus messages on a fixed interval to ensure they aren't
|
|
|
|
|
/// prematurely dropped from the P2P layer. THe P2P layer SHOULD perform content-based
|
|
|
|
|
/// deduplication to ensure a sane amount of load.
|
2025-01-08 16:41:11 -05:00
|
|
|
fn broadcast(&self, genesis: [u8; 32], msg: Vec<u8>) -> impl Send + Future<Output = ()>;
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<P: P2p> P2p for Arc<P> {
|
2025-01-08 16:41:11 -05:00
|
|
|
fn broadcast(&self, genesis: [u8; 32], msg: Vec<u8>) -> impl Send + Future<Output = ()> {
|
|
|
|
|
P::broadcast(self, genesis, msg)
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-22 22:27:12 -04:00
|
|
|
#[derive(Clone)]
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
pub struct Tributary<D: Db, T: TransactionTrait, P: P2p> {
|
2023-04-23 23:37:40 -04:00
|
|
|
db: D,
|
|
|
|
|
|
2023-04-23 16:56:23 -04:00
|
|
|
genesis: [u8; 32],
|
2023-04-14 14:11:19 -04:00
|
|
|
network: TendermintNetwork<D, T, P>,
|
2023-04-13 18:43:03 -04:00
|
|
|
|
2023-08-27 05:01:19 -04:00
|
|
|
synced_block: Arc<RwLock<SyncedBlockSender<TendermintNetwork<D, T, P>>>>,
|
2023-04-24 02:44:21 -04:00
|
|
|
synced_block_result: Arc<RwLock<SyncedBlockResultReceiver>>,
|
2023-04-23 23:15:15 -04:00
|
|
|
messages: Arc<RwLock<MessageSender<TendermintNetwork<D, T, P>>>>,
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
|
2023-04-13 18:43:03 -04:00
|
|
|
pub async fn new(
|
2023-04-14 14:11:19 -04:00
|
|
|
db: D,
|
2023-04-13 18:43:03 -04:00
|
|
|
genesis: [u8; 32],
|
|
|
|
|
start_time: u64,
|
|
|
|
|
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
2023-04-22 10:49:52 -04:00
|
|
|
validators: Vec<(<Ristretto as Ciphersuite>::G, u64)>,
|
2023-04-13 18:43:03 -04:00
|
|
|
p2p: P,
|
2023-04-14 15:51:43 -04:00
|
|
|
) -> Option<Self> {
|
2023-08-08 15:12:47 -04:00
|
|
|
log::info!("new Tributary with genesis {}", hex::encode(genesis));
|
|
|
|
|
|
2023-04-22 10:49:52 -04:00
|
|
|
let validators_vec = validators.iter().map(|validator| validator.0).collect::<Vec<_>>();
|
2023-04-13 18:43:03 -04:00
|
|
|
|
|
|
|
|
let signer = Arc::new(Signer::new(genesis, key));
|
2023-04-14 15:51:43 -04:00
|
|
|
let validators = Arc::new(Validators::new(genesis, validators)?);
|
2023-04-13 18:43:03 -04:00
|
|
|
|
2023-04-23 23:37:40 -04:00
|
|
|
let mut blockchain = Blockchain::new(db.clone(), genesis, &validators_vec);
|
2024-02-05 11:50:55 +03:00
|
|
|
let block_number = BlockNumber(blockchain.block_number());
|
2023-04-14 14:11:19 -04:00
|
|
|
|
|
|
|
|
let start_time = if let Some(commit) = blockchain.commit(&blockchain.tip()) {
|
|
|
|
|
Commit::<Validators>::decode(&mut commit.as_ref()).unwrap().end_time
|
|
|
|
|
} else {
|
|
|
|
|
start_time
|
|
|
|
|
};
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
let proposal = TendermintBlock(
|
2023-12-17 00:01:41 -05:00
|
|
|
blockchain.build_block::<TendermintNetwork<D, T, P>>(&validators).serialize(),
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
);
|
2023-04-13 18:43:03 -04:00
|
|
|
let blockchain = Arc::new(RwLock::new(blockchain));
|
|
|
|
|
|
2024-07-16 16:42:15 -07:00
|
|
|
let network = TendermintNetwork { genesis, signer, validators, blockchain, p2p };
|
2023-04-13 18:43:03 -04:00
|
|
|
|
2023-04-24 02:44:21 -04:00
|
|
|
let TendermintHandle { synced_block, synced_block_result, messages, machine } =
|
2024-03-08 01:15:10 -05:00
|
|
|
TendermintMachine::new(
|
|
|
|
|
db.clone(),
|
|
|
|
|
network.clone(),
|
|
|
|
|
genesis,
|
|
|
|
|
block_number,
|
|
|
|
|
start_time,
|
|
|
|
|
proposal,
|
|
|
|
|
)
|
|
|
|
|
.await;
|
2023-10-14 20:07:12 -04:00
|
|
|
tokio::spawn(machine.run());
|
2023-04-13 18:43:03 -04:00
|
|
|
|
2023-04-24 02:44:21 -04:00
|
|
|
Some(Self {
|
|
|
|
|
db,
|
|
|
|
|
genesis,
|
|
|
|
|
network,
|
2023-08-27 05:01:19 -04:00
|
|
|
synced_block: Arc::new(RwLock::new(synced_block)),
|
2023-04-24 02:44:21 -04:00
|
|
|
synced_block_result: Arc::new(RwLock::new(synced_block_result)),
|
|
|
|
|
messages: Arc::new(RwLock::new(messages)),
|
|
|
|
|
})
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-22 22:27:12 -04:00
|
|
|
pub fn block_time() -> u32 {
|
|
|
|
|
TendermintNetwork::<D, T, P>::block_time()
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 05:05:17 -04:00
|
|
|
pub fn genesis(&self) -> [u8; 32] {
|
2023-04-23 16:56:23 -04:00
|
|
|
self.genesis
|
2023-04-20 05:05:17 -04:00
|
|
|
}
|
2023-04-23 23:15:15 -04:00
|
|
|
|
2024-02-05 11:50:55 +03:00
|
|
|
pub async fn block_number(&self) -> u64 {
|
2023-04-23 23:15:15 -04:00
|
|
|
self.network.blockchain.read().await.block_number()
|
2023-04-22 10:49:52 -04:00
|
|
|
}
|
2023-04-23 23:15:15 -04:00
|
|
|
pub async fn tip(&self) -> [u8; 32] {
|
|
|
|
|
self.network.blockchain.read().await.tip()
|
2023-04-15 00:41:48 -04:00
|
|
|
}
|
2023-04-23 23:37:40 -04:00
|
|
|
|
2023-04-24 06:50:40 -04:00
|
|
|
pub fn reader(&self) -> TributaryReader<D, T> {
|
|
|
|
|
TributaryReader(self.db.clone(), self.genesis, PhantomData)
|
2023-04-23 18:55:43 -04:00
|
|
|
}
|
2023-04-15 00:41:48 -04:00
|
|
|
|
2023-04-23 23:15:15 -04:00
|
|
|
pub async fn provide_transaction(&self, tx: T) -> Result<(), ProvidedError> {
|
|
|
|
|
self.network.blockchain.write().await.provide_transaction(tx)
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
|
2023-12-01 12:09:22 -05:00
|
|
|
pub async fn next_nonce(
|
|
|
|
|
&self,
|
|
|
|
|
signer: &<Ristretto as Ciphersuite>::G,
|
|
|
|
|
order: &[u8],
|
|
|
|
|
) -> Option<u32> {
|
|
|
|
|
self.network.blockchain.read().await.next_nonce(signer, order)
|
2023-04-13 20:35:55 -04:00
|
|
|
}
|
|
|
|
|
|
2023-10-14 21:50:11 -04:00
|
|
|
// Returns Ok(true) if new, Ok(false) if an already present unsigned, or the error.
|
2023-04-23 16:56:23 -04:00
|
|
|
// Safe to be &self since the only meaningful usage of self is self.network.blockchain which
|
2023-04-25 03:14:42 -04:00
|
|
|
// successfully acquires its own write lock
|
2023-10-14 21:50:11 -04:00
|
|
|
pub async fn add_transaction(&self, tx: T) -> Result<bool, TransactionError> {
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
let tx = Transaction::Application(tx);
|
2023-04-13 18:43:03 -04:00
|
|
|
let mut to_broadcast = vec![TRANSACTION_MESSAGE];
|
|
|
|
|
tx.write(&mut to_broadcast).unwrap();
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
let res = self.network.blockchain.write().await.add_transaction::<TendermintNetwork<D, T, P>>(
|
|
|
|
|
true,
|
|
|
|
|
tx,
|
2023-12-17 00:01:41 -05:00
|
|
|
&self.network.signature_scheme(),
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
);
|
2023-10-14 21:50:11 -04:00
|
|
|
if res == Ok(true) {
|
2023-04-23 16:56:23 -04:00
|
|
|
self.network.p2p.broadcast(self.genesis, to_broadcast).await;
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 05:01:19 -04:00
|
|
|
async fn sync_block_internal(
|
|
|
|
|
&self,
|
|
|
|
|
block: Block<T>,
|
|
|
|
|
commit: Vec<u8>,
|
|
|
|
|
result: &mut UnboundedReceiver<bool>,
|
|
|
|
|
) -> bool {
|
2023-04-13 18:43:03 -04:00
|
|
|
let (tip, block_number) = {
|
2023-04-23 23:15:15 -04:00
|
|
|
let blockchain = self.network.blockchain.read().await;
|
2023-04-13 18:43:03 -04:00
|
|
|
(blockchain.tip(), blockchain.block_number())
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if block.header.parent != tip {
|
2023-04-24 02:44:21 -04:00
|
|
|
log::debug!("told to sync a block whose parent wasn't our tip");
|
2023-04-13 18:43:03 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let block = TendermintBlock(block.serialize());
|
2023-05-09 23:45:05 -04:00
|
|
|
let mut commit_ref = commit.as_ref();
|
|
|
|
|
let Ok(commit) = Commit::<Arc<Validators>>::decode(&mut commit_ref) else {
|
2023-04-24 02:44:21 -04:00
|
|
|
log::error!("sent an invalidly serialized commit");
|
2023-04-13 18:43:03 -04:00
|
|
|
return false;
|
|
|
|
|
};
|
2023-05-09 23:45:05 -04:00
|
|
|
// Storage DoS vector. We *could* truncate to solely the relevant portion, trying to save this,
|
|
|
|
|
// yet then we'd have to test the truncation was performed correctly.
|
|
|
|
|
if !commit_ref.is_empty() {
|
|
|
|
|
log::error!("sent an commit with additional data after it");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-04-13 18:43:03 -04:00
|
|
|
if !self.network.verify_commit(block.id(), &commit) {
|
2023-04-24 02:44:21 -04:00
|
|
|
log::error!("sent an invalid commit");
|
2023-04-13 18:43:03 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-05 11:50:55 +03:00
|
|
|
let number = BlockNumber(block_number + 1);
|
2023-08-27 05:01:19 -04:00
|
|
|
self.synced_block.write().await.send(SyncedBlock { number, block, commit }).await.unwrap();
|
2023-04-24 02:44:21 -04:00
|
|
|
result.next().await.unwrap()
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
|
2023-08-27 05:01:19 -04:00
|
|
|
// Sync a block.
|
|
|
|
|
// TODO: Since we have a static validator set, we should only need the tail commit?
|
|
|
|
|
pub async fn sync_block(&self, block: Block<T>, commit: Vec<u8>) -> bool {
|
|
|
|
|
let mut result = self.synced_block_result.write().await;
|
|
|
|
|
self.sync_block_internal(block, commit, &mut result).await
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-13 18:43:03 -04:00
|
|
|
// Return true if the message should be rebroadcasted.
|
2023-08-27 05:01:19 -04:00
|
|
|
pub async fn handle_message(&self, msg: &[u8]) -> bool {
|
2023-04-22 10:49:52 -04:00
|
|
|
match msg.first() {
|
|
|
|
|
Some(&TRANSACTION_MESSAGE) => {
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
let Ok(tx) = Transaction::read::<&[u8]>(&mut &msg[1 ..]) else {
|
2023-04-22 10:49:52 -04:00
|
|
|
log::error!("received invalid transaction message");
|
2023-04-13 18:43:03 -04:00
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// TODO: Sync mempools with fellow peers
|
|
|
|
|
// Can we just rebroadcast transactions not included for at least two blocks?
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
let res =
|
|
|
|
|
self.network.blockchain.write().await.add_transaction::<TendermintNetwork<D, T, P>>(
|
|
|
|
|
false,
|
|
|
|
|
tx,
|
2023-12-17 00:01:41 -05:00
|
|
|
&self.network.signature_scheme(),
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
);
|
2023-10-14 21:50:11 -04:00
|
|
|
log::debug!("received transaction message. valid new transaction: {res:?}");
|
|
|
|
|
res == Ok(true)
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-22 10:49:52 -04:00
|
|
|
Some(&TENDERMINT_MESSAGE) => {
|
2023-08-01 00:47:36 -04:00
|
|
|
let Ok(msg) =
|
|
|
|
|
SignedMessageFor::<TendermintNetwork<D, T, P>>::decode::<&[u8]>(&mut &msg[1 ..])
|
|
|
|
|
else {
|
2023-04-22 10:49:52 -04:00
|
|
|
log::error!("received invalid tendermint message");
|
2023-04-13 18:43:03 -04:00
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-23 16:56:23 -04:00
|
|
|
self.messages.write().await.send(msg).await.unwrap();
|
2023-04-22 10:49:52 -04:00
|
|
|
false
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-25 23:11:36 -04:00
|
|
|
|
|
|
|
|
/// Get a Future which will resolve once the next block has been added.
|
|
|
|
|
pub async fn next_block_notification(
|
|
|
|
|
&self,
|
|
|
|
|
) -> impl Send + Sync + core::future::Future<Output = Result<(), impl Send + Sync>> {
|
|
|
|
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
|
|
|
|
self.network.blockchain.write().await.next_block_notifications.push_back(tx);
|
|
|
|
|
rx
|
|
|
|
|
}
|
2023-04-13 18:43:03 -04:00
|
|
|
}
|
2023-04-24 06:50:40 -04:00
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
Slash malevolent validators (#294)
* add slash tx
* ignore unsigned tx replays
* verify that provided evidence is valid
* fix clippy + fmt
* move application tx handling to another module
* partially handle the tendermint txs
* fix pr comments
* support unsigned app txs
* add slash target to the votes
* enforce provided, unsigned, signed tx ordering within a block
* bug fixes
* add unit test for tendermint txs
* bug fixes
* update tests for tendermint txs
* add tx ordering test
* tidy up tx ordering test
* cargo +nightly fmt
* Misc fixes from rebasing
* Finish resolving clippy
* Remove sha3 from tendermint-machine
* Resolve a DoS in SlashEvidence's read
Also moves Evidence from Vec<Message> to (Message, Option<Message>). That
should meet all requirements while being a bit safer.
* Make lazy_static a dev-depend for tributary
* Various small tweaks
One use of sort was inefficient, sorting unsigned || signed when unsigned was
already properly sorted. Given how the unsigned TXs were given a nonce of 0, an
unstable sort may swap places with an unsigned TX and a signed TX with a nonce
of 0 (leading to a faulty block).
The extra protection added here sorts signed, then concats.
* Fix Tributary tests I broke, start review on tendermint/tx.rs
* Finish reviewing everything outside tests and empty_signature
* Remove empty_signature
empty_signature led to corrupted local state histories. Unfortunately, the API
is only sane with a signature.
We now use the actual signature, which risks creating a signature over a
malicious message if we have ever have an invariant producing malicious
messages. Prior, we only signed the message after the local machine confirmed
it was okay per the local view of consensus.
This is tolerated/preferred over a corrupt state history since production of
such messages is already an invariant. TODOs are added to make handling of this
theoretical invariant further robust.
* Remove async_sequential for tokio::test
There was no competition for resources forcing them to be run sequentially.
* Modify block order test to be statistically significant without multiple runs
* Clean tests
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-08-21 07:28:23 +03:00
|
|
|
pub struct TributaryReader<D: Db, T: TransactionTrait>(D, [u8; 32], PhantomData<T>);
|
|
|
|
|
impl<D: Db, T: TransactionTrait> TributaryReader<D, T> {
|
2023-04-24 06:50:40 -04:00
|
|
|
pub fn genesis(&self) -> [u8; 32] {
|
|
|
|
|
self.1
|
|
|
|
|
}
|
2023-09-25 17:15:36 -04:00
|
|
|
|
|
|
|
|
// Since these values are static once set, they can be safely read from the database without lock
|
2023-04-24 06:50:40 -04:00
|
|
|
// acquisition
|
|
|
|
|
pub fn block(&self, hash: &[u8; 32]) -> Option<Block<T>> {
|
|
|
|
|
Blockchain::<D, T>::block_from_db(&self.0, self.1, hash)
|
|
|
|
|
}
|
|
|
|
|
pub fn commit(&self, hash: &[u8; 32]) -> Option<Vec<u8>> {
|
|
|
|
|
Blockchain::<D, T>::commit_from_db(&self.0, self.1, hash)
|
|
|
|
|
}
|
|
|
|
|
pub fn parsed_commit(&self, hash: &[u8; 32]) -> Option<Commit<Validators>> {
|
|
|
|
|
self.commit(hash).map(|commit| Commit::<Validators>::decode(&mut commit.as_ref()).unwrap())
|
|
|
|
|
}
|
|
|
|
|
pub fn block_after(&self, hash: &[u8; 32]) -> Option<[u8; 32]> {
|
|
|
|
|
Blockchain::<D, T>::block_after(&self.0, self.1, hash)
|
|
|
|
|
}
|
|
|
|
|
pub fn time_of_block(&self, hash: &[u8; 32]) -> Option<u64> {
|
|
|
|
|
self
|
|
|
|
|
.commit(hash)
|
|
|
|
|
.map(|commit| Commit::<Validators>::decode(&mut commit.as_ref()).unwrap().end_time)
|
|
|
|
|
}
|
2023-09-25 17:15:36 -04:00
|
|
|
|
2023-10-14 02:45:47 +03:00
|
|
|
pub fn locally_provided_txs_in_block(&self, hash: &[u8; 32], order: &str) -> bool {
|
|
|
|
|
Blockchain::<D, T>::locally_provided_txs_in_block(&self.0, &self.1, hash, order)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-25 17:15:36 -04:00
|
|
|
// This isn't static, yet can be read with only minor discrepancy risks
|
|
|
|
|
pub fn tip(&self) -> [u8; 32] {
|
|
|
|
|
Blockchain::<D, T>::tip_from_db(&self.0, self.1)
|
|
|
|
|
}
|
2023-04-24 06:50:40 -04:00
|
|
|
}
|