Skip to content

Commit

Permalink
feat: AccountUpdateDetails::merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Mirko-von-Leipzig committed Jul 17, 2024
1 parent 5b121e3 commit 89d9123
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
31 changes: 31 additions & 0 deletions objects/src/accounts/delta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ impl AccountDelta {
Ok(Self { storage, vault, nonce })
}

/// Merge another [AccountDelta] into this one.
pub fn merge(self, other: Self) -> Result<Self, AccountDeltaError> {
// Incoming nonce takes precedence.
let nonce = other.nonce.or(self.nonce);
let storage = self.storage.merge(other.storage);
let vault = self.vault.merge(other.vault);
Self::new(storage, vault, nonce)
}

// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -104,6 +113,28 @@ impl AccountUpdateDetails {
pub fn is_private(&self) -> bool {
matches!(self, Self::Private)
}

/// Merges the `other` update into this one.
///
/// This account update is assumed to come before the other.
pub fn merge(self, other: AccountUpdateDetails) -> Result<Self, AccountDeltaError> {
let merged_update = match (self, other) {
(AccountUpdateDetails::Private, AccountUpdateDetails::Private) => {
AccountUpdateDetails::Private
},
(AccountUpdateDetails::New(mut account), AccountUpdateDetails::Delta(delta)) => {
account.apply_delta(&delta).unwrap();

AccountUpdateDetails::New(account)
},
(AccountUpdateDetails::Delta(initial), AccountUpdateDetails::Delta(new_delta)) => {
AccountUpdateDetails::Delta(initial.merge(new_delta)?)
},
_ => todo!("Illegal combination error"),
};

Ok(merged_update)
}
}

// SERIALIZATION
Expand Down
28 changes: 28 additions & 0 deletions objects/src/accounts/delta/storage.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use alloc::{string::ToString, vec::Vec};

use super::{
Expand Down Expand Up @@ -40,6 +42,32 @@ impl AccountStorageDelta {
}
}

/// Merges another delta into this one, overwriting any existing values.
pub fn merge(self, other: Self) -> Self {
let items =
self.cleared_items
.into_iter()
.map(|slot| (slot, None))
.chain(self.updated_items.into_iter().map(|(slot, value)| (slot, Some(value))))
.chain(other.cleared_items.into_iter().map(|slot| (slot, None)).chain(
other.updated_items.into_iter().map(|(slot, value)| (slot, Some(value))),
))
.collect::<HashMap<_, _>>();

let cleared_items = items
.iter()
.filter_map(|(slot, value)| value.is_none().then_some(*slot))
.collect();
let updated_items =
items.iter().filter_map(|(slot, value)| value.map(|v| (*slot, v))).collect();

Self {
cleared_items,
updated_items,
updated_maps: todo!(),
}
}

/// Checks whether this storage delta is valid.
///
/// # Errors
Expand Down
28 changes: 28 additions & 0 deletions objects/src/accounts/delta/vault.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use alloc::{string::ToString, vec::Vec};

use super::{
Expand Down Expand Up @@ -37,6 +39,32 @@ impl AccountVaultDelta {
}
}

/// Merges another delta into this one, overwriting any existing values.
pub fn merge(self, other: Self) -> Self {
// Collec the assets into a hashmap where true indicates added, and false removed.
// This lets us simplify the addition/removal dance we would otherwise have to go through.
//
// Ordering matters. Since later items will overwrite earlier ones we need to begin
// with self, then other.
let assets = self
.added_assets
.into_iter()
.map(|asset| (asset, true))
.chain(self.removed_assets.into_iter().map(|asset| (asset, true)))
.chain(other.added_assets.into_iter().map(|asset| (asset, false)))
.chain(other.removed_assets.into_iter().map(|asset| (asset, false)))
.collect::<HashMap<_, _>>();

let added = assets
.iter()
.filter_map(|(asset, was_added)| was_added.then_some(asset.clone()));
let removed = assets
.iter()
.filter_map(|(asset, was_added)| (!was_added).then_some(asset.clone()));

Self::from_iterators(added, removed)
}

/// Checks whether this vault delta is valid.
///
/// # Errors
Expand Down

0 comments on commit 89d9123

Please sign in to comment.