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

DA compression for fuel-vm types #670

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open

Conversation

Dentosal
Copy link
Member

@Dentosal Dentosal commented Feb 1, 2024

See correspoing fuel-core PR as well: FuelLabs/fuel-core#1609

This PR adds Compact derive macro and fuel-compression machinery, that are used to convert Transaction and contained types into CompactTransaction and Compact*. The compact types are equivalent to the original types, except that malleable fields are removed, and often-repeated types like AssetId and Address are converted to three-byte keys to a separate database, called temporal storage. See the contained fuel-compression/README.md for an extended description.

@Dentosal Dentosal added fuel-types Related to the `fuel-types` crate. mainnet labels Feb 1, 2024
@Dentosal Dentosal self-assigned this Feb 1, 2024
@xgreenx xgreenx requested a review from a team February 19, 2024 18:11
Copy link
Collaborator

@xgreenx xgreenx left a comment

Choose a reason for hiding this comment

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

Thank you nice PR!=) It is cool that Compact can be derived almost for all types.

I feel like we put too many details about the implementation of the algorithm and how keys are created, and it seems we can simplify that part a lot to be agnostic. But the main with compaction looks good; I will review it one more time, more precisely when PR is in final shape.

BTW, compilation fails for me:

image

let start: Key<T> = self.start_keys.value();
let end: Key<T> = self.safe_keys_start.value();
// Check if the value is in the possibly-overwritable range
if !key.is_between(start, end) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What if the key is not in the range but at the beginning of the whole range, for example, zero? You will overflow the end and may also overwrite it.

Copy link
Member Author

Choose a reason for hiding this comment

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

(that code is now test only)

The overflow should work correctly in that case. I should probably add a test case showing that it actually works.

{
type Compact = ArrayWrapper<S, T::Compact>;

fn count(&self) -> CountPerTable {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we want to have a separate implementation for bytes later to be more performance?

Copy link
Member Author

Choose a reason for hiding this comment

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

This fully monomorphizes. Zero-cost abstraction.

if v == needle {
return Some(key);
}
key = key.next();
Copy link
Collaborator

Choose a reason for hiding this comment

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

How do we know that it will not overflow?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's allowed to overflow. Wrapping around is the expected behavior.

fuel-compression/src/registry/mod.rs Outdated Show resolved Hide resolved
pub sender: Address,
/// The receiver on the `Fuel` chain.
#[cfg_attr(feature = "da-compression", da_compress(registry = "Address"))]
pub recipient: Address,
pub amount: Word,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can skip amount since it is restorable informaiton

Copy link
Member Author

Choose a reason for hiding this comment

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

Because we can find get from L1 message?

fuel-tx/src/transaction/types/input/message.rs Outdated Show resolved Hide resolved
fuel-tx/src/transaction/types/output.rs Outdated Show resolved Hide resolved
@@ -20,6 +20,7 @@ use rand::{
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "da-compression", derive(fuel_compression::Compact))]
#[derive(fuel_types::canonical::Deserialize, fuel_types::canonical::Serialize)]
pub struct UtxoId {
Copy link
Collaborator

Choose a reason for hiding this comment

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

If I remember correctly, we agreed on replacing UtxoId with TxPointer. Do you plan to do that during this PR or not?

Copy link
Member Author

@Dentosal Dentosal Mar 8, 2024

Choose a reason for hiding this comment

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

I'm not planning to do that here, since that's separate from the BiggerType -> Key separation I'm trying to achieve in the PR. Maybe I'll add it here if I can refactor like this #670 (comment)

{
/// Reverse lookup.
/// TODO: possibly add a lookup table for this, if deemed necessary
pub fn lookup_value(&self, needle: &T::Type) -> Option<Key<T>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we put too much business logic here with overflowing and counters. I feel like it should be part of the fuel-core while fuel-compression is responsible only for iterating over the fields and calling next_key::<Table>(value). The type that implements next_key may be decided in which way he wants to do that.

The count function also sounds like something related to the exact algorithm implementation.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree; if I can get the logic separated it would be really nice. I'll look into it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've been trying to figure out what parts could be moved out of fuel-vm. Most of the algorithm implementation, including this whole file, can probably be transferred.

The typed keys have to remain here, as the proc macro cannot be generic over key type. This means the implementation of Key has to live here.

The count function of the trait also has to live here. The only way to obtain the number of keys in an entity must be part of the trait. While all key allocation algorithms might not use it, many of the sensible ones do.

Copy link
Contributor

@bvrooman bvrooman left a comment

Choose a reason for hiding this comment

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

Reviewed 6/41 so far, will continue review at the next chance I get

fuel-compression/src/compaction.rs Outdated Show resolved Hide resolved
fuel-compression/src/compaction.rs Outdated Show resolved Hide resolved
fuel-compression/src/compaction.rs Show resolved Hide resolved
@Dentosal Dentosal marked this pull request as ready for review July 22, 2024 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fuel-types Related to the `fuel-types` crate. mainnet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants