Skip to content

Commit 2bbfe61

Browse files
committed
Merge branch 'grarco/fix-masp-height-overflow' (#4725)
* origin/grarco/fix-masp-height-overflow: Error out on missing block Fixes broken migration test Adjusts block height in dry-run Fixes broken tests Changelog #4725 Improves masp expiration tests Fixes possible expiration overflow in masp tx construction
2 parents 4a0d7e6 + bb2cdc0 commit 2bbfe61

File tree

13 files changed

+439
-32
lines changed

13 files changed

+439
-32
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Fixed a possible overflow of the masp expiration height in the SDK.
2+
([\#4725](https://github.com/anoma/namada/pull/4725))

crates/node/src/dry_run_tx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ where
3333
tx.validate_tx().into_storage_result()?;
3434

3535
let gas_scale = parameters::get_gas_scale(&state)?;
36-
let height = state.in_mem().get_last_block_height();
36+
let height = state.in_mem().get_block_height().0;
3737

3838
// Wrapper dry run to allow estimating the entire gas cost of a transaction
3939
let (wrapper_hash, tx_result, tx_gas_meter) = match tx.header().tx_type {

crates/node/src/shell/testing/node.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,15 @@ impl MockNode {
371371
.unwrap_or_default()
372372
}
373373

374+
pub fn last_block_height(&self) -> BlockHeight {
375+
self.shell
376+
.lock()
377+
.unwrap()
378+
.state
379+
.in_mem()
380+
.get_last_block_height()
381+
}
382+
374383
pub fn current_epoch(&self) -> Epoch {
375384
self.shell.lock().unwrap().state.in_mem().last_epoch
376385
}
@@ -484,9 +493,8 @@ impl MockNode {
484493
pub fn finalize_and_commit(&self, header_time: Option<DateTimeUtc>) {
485494
let (proposer_address, votes) = self.prepare_request();
486495

496+
let height = self.last_block_height().next_height();
487497
let mut locked = self.shell.lock().unwrap();
488-
let height =
489-
locked.state.in_mem().get_last_block_height().next_height();
490498

491499
// check if we have protocol txs to be included
492500
// in the finalize block request
@@ -614,9 +622,8 @@ impl MockNode {
614622
}),
615623
..Default::default()
616624
};
625+
let height = self.last_block_height().next_height();
617626
let mut locked = self.shell.lock().unwrap();
618-
let height =
619-
locked.state.in_mem().get_last_block_height().next_height();
620627
let (result, tx_results) = locked.process_proposal(req);
621628

622629
let mut errors: Vec<_> = tx_results

crates/node/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ pub fn dry_run_proposal(
189189

190190
let gas_scale = parameters::get_gas_scale(&state)
191191
.expect("Failed to get gas scale from parameters");
192-
let height = state.in_mem().get_last_block_height();
192+
let height = state.in_mem().get_block_height().0;
193193

194194
let mut tx = Tx::from_type(TxType::Raw);
195195
tx.header.chain_id = chain_id.clone();

crates/shielded_token/src/masp/shielded_wallet.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,10 +1277,17 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
12771277
Some(expiration) => {
12781278
// Try to match a DateTime expiration with a plausible
12791279
// corresponding block height
1280-
let last_block_height = Self::query_block(context.client())
1281-
.await
1282-
.map_err(|e| TransferErr::General(e.to_string()))?
1283-
.unwrap_or(1);
1280+
let last_block_height = u32::try_from(
1281+
Self::query_block(context.client())
1282+
.await
1283+
.map_err(|e| TransferErr::General(e.to_string()))?
1284+
.ok_or_else(|| {
1285+
TransferErr::General(
1286+
"No blocks have been produced yet".to_string(),
1287+
)
1288+
})?,
1289+
)
1290+
.map_err(|e| TransferErr::General(e.to_string()))?;
12841291
let max_block_time =
12851292
Self::query_max_block_time_estimate(context.client())
12861293
.await
@@ -1296,14 +1303,20 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
12961303
/ i64::try_from(max_block_time.0).unwrap(),
12971304
)
12981305
.map_err(|e| TransferErr::General(e.to_string()))?;
1299-
u32::try_from(last_block_height)
1300-
.map_err(|e| TransferErr::General(e.to_string()))?
1301-
+ delta_blocks
1306+
match checked!(last_block_height + delta_blocks) {
1307+
Ok(height) if height <= u32::MAX - 20 => height,
1308+
_ => {
1309+
return Err(TransferErr::General(
1310+
"The provided expiration exceeds the maximum \
1311+
allowed"
1312+
.to_string(),
1313+
));
1314+
}
1315+
}
13021316
}
13031317
None => {
1304-
// NOTE: The masp library doesn't support optional
1305-
// expiration so we set the max to mimic
1306-
// a never-expiring tx. We also need to
1318+
// NOTE: The masp library doesn't support optional expiration so
1319+
// we set the max to mimic a never-expiring tx. We also need to
13071320
// remove 20 which is going to be added back by the builder
13081321
u32::MAX - 20
13091322
}

crates/state/src/in_memory.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,23 @@ where
216216
)
217217
}
218218

219-
/// Get the block height
219+
/// Get the block height. The height is that of the block to which the
220+
/// current transaction is being applied if we are in between the
221+
/// `FinalizeBlock` and the `Commit` phases. For all the other phases we
222+
/// return the block height of next block that the consensus process
223+
/// will decide upon (i.e. the block height of the last committed block
224+
/// + 1)
220225
pub fn get_block_height(&self) -> (BlockHeight, Gas) {
226+
let height = match self.header {
227+
Some(_) => self.block.height,
228+
// When not finalizing a decided block, increase the block height to
229+
// match that of the next block that will be proposed
230+
None => self.block.height.next_height(),
231+
};
221232
// Adding consts that cannot overflow
222233
#[allow(clippy::arithmetic_side_effects)]
223234
(
224-
self.block.height,
235+
height,
225236
(BLOCK_HEIGHT_LENGTH as u64 * MEMORY_ACCESS_GAS_PER_BYTE).into(),
226237
)
227238
}

crates/state/src/wl_state.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,10 +1198,10 @@ where
11981198
Ok(tree)
11991199
}
12001200

1201-
/// Get the timestamp of the last committed block, or the current timestamp
1202-
/// if no blocks have been produced yet
1201+
/// Get the timestamp of the last committed block, or the current local
1202+
/// timestamp if no blocks have been produced yet
12031203
pub fn get_last_block_timestamp(&self) -> Result<DateTimeUtc> {
1204-
let last_block_height = self.in_mem.get_block_height().0;
1204+
let last_block_height = self.in_mem.get_last_block_height();
12051205

12061206
Ok(self.db.read_block_header(last_block_height)?.map_or_else(
12071207
#[allow(clippy::disallowed_methods)]

crates/storage/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ pub trait StorageRead {
8989
fn get_chain_id(&self) -> Result<ChainId>;
9090

9191
/// Getting the block height. The height is that of the block to which the
92-
/// current transaction is being applied.
92+
/// current transaction is being applied if we are in between the
93+
/// `FinalizeBlock` and the `Commit` phases. For all the other phases we
94+
/// return the block height of next block that the consensus process
95+
/// will decide upon (i.e. the block height of the last committed block
96+
/// + 1)
9397
fn get_block_height(&self) -> Result<BlockHeight>;
9498

9599
/// Getting the block header.

crates/tests/src/integration/ledger_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2325,7 +2325,7 @@ fn scheduled_migration() -> Result<()> {
23252325
locked.scheduled_migration = Some(scheduled_migration);
23262326
}
23272327

2328-
while node.block_height().0 != 4 {
2328+
while node.last_block_height().0 != 4 {
23292329
node.finalize_and_commit(None)
23302330
}
23312331
// check that the key doesn't exist before the scheduled block

0 commit comments

Comments
 (0)