Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Message conditions #430

Merged
merged 3 commits into from
Mar 20, 2024
Merged

Message conditions #430

merged 3 commits into from
Mar 20, 2024

Conversation

arvidn
Copy link
Contributor

@arvidn arvidn commented Mar 11, 2024

Overview

This PR implements the message condition codes as described by CHIP-25.

Enable/disable

Support for these new conditions is disabled by default, and only enabled by passing in the ENABLE_MESSAGE_CONDITIONS flag. (the enable/disable logic is implemented in crates/chia-consensus/src/gen/opcodes.rs).

Error codes

There are 3 new error codes introduced by this PR. These will need to be added to chia-blockchain as well.

ErrorCode::InvalidMessageMode => 145,
ErrorCode::InvalidCoinId => 146,
ErrorCode::MessageNotSentOrReceived => 147,

Deferred memory allocation

Since there's no CLVM cost associated with these new conditions, we need to be careful to mitigate abuse in the form of DoS attacks. When a message is sent or received, we record as little information as possible up front, to resolve later, after all spends has been executed.

Each message has a mask indicating which attributes of itself to take into account. We don't need to store those attributes in the message, just the mask.

Each message also specifies the attributes of the other end of the message (if you're the sender, you specify the receiver's attributes and vice versa). These attributes do need to be stored in the message. To avoid memory allocation, only the NodePtr are stored. This is encapsulated in the SpendId enum(incrates/chia-consensus/src/gen/messages.rs`).

Each message has a message NodePtr, a mask identifying its own properties to take into account and a SpendId indentifying the other end's properties.

When it's time to validate all messages, we turn each message into a key and increment (send message) and decrement (receive message) a counter for each key. At the end we ensure that all counters are 0. This is implemented at the end of the validate_conditions() function.

The key generation is where we actually allocate. It's generated in such a way that when the self-attributes matches the parsed-attributes, they are identical. This is how senders and receivers match up. See SpendId::make_key() in crates/chia-consensus/src/gen/messages.rs.

The justification of avoiding and deferring memory allocation is that one of the most expensive stress tests we have is duplicate-coin-announce.txt which takes almost 3 seconds to run. Avoiding the copying of the coin ID (and message) was a material speed-up in earlier tests.

fast-forward

Spends that send a message that's identified by their parent ID are not eligible for fast forward. Likewise, spends receiving a message identified by their own parent ID are also not eligible for fast forward. This includes messages identified by their coin ID, since the parent ID is part of that.

deduplication

Spends that send or receive messages are not eligible for de-duplication. De-duplicating such spend would leave the other end of the message dangling. This has some false negatives. Specifically for coins sending a message to itself. It would be safe to de-duplicate such spend, but it's more complicated to carve out that special case. Maybe we can do that in the future if we encounter a use case.

Testing

There are a large number of test cases in crates/chia-consensus/src/gen/conditions.rs.

test_message_strict_args_count() makes sure we allow unknown additional parameters, unless STRICT_ARGS_COUNT is set (i.e. mempool mode)

test_message_conditions_single_spend() has test cases where a single spend sends a message to itself. Some valid in mempool mode, some not.

test_limit_messages() ensures that the 1024 limit applies to these new conditions, just like it does to the existing create announcement and assert announcement.

test_message_conditions_failures() ensures parse failures are correctly caught and yields the expected error code.

test_message_conditions_two_spends() has test cases where one spend sends a message to another spend.

test_all_message_conditions() programatically generates all combinations of messages that can be sent from one spend to another. These are only positive tests.

test_message_eligible_for_ff() tests all combinations of messages between coins where one coin is eligible for fast-forward. The test ensures that it remains eligible as long as its parent ID is not committed to by the message (both by sending or receiving a message).

Fuzzing

The SpendId::parse() has a fuzzing driver and the parse-conditions was extended to enable the message conditions.

TODO

  • Figure out under what circumstances should spends be eligible for fast-forward and dedup. There should probably be more thorough tests and more deliberate logic for this
  • implement stress tests and attempts to flood these messages to ensure the implementation doesn't fall over (I will update the stress tests in a separate PR)

Copy link

coveralls-official bot commented Mar 11, 2024

Pull Request Test Coverage Report for Build 8356147310

Details

  • 555 of 571 (97.2%) changed or added relevant lines in 6 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.5%) to 85.554%

Changes Missing Coverage Covered Lines Changed/Added Lines %
crates/chia-consensus/src/gen/validation_error.rs 0 3 0.0%
crates/chia-consensus/src/gen/messages.rs 143 147 97.28%
crates/chia-consensus/src/gen/conditions.rs 355 364 97.53%
Totals Coverage Status
Change from base Build 8333202033: 0.5%
Covered Lines: 11643
Relevant Lines: 13609

💛 - Coveralls

Copy link
Contributor

@Rigidity Rigidity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few small things

crates/chia-consensus/fuzz/fuzz_targets/parse-spend-id.rs Outdated Show resolved Hide resolved
crates/chia-consensus/src/gen/messages.rs Show resolved Hide resolved
crates/chia-consensus/src/gen/messages.rs Show resolved Hide resolved
Copy link
Contributor

@Rigidity Rigidity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@arvidn arvidn merged commit 36f6787 into main Mar 20, 2024
64 checks passed
@arvidn arvidn deleted the message-conditions branch March 20, 2024 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants