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

Lock farm early in case it already exists to prevent potential damage of the JSON file #2668

Merged
merged 1 commit into from
Apr 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 73 additions & 63 deletions crates/subspace-farmer/src/single_disk_farm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1105,86 +1105,96 @@ impl SingleDiskFarm {
let identity = Identity::open_or_create(directory)?;
let public_key = identity.public_key().to_bytes().into();

let single_disk_farm_info = match SingleDiskFarmInfo::load_from(directory)? {
Some(mut single_disk_farm_info) => {
if &farmer_app_info.genesis_hash != single_disk_farm_info.genesis_hash() {
return Err(SingleDiskFarmError::WrongChain {
id: *single_disk_farm_info.id(),
correct_chain: hex::encode(single_disk_farm_info.genesis_hash()),
wrong_chain: hex::encode(farmer_app_info.genesis_hash),
});
}
let (single_disk_farm_info, single_disk_farm_info_lock) =
match SingleDiskFarmInfo::load_from(directory)? {
Some(mut single_disk_farm_info) => {
let single_disk_farm_info_lock = if *disable_farm_locking {
None
} else {
Some(
SingleDiskFarmInfo::try_lock(directory)
.map_err(SingleDiskFarmError::LikelyAlreadyInUse)?,
)
};

if &public_key != single_disk_farm_info.public_key() {
return Err(SingleDiskFarmError::IdentityMismatch {
id: *single_disk_farm_info.id(),
correct_public_key: *single_disk_farm_info.public_key(),
wrong_public_key: public_key,
});
}
if &farmer_app_info.genesis_hash != single_disk_farm_info.genesis_hash() {
return Err(SingleDiskFarmError::WrongChain {
id: *single_disk_farm_info.id(),
correct_chain: hex::encode(single_disk_farm_info.genesis_hash()),
wrong_chain: hex::encode(farmer_app_info.genesis_hash),
});
}

let pieces_in_sector = single_disk_farm_info.pieces_in_sector();
if &public_key != single_disk_farm_info.public_key() {
return Err(SingleDiskFarmError::IdentityMismatch {
id: *single_disk_farm_info.id(),
correct_public_key: *single_disk_farm_info.public_key(),
wrong_public_key: public_key,
});
}

if max_pieces_in_sector < pieces_in_sector {
return Err(SingleDiskFarmError::InvalidPiecesInSector {
id: *single_disk_farm_info.id(),
max_supported: max_pieces_in_sector,
initialized_with: pieces_in_sector,
});
}
let pieces_in_sector = single_disk_farm_info.pieces_in_sector();

if max_pieces_in_sector < pieces_in_sector {
return Err(SingleDiskFarmError::InvalidPiecesInSector {
id: *single_disk_farm_info.id(),
max_supported: max_pieces_in_sector,
initialized_with: pieces_in_sector,
});
}

if max_pieces_in_sector > pieces_in_sector {
info!(
if max_pieces_in_sector > pieces_in_sector {
info!(
pieces_in_sector,
max_pieces_in_sector,
"Farm initialized with smaller number of pieces in sector, farm needs to \
be re-created for increase"
);
}
}

if allocated_space != single_disk_farm_info.allocated_space() {
info!(
old_space = %bytesize::to_string(single_disk_farm_info.allocated_space(), true),
new_space = %bytesize::to_string(allocated_space, true),
"Farm size has changed"
);
if allocated_space != single_disk_farm_info.allocated_space() {
info!(
old_space = %bytesize::to_string(single_disk_farm_info.allocated_space(), true),
new_space = %bytesize::to_string(allocated_space, true),
"Farm size has changed"
);

{
let new_allocated_space = allocated_space;
let SingleDiskFarmInfo::V0 {
allocated_space, ..
} = &mut single_disk_farm_info;
*allocated_space = new_allocated_space;
{
let new_allocated_space = allocated_space;
let SingleDiskFarmInfo::V0 {
allocated_space, ..
} = &mut single_disk_farm_info;
*allocated_space = new_allocated_space;
}

single_disk_farm_info.store_to(directory)?;
}

single_disk_farm_info.store_to(directory)?;
(single_disk_farm_info, single_disk_farm_info_lock)
}
None => {
let single_disk_farm_info = SingleDiskFarmInfo::new(
FarmId::new(),
farmer_app_info.genesis_hash,
public_key,
max_pieces_in_sector,
allocated_space,
);

single_disk_farm_info
}
None => {
let single_disk_farm_info = SingleDiskFarmInfo::new(
FarmId::new(),
farmer_app_info.genesis_hash,
public_key,
max_pieces_in_sector,
allocated_space,
);

single_disk_farm_info.store_to(directory)?;
single_disk_farm_info.store_to(directory)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that we write first and then secure a lock. Am I missing something?

Copy link
Member Author

Choose a reason for hiding this comment

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

There is no file to lock yet in case we've just created new farm

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. We can create a lock on the directory first (possibly creating it as well) - I believe fs4 treats a directory as a file. However, I don't think it will matter in practice because we protect manual runs which don't expect to have race conditions.


single_disk_farm_info
}
};
let single_disk_farm_info_lock = if *disable_farm_locking {
None
} else {
Some(
SingleDiskFarmInfo::try_lock(directory)
.map_err(SingleDiskFarmError::LikelyAlreadyInUse)?,
)
};

let single_disk_farm_info_lock = if *disable_farm_locking {
None
} else {
Some(
SingleDiskFarmInfo::try_lock(directory)
.map_err(SingleDiskFarmError::LikelyAlreadyInUse)?,
)
};
(single_disk_farm_info, single_disk_farm_info_lock)
}
};

let pieces_in_sector = single_disk_farm_info.pieces_in_sector();
let sector_size = sector_size(pieces_in_sector);
Expand Down
Loading