Skip to content

Commit

Permalink
Remove optional fields from configs (#1740)
Browse files Browse the repository at this point in the history
Closes #1668

Removes optional fields from coin and contract configs. 
Added the `CoinConfigGenerator` to enable easier setup of coin configs
for testing. It holds an internal counter that's used to init the
`tx_id` and `output_index`.

A caveat is that we have to be careful when creating coins/contracts in
unit tests. If we use default values for `tx_id` there could be
overlapping utxos and the node setup will fail. Care also needs to be
applied if tests setup configs from multiple sources.

---------

Co-authored-by: xgreenx <xgreenx9999@gmail.com>
  • Loading branch information
MujkicA and xgreenx committed Mar 7, 2024
1 parent a7eec76 commit 4110889
Show file tree
Hide file tree
Showing 26 changed files with 324 additions and 421 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- [#1740](https://github.com/FuelLabs/fuel-core/pull/1740): Remove optional fields from genesis configs
- [#1737](https://github.com/FuelLabs/fuel-core/pull/1737): Remove temporary tables for calculating roots during genesis.
- [#1731](https://github.com/FuelLabs/fuel-core/pull/1731): Expose `schema.sdl` from `fuel-core-client`.

Expand Down
6 changes: 1 addition & 5 deletions benches/benches/vm_initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use fuel_core_types::{
Output,
Script,
Transaction,
Word,
},
fuel_types::canonical::Serialize,
fuel_vm::{
Expand Down Expand Up @@ -65,10 +64,7 @@ fn transaction<R: Rng>(
1_000_000,
script,
script_data,
Policies::new()
.with_max_fee(0)
.with_maturity(0.into())
.with_max_fee(Word::MAX),
Policies::new().with_max_fee(0).with_maturity(0.into()),
inputs,
outputs,
vec![vec![123; 32].into(); 1],
Expand Down

Large diffs are not rendered by default.

25 changes: 11 additions & 14 deletions bin/fuel-core/src/cli/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,10 @@ mod tests {
.unwrap();

CoinConfig {
tx_id: Some(tx_id),
output_index: Some(output_index),
tx_pointer_block_height: Some(coin.tx_pointer().block_height()),
tx_pointer_tx_idx: Some(coin.tx_pointer().tx_index()),
tx_id,
output_index,
tx_pointer_block_height: coin.tx_pointer().block_height(),
tx_pointer_tx_idx: coin.tx_pointer().tx_index(),
owner: *coin.owner(),
amount: *coin.amount(),
asset_id: *coin.asset_id(),
Expand Down Expand Up @@ -465,10 +465,10 @@ mod tests {
contract_id,
code,
salt,
tx_id: Some(*utxo_id.tx_id()),
output_index: Some(utxo_id.output_index()),
tx_pointer_block_height: Some(tx_pointer.block_height()),
tx_pointer_tx_idx: Some(tx_pointer.tx_index()),
tx_id: *utxo_id.tx_id(),
output_index: utxo_id.output_index(),
tx_pointer_block_height: tx_pointer.block_height(),
tx_pointer_tx_idx: tx_pointer.tx_index(),
}
}

Expand Down Expand Up @@ -694,12 +694,9 @@ mod tests {
}

fn sorted_state(mut state: StateConfig) -> StateConfig {
state.coins.sort_by_key(|coin| {
UtxoId::new(
coin.tx_id.unwrap_or_default(),
coin.output_index.unwrap_or_default(),
)
});
state
.coins
.sort_by_key(|coin| UtxoId::new(coin.tx_id, coin.output_index));
state.messages.sort_by_key(|msg| msg.nonce);
state.contracts.sort_by_key(|contract| contract.contract_id);
state
Expand Down
101 changes: 78 additions & 23 deletions crates/chain-config/src/config/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use fuel_core_types::{
BlockHeight,
Bytes32,
},
fuel_vm::SecretKey,
};
use serde::{
Deserialize,
Expand All @@ -22,48 +23,71 @@ use serde::{
#[derive(Default, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct CoinConfig {
/// auto-generated if None
pub tx_id: Option<Bytes32>,
pub output_index: Option<u8>,
pub tx_id: Bytes32,
pub output_index: u8,
/// used if coin is forked from another chain to preserve id & tx_pointer
pub tx_pointer_block_height: Option<BlockHeight>,
pub tx_pointer_block_height: BlockHeight,
/// used if coin is forked from another chain to preserve id & tx_pointer
/// The index of the originating tx within `tx_pointer_block_height`
pub tx_pointer_tx_idx: Option<u16>,
pub tx_pointer_tx_idx: u16,
pub owner: Address,
pub amount: u64,
pub asset_id: AssetId,
}

impl CoinConfig {
// TODO: Remove https://github.com/FuelLabs/fuel-core/issues/1668
pub fn utxo_id(&self) -> Option<UtxoId> {
match (self.tx_id, self.output_index) {
(Some(tx_id), Some(output_index)) => Some(UtxoId::new(tx_id, output_index)),
_ => None,
/// Generates a new coin config with a unique utxo id for testing
#[derive(Default, Debug)]
pub struct CoinConfigGenerator {
count: usize,
}

impl CoinConfigGenerator {
pub fn new() -> Self {
Self { count: 0 }
}

pub fn generate(&mut self) -> CoinConfig {
let mut bytes = [0u8; 32];
bytes[..std::mem::size_of::<usize>()].copy_from_slice(&self.count.to_be_bytes());

let config = CoinConfig {
tx_id: Bytes32::from(bytes),
..Default::default()
};
self.count = self.count.checked_add(1).expect("Max coin count reached");

config
}

pub fn generate_with(&mut self, secret: SecretKey, amount: u64) -> CoinConfig {
let owner = Address::from(*secret.public_key().hash());

CoinConfig {
amount,
owner,
..self.generate()
}
}
}

impl CoinConfig {
pub fn utxo_id(&self) -> UtxoId {
UtxoId::new(self.tx_id, self.output_index)
}

// TODO: Remove https://github.com/FuelLabs/fuel-core/issues/1668
pub fn tx_pointer(&self) -> TxPointer {
match (self.tx_pointer_block_height, self.tx_pointer_tx_idx) {
(Some(block_height), Some(tx_idx)) => TxPointer::new(block_height, tx_idx),
_ => TxPointer::default(),
}
TxPointer::new(self.tx_pointer_block_height, self.tx_pointer_tx_idx)
}
}

#[cfg(all(test, feature = "random", feature = "std"))]
impl crate::Randomize for CoinConfig {
fn randomize(mut rng: impl ::rand::Rng) -> Self {
Self {
tx_id: rng
.gen::<bool>()
.then(|| super::random_bytes_32(&mut rng).into()),
output_index: rng.gen::<bool>().then(|| rng.gen()),
tx_pointer_block_height: rng
.gen::<bool>()
.then(|| BlockHeight::new(rng.gen())),
tx_pointer_tx_idx: rng.gen::<bool>().then(|| rng.gen()),
tx_id: super::random_bytes_32(&mut rng).into(),
output_index: rng.gen(),
tx_pointer_block_height: rng.gen(),
tx_pointer_tx_idx: rng.gen(),
owner: Address::new(super::random_bytes_32(&mut rng)),
amount: rng.gen(),
asset_id: AssetId::new(super::random_bytes_32(rng)),
Expand All @@ -89,3 +113,34 @@ impl GenesisCommitment for CompressedCoin {
Ok(coin_hash)
}
}

#[cfg(test)]
mod tests {
use super::*;
use fuel_core_types::{
fuel_types::Address,
fuel_vm::SecretKey,
};

#[test]
fn test_generate_unique_utxo_id() {
let mut generator = CoinConfigGenerator::new();
let config1 = generator.generate();
let config2 = generator.generate();

assert_ne!(config1.utxo_id(), config2.utxo_id());
}

#[test]
fn test_generate_with_owner_and_amount() {
let mut rng = rand::thread_rng();
let secret = SecretKey::random(&mut rng);
let amount = 1000;

let mut generator = CoinConfigGenerator::new();
let config = generator.generate_with(secret, amount);

assert_eq!(config.owner, Address::from(*secret.public_key().hash()));
assert_eq!(config.amount, amount);
}
}
34 changes: 11 additions & 23 deletions crates/chain-config/src/config/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,25 @@ pub struct ContractConfig {
#[serde_as(as = "HexIfHumanReadable")]
pub code: Vec<u8>,
pub salt: Salt,
pub tx_id: Option<Bytes32>,
pub output_index: Option<u8>,
pub tx_id: Bytes32,
pub output_index: u8,
/// TxPointer: auto-generated if None
/// used if contract is forked from another chain to preserve id & tx_pointer
/// The block height that the contract was last used in
pub tx_pointer_block_height: Option<BlockHeight>,
pub tx_pointer_block_height: BlockHeight,
/// TxPointer: auto-generated if None
/// used if contract is forked from another chain to preserve id & tx_pointer
/// The index of the originating tx within `tx_pointer_block_height`
pub tx_pointer_tx_idx: Option<u16>,
pub tx_pointer_tx_idx: u16,
}

impl ContractConfig {
// TODO: Remove https://github.com/FuelLabs/fuel-core/issues/1668
pub fn utxo_id(&self) -> Option<UtxoId> {
match (self.tx_id, self.output_index) {
(Some(tx_id), Some(output_index)) => Some(UtxoId::new(tx_id, output_index)),
_ => None,
}
pub fn utxo_id(&self) -> UtxoId {
UtxoId::new(self.tx_id, self.output_index)
}

// TODO: Remove https://github.com/FuelLabs/fuel-core/issues/1668
pub fn tx_pointer(&self) -> TxPointer {
match (self.tx_pointer_block_height, self.tx_pointer_tx_idx) {
(Some(block_height), Some(tx_idx)) => TxPointer::new(block_height, tx_idx),
_ => TxPointer::default(),
}
TxPointer::new(self.tx_pointer_block_height, self.tx_pointer_tx_idx)
}
}

Expand All @@ -63,14 +55,10 @@ impl crate::Randomize for ContractConfig {
contract_id: ContractId::new(super::random_bytes_32(&mut rng)),
code: (super::random_bytes_32(&mut rng)).to_vec(),
salt: Salt::new(super::random_bytes_32(&mut rng)),
tx_id: rng
.gen::<bool>()
.then(|| super::random_bytes_32(&mut rng).into()),
output_index: rng.gen::<bool>().then(|| rng.gen()),
tx_pointer_block_height: rng
.gen::<bool>()
.then(|| BlockHeight::from(rng.gen::<u32>())),
tx_pointer_tx_idx: rng.gen::<bool>().then(|| rng.gen()),
tx_id: super::random_bytes_32(&mut rng).into(),
output_index: rng.gen(),
tx_pointer_block_height: rng.gen(),
tx_pointer_tx_idx: rng.gen(),
}
}
}
Expand Down
27 changes: 6 additions & 21 deletions crates/chain-config/src/config/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use fuel_core_storage::{
Result as StorageResult,
};
use fuel_core_types::{
fuel_tx::UtxoId,
fuel_types::{
Address,
BlockHeight,
Expand All @@ -25,6 +24,7 @@ use serde::{
Serialize,
};

use crate::CoinConfigGenerator;
#[cfg(feature = "std")]
use crate::SnapshotMetadata;

Expand Down Expand Up @@ -171,6 +171,8 @@ impl StateConfig {
pub fn local_testnet() -> Self {
// endow some preset accounts with an initial balance
tracing::info!("Initial Accounts");

let mut coin_generator = CoinConfigGenerator::new();
let coins = TESTNET_WALLET_SECRETS
.into_iter()
.map(|secret| {
Expand All @@ -186,7 +188,7 @@ impl StateConfig {
bech32_encoding,
TESTNET_INITIAL_BALANCE
);
Self::initial_coin(secret, TESTNET_INITIAL_BALANCE, None)
coin_generator.generate_with(secret, TESTNET_INITIAL_BALANCE)
})
.collect_vec();

Expand All @@ -200,6 +202,7 @@ impl StateConfig {
pub fn random_testnet() -> Self {
tracing::info!("Initial Accounts");
let mut rng = rand::thread_rng();
let mut coin_generator = CoinConfigGenerator::new();
let coins = (0..5)
.map(|_| {
let secret = SecretKey::random(&mut rng);
Expand All @@ -214,7 +217,7 @@ impl StateConfig {
bech32_encoding,
TESTNET_INITIAL_BALANCE
);
Self::initial_coin(secret, TESTNET_INITIAL_BALANCE, None)
coin_generator.generate_with(secret, TESTNET_INITIAL_BALANCE)
})
.collect_vec();

Expand All @@ -223,24 +226,6 @@ impl StateConfig {
..StateConfig::default()
}
}

pub fn initial_coin(
secret: SecretKey,
amount: u64,
utxo_id: Option<UtxoId>,
) -> CoinConfig {
let address = Address::from(*secret.public_key().hash());

CoinConfig {
tx_id: utxo_id.as_ref().map(|u| *u.tx_id()),
output_index: utxo_id.as_ref().map(|u| u.output_index()),
tx_pointer_block_height: None,
tx_pointer_tx_idx: None,
owner: address,
amount,
asset_id: Default::default(),
}
}
}

#[impl_tools::autoimpl(for<T: trait> &T, &mut T)]
Expand Down
4 changes: 2 additions & 2 deletions crates/chain-config/src/config/state/parquet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ mod tests {
// then
let actually_read = bytes_read.load(std::sync::atomic::Ordering::SeqCst);

assert_eq!(total_size, 102958);
assert_eq!(actually_read, 871);
assert_eq!(total_size, 121649);
assert_eq!(actually_read, 1086);
}
}
16 changes: 8 additions & 8 deletions crates/chain-config/src/config/state/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,10 +506,10 @@ mod tests {
let filepath = dir.path().join("some_file.json");
let mut encoder = StateWriter::json(&filepath);
let coin = CoinConfig {
tx_id: Some([1u8; 32].into()),
output_index: Some(2),
tx_pointer_block_height: Some(BlockHeight::new(3)),
tx_pointer_tx_idx: Some(4),
tx_id: [1u8; 32].into(),
output_index: 2,
tx_pointer_block_height: BlockHeight::new(3),
tx_pointer_tx_idx: 4,
owner: [6u8; 32].into(),
amount: 7,
asset_id: [8u8; 32].into(),
Expand Down Expand Up @@ -560,10 +560,10 @@ mod tests {
contract_id: [1u8; 32].into(),
code: [2u8; 32].into(),
salt: [3u8; 32].into(),
tx_id: Some([4u8; 32].into()),
output_index: Some(5),
tx_pointer_block_height: Some(BlockHeight::new(6)),
tx_pointer_tx_idx: Some(7),
tx_id: [4u8; 32].into(),
output_index: 5,
tx_pointer_block_height: BlockHeight::new(6),
tx_pointer_tx_idx: 7,
};

// when
Expand Down
Loading

0 comments on commit 4110889

Please sign in to comment.