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

Replace unixTime with slotIndex in Timelock/Expiration #965

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d1cf775
Replace unixTime with slotIndex in Timelock/Expiration
thibault-martinez Jul 28, 2023
14ad012
More changes
thibault-martinez Jul 28, 2023
5c04740
More changes
thibault-martinez Jul 28, 2023
823cae5
More changes
thibault-martinez Jul 28, 2023
672cced
More changes
thibault-martinez Jul 28, 2023
5f734b3
It's alive!!!
thibault-martinez Jul 28, 2023
e039c13
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Jul 28, 2023
e088a82
Clippy
thibault-martinez Jul 28, 2023
d661279
Remove udep
thibault-martinez Jul 28, 2023
e2b7f6d
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Jul 28, 2023
6fc372c
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Jul 31, 2023
c17593e
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Aug 21, 2023
b07e52e
Update sdk/src/types/block/output/unlock_condition/expiration.rs
thibault-martinez Aug 21, 2023
5df5418
Address comments
thibault-martinez Aug 21, 2023
76447fd
Address comment
thibault-martinez Aug 21, 2023
0d90cbb
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Aug 22, 2023
04aae41
CLI nit
thibault-martinez Aug 22, 2023
5badd58
Clippy
thibault-martinez Aug 22, 2023
9e7d5c0
Impl Option
thibault-martinez Aug 22, 2023
dea11b5
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Aug 22, 2023
c98df4a
Remove some Some
thibault-martinez Aug 22, 2023
095a01b
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Aug 23, 2023
e37ae0a
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Aug 28, 2023
ddfa7f2
Use SlotIndex in QueryParameter
thibault-martinez Aug 28, 2023
61caad2
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Sep 1, 2023
c6c3414
Nits
thibault-martinez Sep 1, 2023
b453fe3
Address some TODOs
thibault-martinez Sep 1, 2023
67e2bb1
Nit
thibault-martinez Sep 1, 2023
f2ad78f
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Sep 1, 2023
6394011
Mandatory slot index
thibault-martinez Sep 4, 2023
8349afd
Remove an Option
thibault-martinez Sep 4, 2023
395cc17
Nit
thibault-martinez Sep 4, 2023
d2dd036
Example
thibault-martinez Sep 4, 2023
3e495c5
Use tx creation_slot
thibault-martinez Sep 4, 2023
1cde214
Address some comments
thibault-martinez Sep 4, 2023
e52c59e
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Sep 4, 2023
2ab38e1
Alternative print for underflow
thibault-martinez Sep 4, 2023
2b36017
Nit
thibault-martinez Sep 4, 2023
3fd9c3a
Fix test
thibault-martinez Sep 4, 2023
c2fa4c4
Review comments
thibault-martinez Sep 5, 2023
7766708
Merge branch '2.0' into expiration-timelock-slot-index
thibault-martinez Sep 5, 2023
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
7 changes: 0 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ dialoguer = { version = "0.10.4", default-features = false, features = [
] }
dotenvy = { version = "0.15.7", default-features = false }
fern-logger = { version = "0.5.0", default-features = false }
humantime = { version = "2.1.0", default-features = false }
log = { version = "0.4.20", default-features = false }
prefix-hex = { version = "0.7.1", default-features = false, features = ["std"] }
serde_json = { version = "1.0.105", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion cli/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub async fn account_prompt_internal(account: Account, history: &mut AccountHist
address,
amount,
return_address,
expiration.map(|e| e.as_secs() as u32),
expiration,
allow_micro_amount,
)
.await
Expand Down
33 changes: 20 additions & 13 deletions cli/src/command/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use iota_sdk::{
Output, OutputId, TokenId,
},
payload::transaction::TransactionId,
slot::SlotIndex,
ConvertTo,
},
},
Expand Down Expand Up @@ -163,11 +164,11 @@ pub enum AccountCommand {
/// default to the first address of the account.
#[arg(long)]
return_address: Option<Bech32Address>,
/// Expiration in seconds, after which the output will be available for the sender again, if not spent by the
/// receiver already. The expiration will only be used if one is necessary given the provided amount. If an
/// expiration is needed but not provided, it will default to one day.
/// Expiration in slot indices, after which the output will be available for the sender again, if not spent by
/// the receiver already. The expiration will only be used if one is necessary given the provided
/// amount. If an expiration is needed but not provided, it will default to one day.
#[arg(long)]
expiration: Option<humantime::Duration>,
expiration: Option<SlotIndex>,
/// Whether to send micro amounts. This will automatically add Storage Deposit Return and Expiration unlock
/// conditions if necessary. This flag is implied by the existence of a return address or expiration.
#[arg(long, default_value_t = false)]
Expand Down Expand Up @@ -382,9 +383,16 @@ pub async fn claimable_outputs_command(account: &Account) -> Result<(), Error> {
println_log_info!(" - base coin amount: {}", amount);

if let Some(expiration) = unlock_conditions.expiration() {
let current_time = iota_sdk::utils::unix_timestamp_now().as_secs() as u32;
let time_left = expiration.timestamp() - current_time;
println_log_info!(" - expires in: {} seconds", time_left);
let slot_index = account.client().get_slot_index().await?;

if *expiration.slot_index() > *slot_index {
println_log_info!(" - expires in {} slot indices", *expiration.slot_index() - *slot_index);
} else {
println_log_info!(
" - expired {} slot indices ago",
*slot_index - *expiration.slot_index()
);
}
}
}
}
Expand Down Expand Up @@ -640,7 +648,7 @@ pub async fn send_command(
address: impl ConvertTo<Bech32Address>,
amount: u64,
return_address: Option<impl ConvertTo<Bech32Address>>,
expiration: Option<u32>,
expiration: Option<SlotIndex>,
allow_micro_amount: bool,
) -> Result<(), Error> {
let params = [SendParams::new(amount, address)?
Expand Down Expand Up @@ -876,7 +884,7 @@ async fn print_address(account: &Account, address: &Bip44Address) -> Result<(),
}

let addresses = account.addresses_with_unspent_outputs().await?;
let current_time = iota_sdk::utils::unix_timestamp_now().as_secs() as u32;
let slot_index = account.client().get_slot_index().await?;

if let Ok(index) = addresses.binary_search_by_key(&(address.key_index(), address.internal()), |a| {
(a.key_index(), a.internal())
Expand All @@ -885,10 +893,9 @@ async fn print_address(account: &Account, address: &Bip44Address) -> Result<(),
for output_id in addresses[index].output_ids() {
if let Some(output_data) = account.get_output(output_id).await {
// Output might be associated with the address, but can't unlocked by it, so we check that here
let (required_address, _) =
output_data
.output
.required_and_unlocked_address(current_time, output_id, None)?;
let (required_address, _) = output_data
.output
.required_and_unlocked_address(slot_index, output_id, None)?;
if *address.address().as_ref() == required_address {
let unlock_conditions = output_data
.output
Expand Down
2 changes: 2 additions & 0 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ derive_more = { version = "0.99.17", default-features = false, features = [
"deref",
"deref_mut",
"display",
"add",
"add_assign",
] }
getset = { version = "0.1.2", default-features = false }
hashbrown = { version = "0.14.0", default-features = false, features = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use iota_sdk::{
unlock_condition::{AddressUnlockCondition, TimelockUnlockCondition},
BasicOutputBuilder,
},
slot::SlotIndex,
},
wallet::Result,
Wallet,
Expand All @@ -37,18 +38,14 @@ async fn main() -> Result<()> {
.set_stronghold_password(std::env::var("STRONGHOLD_PASSWORD").unwrap())
.await?;

// Create an ouput with amount 1_000_000 and a timelock of 1 hour
let in_an_hour = (std::time::SystemTime::now() + std::time::Duration::from_secs(3600))
.duration_since(std::time::UNIX_EPOCH)
.expect("clock went backwards")
.as_secs()
.try_into()
.unwrap();
// TODO better time-based UX ?
abdulmth marked this conversation as resolved.
Show resolved Hide resolved
// Create an output with amount 1_000_000 and a timelock of 1000 slots.
let slot_index = SlotIndex::from(1000);
let basic_output = BasicOutputBuilder::new_with_amount(1_000_000)
.add_unlock_condition(AddressUnlockCondition::new(Bech32Address::try_from_str(
"rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu",
)?))
.add_unlock_condition(TimelockUnlockCondition::new(in_an_hour)?)
.add_unlock_condition(TimelockUnlockCondition::new(slot_index)?)
.finish_output(account.client().get_token_supply().await?)?;

let transaction = account.send_outputs(vec![basic_output], None).await?;
Expand Down
2 changes: 1 addition & 1 deletion sdk/examples/wallet/offline_signing/2_sign_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ async fn main() -> Result<()> {

// Signs prepared transaction offline.
let unlocks = SecretManager::Stronghold(secret_manager)
.sign_transaction_essence(&prepared_transaction_data, None)
.sign_transaction_essence(&prepared_transaction_data)
.await?;

let signed_transaction = TransactionPayload::new(prepared_transaction_data.essence.as_regular().clone(), unlocks)?;
Expand Down
30 changes: 15 additions & 15 deletions sdk/src/client/api/block_builder/input_selection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use crate::{
OUTPUT_COUNT_RANGE,
},
protocol::ProtocolParameters,
slot::SlotIndex,
},
utils::unix_timestamp_now,
};

/// Working state for the input selection algorithm.
Expand All @@ -41,7 +41,7 @@ pub struct InputSelection {
burn: Option<Burn>,
remainder_address: Option<Address>,
protocol_parameters: ProtocolParameters,
timestamp: u32,
slot_index: SlotIndex,
requirements: Vec<Requirement>,
automatically_transitioned: HashMap<ChainId, Option<AccountTransition>>,
}
Expand All @@ -63,7 +63,7 @@ impl InputSelection {
is_account_transition(&input.output, *input.output_id(), &self.outputs, self.burn.as_ref());
let required_address = input
.output
.required_and_unlocked_address(self.timestamp, input.output_id(), account_transition)?
.required_and_unlocked_address(self.slot_index, input.output_id(), account_transition)?
.0;

match required_address {
Expand Down Expand Up @@ -186,7 +186,8 @@ impl InputSelection {
burn: None,
remainder_address: None,
protocol_parameters,
timestamp: unix_timestamp_now().as_secs() as u32,
// TODO may want to make this mandatory at some point
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
slot_index: SlotIndex::from(0),
requirements: Vec::new(),
automatically_transitioned: HashMap::new(),
}
Expand Down Expand Up @@ -216,9 +217,9 @@ impl InputSelection {
self
}

/// Sets the timestamp of an [`InputSelection`].
pub fn timestamp(mut self, timestamp: u32) -> Self {
self.timestamp = timestamp;
/// Sets the slot index of an [`InputSelection`].
pub fn slot_index(mut self, slot_index: impl Into<SlotIndex>) -> Self {
Alex6323 marked this conversation as resolved.
Show resolved Hide resolved
self.slot_index = slot_index.into();
self
}

Expand All @@ -237,14 +238,14 @@ impl InputSelection {
// PANIC: safe to unwrap as non basic/account/foundry/nft outputs are already filtered out.
let unlock_conditions = input.output.unlock_conditions().unwrap();

if unlock_conditions.is_time_locked(self.timestamp) {
if unlock_conditions.is_time_locked(self.slot_index) {
return false;
}

let required_address = input
.output
// Account transition is irrelevant here as we keep accounts anyway.
.required_and_unlocked_address(self.timestamp, input.output_id(), None)
.required_and_unlocked_address(self.slot_index, input.output_id(), None)
// PANIC: safe to unwrap as non basic/account/foundry/nft outputs are already filtered out.
.unwrap()
.0;
Expand All @@ -257,9 +258,8 @@ impl InputSelection {
pub(crate) fn sort_input_signing_data(
mut inputs: Vec<InputSigningData>,
outputs: &[Output],
time: Option<u32>,
slot_index: SlotIndex,
) -> Result<Vec<InputSigningData>, Error> {
let time = time.unwrap_or_else(|| unix_timestamp_now().as_secs() as u32);
// initially sort by output to make it deterministic
// TODO: rethink this, we only need it deterministic for tests, for the protocol it doesn't matter, also there
// might be a more efficient way to do this
Expand All @@ -275,7 +275,7 @@ impl InputSelection {
);
let (input_address, _) = input_signing_data
.output
.required_and_unlocked_address(time, input_signing_data.output_id(), account_transition)
.required_and_unlocked_address(slot_index, input_signing_data.output_id(), account_transition)
// PANIC: safe to unwrap, because we filtered irrelevant outputs out before
.unwrap();

Expand All @@ -287,7 +287,7 @@ impl InputSelection {
let (input_address, _) =
input
.output
.required_and_unlocked_address(time, input.output_id(), account_transition)?;
.required_and_unlocked_address(slot_index, input.output_id(), account_transition)?;

match sorted_inputs.iter().position(|input_signing_data| match input_address {
Address::Account(unlock_address) => {
Expand Down Expand Up @@ -334,7 +334,7 @@ impl InputSelection {
);
let (input_address, _) = input_signing_data
.output
.required_and_unlocked_address(time, input.output_id(), account_transition)
.required_and_unlocked_address(slot_index, input.output_id(), account_transition)
// PANIC: safe to unwrap, because we filtered irrelevant outputs out before
.unwrap();

Expand Down Expand Up @@ -408,7 +408,7 @@ impl InputSelection {
self.validate_transitions()?;

Ok(Selected {
inputs: Self::sort_input_signing_data(self.selected_inputs, &self.outputs, Some(self.timestamp))?,
inputs: Self::sort_input_signing_data(self.selected_inputs, &self.outputs, self.slot_index)?,
outputs: self.outputs,
remainder,
})
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/client/api/block_builder/input_selection/remainder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl InputSelection {
// PANIC: safe to unwrap as outputs with no address have been filtered out already.
let required_address = input
.output
.required_and_unlocked_address(self.timestamp, input.output_id(), account_transition)
.required_and_unlocked_address(self.slot_index, input.output_id(), account_transition)
.unwrap()
.0;

Expand Down Expand Up @@ -86,7 +86,7 @@ impl InputSelection {
&self,
) -> Result<(Option<RemainderData>, Vec<Output>), Error> {
let (inputs_sum, outputs_sum, inputs_sdr, outputs_sdr) =
amount_sums(&self.selected_inputs, &self.outputs, self.timestamp);
amount_sums(&self.selected_inputs, &self.outputs, self.slot_index);
let mut storage_deposit_returns = Vec::new();

for (address, amount) in inputs_sdr {
Expand Down
Loading
Loading