Skip to content

Commit

Permalink
feat: Versionable CompressedCoin (FuelLabs#1628)
Browse files Browse the repository at this point in the history
Related issues:
- FuelLabs#1552
  • Loading branch information
Brandon Vrooman authored Jan 26, 2024
1 parent 79c8c8d commit 2eaa6d4
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 141 deletions.
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ Description of the upcoming release here.
- [#1601](https://github.com/FuelLabs/fuel-core/pull/1601): Fix formatting in docs and check that `cargo doc` passes in the CI.

#### Breaking
- [#1616](https://github.com/FuelLabs/fuel-core/pull/1616) Make `BlockHeader` type a version-able enum
- [#1614](https://github.com/FuelLabs/fuel-core/pull/#1614): Use the default consensus key regardless of trigger mode. The change is breaking because it removes the `--dev-keys` argument. If the `debug` flag is set, the default consensus key will be used, regardless of the trigger mode.
- [#1596](https://github.com/FuelLabs/fuel-core/pull/1596) Make `Consensus` type a version-able enum
- [#1593](https://github.com/FuelLabs/fuel-core/pull/1593) Make `Block` type a version-able enum
- [#1628](https://github.com/FuelLabs/fuel-core/pull/1628): Make `CompressedCoin` type a version-able enum
- [#1616](https://github.com/FuelLabs/fuel-core/pull/1616): Make `BlockHeader` type a version-able enum
- [#1614](https://github.com/FuelLabs/fuel-core/pull/1614): Use the default consensus key regardless of trigger mode. The change is breaking because it removes the `--dev-keys` argument. If the `debug` flag is set, the default consensus key will be used, regardless of the trigger mode.
- [#1596](https://github.com/FuelLabs/fuel-core/pull/1596): Make `Consensus` type a version-able enum
- [#1593](https://github.com/FuelLabs/fuel-core/pull/1593): Make `Block` type a version-able enum
- [#1576](https://github.com/FuelLabs/fuel-core/pull/1576): The change moves the implementation of the storage traits for required tables from `fuel-core` to `fuel-core-storage` crate. The change also adds a more flexible configuration of the encoding/decoding per the table and allows the implementation of specific behaviors for the table in a much easier way. It unifies the encoding between database, SMTs, and iteration, preventing mismatching bytes representation on the Rust type system level. Plus, it increases the re-usage of the code by applying the same blueprint to other tables.

It is a breaking PR because it changes database encoding/decoding for some tables.
Expand Down
12 changes: 5 additions & 7 deletions crates/chain-config/src/config/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,11 @@ pub struct CoinConfig {

impl GenesisCommitment for CompressedCoin {
fn root(&self) -> anyhow::Result<MerkleRoot> {
let Self {
owner,
amount,
asset_id,
maturity,
tx_pointer,
} = self;
let owner = self.owner();
let amount = self.amount();
let asset_id = self.asset_id();
let maturity = self.maturity();
let tx_pointer = self.tx_pointer();

let coin_hash = *Hasher::default()
.chain(owner)
Expand Down
11 changes: 4 additions & 7 deletions crates/fuel-core/src/coins_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,13 +950,10 @@ mod tests {
self.last_coin_index += 1;

let id = UtxoId::new(Bytes32::from([0u8; 32]), index.try_into().unwrap());
let coin = CompressedCoin {
owner,
amount,
asset_id,
maturity: Default::default(),
tx_pointer: Default::default(),
};
let mut coin = CompressedCoin::default();
coin.set_owner(owner);
coin.set_amount(amount);
coin.set_asset_id(asset_id);

let db = &mut self.database;
StorageMutate::<Coins>::insert(db, &id, &coin).unwrap();
Expand Down
16 changes: 8 additions & 8 deletions crates/fuel-core/src/database/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl StorageMutate<Coins> for Database {
key: &UtxoId,
value: &CompressedCoin,
) -> Result<Option<CompressedCoin>, Self::Error> {
let coin_by_owner = owner_coin_id_key(&value.owner, key);
let coin_by_owner = owner_coin_id_key(value.owner(), key);
// insert primary record
let insert = self.data.storage_as_mut::<Coins>().insert(key, value)?;
// insert secondary index by owner
Expand All @@ -92,7 +92,7 @@ impl StorageMutate<Coins> for Database {

// cleanup secondary index
if let Some(coin) = &coin {
let key = owner_coin_id_key(&coin.owner, key);
let key = owner_coin_id_key(coin.owner(), key);
self.storage_as_mut::<OwnedCoins>().remove(&key)?;
}

Expand Down Expand Up @@ -142,12 +142,12 @@ impl Database {
Ok(CoinConfig {
tx_id: Some(*utxo_id.tx_id()),
output_index: Some(utxo_id.output_index()),
tx_pointer_block_height: Some(coin.tx_pointer.block_height()),
tx_pointer_tx_idx: Some(coin.tx_pointer.tx_index()),
maturity: Some(coin.maturity),
owner: coin.owner,
amount: coin.amount,
asset_id: coin.asset_id,
tx_pointer_block_height: Some(coin.tx_pointer().block_height()),
tx_pointer_tx_idx: Some(coin.tx_pointer().tx_index()),
maturity: Some(*coin.maturity()),
owner: *coin.owner(),
amount: *coin.amount(),
asset_id: *coin.asset_id(),
})
})
.collect::<StorageResult<Vec<CoinConfig>>>()?;
Expand Down
117 changes: 40 additions & 77 deletions crates/fuel-core/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1248,32 +1248,20 @@ mod tests {
.clone();

let first_input = tx2.inputs()[0].clone();
let mut first_coin = CompressedCoin::default();
first_coin.set_owner(*first_input.input_owner().unwrap());
first_coin.set_amount(100);
let second_input = tx2.inputs()[1].clone();
let mut second_coin = CompressedCoin::default();
second_coin.set_owner(*second_input.input_owner().unwrap());
second_coin.set_amount(100);
let db = &mut Database::default();
// Insert both inputs
db.storage::<Coins>()
.insert(
&first_input.utxo_id().unwrap().clone(),
&CompressedCoin {
owner: *first_input.input_owner().unwrap(),
amount: 100,
asset_id: AssetId::default(),
maturity: Default::default(),
tx_pointer: Default::default(),
},
)
.insert(&first_input.utxo_id().unwrap().clone(), &first_coin)
.unwrap();
db.storage::<Coins>()
.insert(
&second_input.utxo_id().unwrap().clone(),
&CompressedCoin {
owner: *second_input.input_owner().unwrap(),
amount: 100,
asset_id: AssetId::default(),
maturity: Default::default(),
tx_pointer: Default::default(),
},
)
.insert(&second_input.utxo_id().unwrap().clone(), &second_coin)
.unwrap();
let executor = create_executor(
db.clone(),
Expand Down Expand Up @@ -1342,20 +1330,14 @@ mod tests {
.clone();

let input = tx.inputs()[0].clone();
let mut coin = CompressedCoin::default();
coin.set_owner(*input.input_owner().unwrap());
coin.set_amount(AMOUNT - 1);
let db = &mut Database::default();

// Inserting a coin with `AMOUNT - 1` should cause a mismatching error during production.
db.storage::<Coins>()
.insert(
&input.utxo_id().unwrap().clone(),
&CompressedCoin {
owner: *input.input_owner().unwrap(),
amount: AMOUNT - 1,
asset_id: AssetId::default(),
maturity: Default::default(),
tx_pointer: Default::default(),
},
)
.insert(&input.utxo_id().unwrap().clone(), &coin)
.unwrap();
let executor = create_executor(
db.clone(),
Expand Down Expand Up @@ -1405,19 +1387,13 @@ mod tests {
.clone();

let input = tx.inputs()[1].clone();
let mut coin = CompressedCoin::default();
coin.set_owner(*input.input_owner().unwrap());
coin.set_amount(100);
let db = &mut Database::default();

db.storage::<Coins>()
.insert(
&input.utxo_id().unwrap().clone(),
&CompressedCoin {
owner: *input.input_owner().unwrap(),
amount: 100,
asset_id: AssetId::default(),
maturity: Default::default(),
tx_pointer: Default::default(),
},
)
.insert(&input.utxo_id().unwrap().clone(), &coin)
.unwrap();
let executor = create_executor(
db.clone(),
Expand Down Expand Up @@ -1979,18 +1955,12 @@ mod tests {
..
}) = tx.inputs()[0]
{
db.storage::<Coins>()
.insert(
&utxo_id,
&CompressedCoin {
owner,
amount,
asset_id,
maturity: Default::default(),
tx_pointer: TxPointer::new(starting_block, starting_block_tx_idx),
},
)
.unwrap();
let mut coin = CompressedCoin::default();
coin.set_owner(owner);
coin.set_amount(amount);
coin.set_asset_id(asset_id);
coin.set_tx_pointer(TxPointer::new(starting_block, starting_block_tx_idx));
db.storage::<Coins>().insert(&utxo_id, &coin).unwrap();
}

let executor = create_executor(
Expand Down Expand Up @@ -2219,7 +2189,7 @@ mod tests {
let maybe_utxo = database.storage::<Coins>().get(&id).unwrap();
assert!(maybe_utxo.is_some());
let utxo = maybe_utxo.unwrap();
assert!(utxo.amount > 0)
assert!(*utxo.amount() > 0)
}
_ => (),
}
Expand Down Expand Up @@ -2397,10 +2367,10 @@ mod tests {
.message_is_spent(&message_data.nonce)
.unwrap());
assert_eq!(
block_db_transaction
*block_db_transaction
.coin(&UtxoId::new(tx_id, 0))
.unwrap()
.amount,
.amount(),
amount + amount
);
}
Expand Down Expand Up @@ -2460,10 +2430,10 @@ mod tests {
.message_is_spent(&message_data.nonce)
.unwrap());
assert_eq!(
block_db_transaction
*block_db_transaction
.coin(&UtxoId::new(tx_id, 0))
.unwrap()
.amount,
.amount(),
amount
);
}
Expand Down Expand Up @@ -2727,18 +2697,15 @@ mod tests {
// setup db with coin to spend
let database = &mut &mut Database::default();
let coin_input = &tx.inputs()[0];
let mut coin = CompressedCoin::default();
coin.set_owner(*coin_input.input_owner().unwrap());
coin.set_amount(coin_input.amount().unwrap());
coin.set_asset_id(*coin_input.asset_id(&base_asset_id).unwrap());
coin.set_maturity(coin_input.maturity().unwrap());
coin.set_tx_pointer(TxPointer::new(Default::default(), block_tx_idx));
database
.storage::<Coins>()
.insert(
coin_input.utxo_id().unwrap(),
&CompressedCoin {
owner: *coin_input.input_owner().unwrap(),
amount: coin_input.amount().unwrap(),
asset_id: *coin_input.asset_id(&base_asset_id).unwrap(),
maturity: coin_input.maturity().unwrap(),
tx_pointer: TxPointer::new(Default::default(), block_tx_idx),
},
)
.insert(coin_input.utxo_id().unwrap(), &coin)
.unwrap();

// make executor with db
Expand Down Expand Up @@ -2802,18 +2769,14 @@ mod tests {
// setup db with coin to spend
let database = &mut &mut Database::default();
let coin_input = &tx.inputs()[0];
let mut coin = CompressedCoin::default();
coin.set_owner(*coin_input.input_owner().unwrap());
coin.set_amount(coin_input.amount().unwrap());
coin.set_asset_id(*coin_input.asset_id(&base_asset_id).unwrap());
coin.set_maturity(coin_input.maturity().unwrap());
database
.storage::<Coins>()
.insert(
coin_input.utxo_id().unwrap(),
&CompressedCoin {
owner: *coin_input.input_owner().unwrap(),
amount: coin_input.amount().unwrap(),
asset_id: *coin_input.asset_id(&base_asset_id).unwrap(),
maturity: coin_input.maturity().unwrap(),
tx_pointer: TxPointer::default(),
},
)
.insert(coin_input.utxo_id().unwrap(), &coin)
.unwrap();

// make executor with db
Expand Down
22 changes: 16 additions & 6 deletions crates/fuel-core/src/service/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ use fuel_core_types::{
SealedBlock,
},
entities::{
coins::coin::CompressedCoin,
coins::coin::{
CompressedCoin,
CompressedCoinV1,
},
contract::ContractUtxoInfo,
message::Message,
},
Expand Down Expand Up @@ -181,7 +184,7 @@ fn init_coin_state(
}),
);

let coin = CompressedCoin {
let compressed_coin: CompressedCoin = CompressedCoinV1 {
owner: coin.owner,
amount: coin.amount,
asset_id: coin.asset_id,
Expand All @@ -190,19 +193,26 @@ fn init_coin_state(
coin.tx_pointer_block_height.unwrap_or_default(),
coin.tx_pointer_tx_idx.unwrap_or_default(),
),
};
}
.into();

// ensure coin can't point to blocks in the future
if coin.tx_pointer.block_height() > state.height.unwrap_or_default() {
if compressed_coin.tx_pointer().block_height()
> state.height.unwrap_or_default()
{
return Err(anyhow!(
"coin tx_pointer height cannot be greater than genesis block"
))
}

if db.storage::<Coins>().insert(&utxo_id, &coin)?.is_some() {
if db
.storage::<Coins>()
.insert(&utxo_id, &compressed_coin)?
.is_some()
{
return Err(anyhow!("Coin should not exist"))
}
coins_tree.push(coin.root()?.as_slice())
coins_tree.push(compressed_coin.root()?.as_slice())
}
}
}
Expand Down
Loading

0 comments on commit 2eaa6d4

Please sign in to comment.