diff --git a/.changelog/unreleased/improvements/1431-rm-empty-keys-mod.md b/.changelog/unreleased/improvements/1431-rm-empty-keys-mod.md
deleted file mode 100644
index ab3d1de908..0000000000
--- a/.changelog/unreleased/improvements/1431-rm-empty-keys-mod.md
+++ /dev/null
@@ -1,2 +0,0 @@
-- Remove unused module in wallet
- ([#1431](https://github.com/anoma/namada/pull/1431))
\ No newline at end of file
diff --git a/.changelog/unreleased/improvements/1444-cse-in-inflation.md b/.changelog/unreleased/improvements/1444-cse-in-inflation.md
deleted file mode 100644
index a769fe96ae..0000000000
--- a/.changelog/unreleased/improvements/1444-cse-in-inflation.md
+++ /dev/null
@@ -1,2 +0,0 @@
-- Improve computations redability when calculating inflations
- ([#1444](https://github.com/anoma/namada/pull/1444))
\ No newline at end of file
diff --git a/.changelog/unreleased/miscellaneous/cwgoes-remove-unused-named-address.md b/.changelog/unreleased/miscellaneous/cwgoes-remove-unused-named-address.md
deleted file mode 100644
index 3152915455..0000000000
--- a/.changelog/unreleased/miscellaneous/cwgoes-remove-unused-named-address.md
+++ /dev/null
@@ -1 +0,0 @@
-Remove unused named address file
diff --git a/.changelog/unreleased/bug-fixes/1455-persist-epoch-update-delay.md b/.changelog/v0.17.1/bug-fixes/1455-persist-epoch-update-delay.md
similarity index 100%
rename from .changelog/unreleased/bug-fixes/1455-persist-epoch-update-delay.md
rename to .changelog/v0.17.1/bug-fixes/1455-persist-epoch-update-delay.md
diff --git a/.changelog/unreleased/bug-fixes/1456-fix-max-wait-tries.md b/.changelog/v0.17.1/bug-fixes/1456-fix-max-wait-tries.md
similarity index 100%
rename from .changelog/unreleased/bug-fixes/1456-fix-max-wait-tries.md
rename to .changelog/v0.17.1/bug-fixes/1456-fix-max-wait-tries.md
diff --git a/.changelog/unreleased/bug-fixes/1474-fix-sdk-tx-with-hash.md b/.changelog/v0.17.1/bug-fixes/1474-fix-sdk-tx-with-hash.md
similarity index 100%
rename from .changelog/unreleased/bug-fixes/1474-fix-sdk-tx-with-hash.md
rename to .changelog/v0.17.1/bug-fixes/1474-fix-sdk-tx-with-hash.md
diff --git a/.changelog/v0.17.1/bug-fixes/1534-fix-block-query.md b/.changelog/v0.17.1/bug-fixes/1534-fix-block-query.md
new file mode 100644
index 0000000000..8bfe764e11
--- /dev/null
+++ b/.changelog/v0.17.1/bug-fixes/1534-fix-block-query.md
@@ -0,0 +1,2 @@
+- Fix a client block query to avoid seeing pre-committed blocks.
+ ([\#1534](https://github.com/anoma/namada/pull/1534))
\ No newline at end of file
diff --git a/.changelog/unreleased/docs/889-gas-and-fee-specs.md b/.changelog/v0.17.1/docs/889-gas-and-fee-specs.md
similarity index 100%
rename from .changelog/unreleased/docs/889-gas-and-fee-specs.md
rename to .changelog/v0.17.1/docs/889-gas-and-fee-specs.md
diff --git a/.changelog/unreleased/features/1110-wallet-deterministic.md b/.changelog/v0.17.1/features/1110-wallet-deterministic.md
similarity index 100%
rename from .changelog/unreleased/features/1110-wallet-deterministic.md
rename to .changelog/v0.17.1/features/1110-wallet-deterministic.md
diff --git a/.changelog/unreleased/features/1344-find-validator-by-tm.md b/.changelog/v0.17.1/features/1344-find-validator-by-tm.md
similarity index 100%
rename from .changelog/unreleased/features/1344-find-validator-by-tm.md
rename to .changelog/v0.17.1/features/1344-find-validator-by-tm.md
diff --git a/.changelog/unreleased/features/892-cubic-slashing.md b/.changelog/v0.17.1/features/892-cubic-slashing.md
similarity index 100%
rename from .changelog/unreleased/features/892-cubic-slashing.md
rename to .changelog/v0.17.1/features/892-cubic-slashing.md
diff --git a/.changelog/unreleased/improvements/1093-signable-txs.md b/.changelog/v0.17.1/improvements/1093-signable-txs.md
similarity index 100%
rename from .changelog/unreleased/improvements/1093-signable-txs.md
rename to .changelog/v0.17.1/improvements/1093-signable-txs.md
diff --git a/.changelog/unreleased/improvements/1238-optinal-multicore-feature.md b/.changelog/v0.17.1/improvements/1238-optinal-multicore-feature.md
similarity index 100%
rename from .changelog/unreleased/improvements/1238-optinal-multicore-feature.md
rename to .changelog/v0.17.1/improvements/1238-optinal-multicore-feature.md
diff --git a/.changelog/unreleased/improvements/1425-wallet-zeroize.md b/.changelog/v0.17.1/improvements/1425-wallet-zeroize.md
similarity index 100%
rename from .changelog/unreleased/improvements/1425-wallet-zeroize.md
rename to .changelog/v0.17.1/improvements/1425-wallet-zeroize.md
diff --git a/.changelog/unreleased/improvements/1432-missing-args-def.md b/.changelog/v0.17.1/improvements/1432-missing-args-def.md
similarity index 100%
rename from .changelog/unreleased/improvements/1432-missing-args-def.md
rename to .changelog/v0.17.1/improvements/1432-missing-args-def.md
diff --git a/.changelog/unreleased/improvements/1434-improve-cli-commission-rate.md b/.changelog/v0.17.1/improvements/1434-improve-cli-commission-rate.md
similarity index 100%
rename from .changelog/unreleased/improvements/1434-improve-cli-commission-rate.md
rename to .changelog/v0.17.1/improvements/1434-improve-cli-commission-rate.md
diff --git a/.changelog/unreleased/improvements/1435-fix-err-typos.md b/.changelog/v0.17.1/improvements/1435-fix-err-typos.md
similarity index 100%
rename from .changelog/unreleased/improvements/1435-fix-err-typos.md
rename to .changelog/v0.17.1/improvements/1435-fix-err-typos.md
diff --git a/.changelog/unreleased/improvements/1436-rename-tx-reveal-arg.md b/.changelog/v0.17.1/improvements/1436-rename-tx-reveal-arg.md
similarity index 100%
rename from .changelog/unreleased/improvements/1436-rename-tx-reveal-arg.md
rename to .changelog/v0.17.1/improvements/1436-rename-tx-reveal-arg.md
diff --git a/.changelog/v0.17.1/improvements/1444-cse-in-inflation.md b/.changelog/v0.17.1/improvements/1444-cse-in-inflation.md
new file mode 100644
index 0000000000..f5a89ac9b2
--- /dev/null
+++ b/.changelog/v0.17.1/improvements/1444-cse-in-inflation.md
@@ -0,0 +1,2 @@
+- Improve computations readability when calculating inflations
+ ([#1444](https://github.com/anoma/namada/pull/1444))
\ No newline at end of file
diff --git a/.changelog/unreleased/improvements/1449-rm-abciplus-cargo-deps.md b/.changelog/v0.17.1/improvements/1449-rm-abciplus-cargo-deps.md
similarity index 100%
rename from .changelog/unreleased/improvements/1449-rm-abciplus-cargo-deps.md
rename to .changelog/v0.17.1/improvements/1449-rm-abciplus-cargo-deps.md
diff --git a/.changelog/unreleased/improvements/1462-restructure-tx-draft.md b/.changelog/v0.17.1/improvements/1462-restructure-tx-draft.md
similarity index 100%
rename from .changelog/unreleased/improvements/1462-restructure-tx-draft.md
rename to .changelog/v0.17.1/improvements/1462-restructure-tx-draft.md
diff --git a/.changelog/unreleased/improvements/1509-improve-pos-logging.md b/.changelog/v0.17.1/improvements/1509-improve-pos-logging.md
similarity index 100%
rename from .changelog/unreleased/improvements/1509-improve-pos-logging.md
rename to .changelog/v0.17.1/improvements/1509-improve-pos-logging.md
diff --git a/.changelog/v0.17.1/summary.md b/.changelog/v0.17.1/summary.md
new file mode 100644
index 0000000000..0491959a0a
--- /dev/null
+++ b/.changelog/v0.17.1/summary.md
@@ -0,0 +1,2 @@
+Namada 0.17.0 is a scheduled minor release featuring several improvements to the slashing mechanism,
+wallet address derivation, transaction structure and the ledger stability.
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index c2d64ee130..7b6852fd7b 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -102,13 +102,13 @@ jobs:
run: sccache --start-server
- name: Install cargo tool
run: |
- curl https://i.jpillora.com/${{ matrix.mdbook_version }}! | bash
- curl https://i.jpillora.com/${{ matrix.mdbook_mermaid }}! | bash
- curl https://i.jpillora.com/${{ matrix.mdbook_linkcheck }}! | bash
- curl https://i.jpillora.com/${{ matrix.mdbook_open_on_gh }}! | bash
- curl https://i.jpillora.com/${{ matrix.mdbook_admonish }}! | bash
- curl https://i.jpillora.com/${{ matrix.mdbook_katex }}! | bash
- curl https://i.jpillora.com/${{ matrix.mdbook_pagetoc }}! | bash
+ curl -k https://installer.heliax.click/${{ matrix.mdbook_version }}! | bash
+ curl -k https://installer.heliax.click/${{ matrix.mdbook_mermaid }}! | bash
+ curl -k https://installer.heliax.click/${{ matrix.mdbook_linkcheck }}! | bash
+ curl -k https://installer.heliax.click/${{ matrix.mdbook_open_on_gh }}! | bash
+ curl -k https://installer.heliax.click/${{ matrix.mdbook_admonish }}! | bash
+ curl -k https://installer.heliax.click/${{ matrix.mdbook_katex }}! | bash
+ curl -k https://installer.heliax.click/${{ matrix.mdbook_pagetoc }}! | bash
cd ${{ matrix.make.folder }} && mdbook-admonish install
- name: ${{ matrix.make.name }}
run: ${{ matrix.make.command }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4eeaf5c114..9b8aa9b80e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,65 @@
# CHANGELOG
-## Unreleased
+## v0.17.1
+
+Namada 0.17.0 is a scheduled minor release featuring several improvements to the slashing mechanism,
+wallet address derivation, transaction structure and the ledger stability.
+
+### BUG FIXES
+
+- Persists a newly added storage field for epoch update blocks delay to be
+ available after node restart when not `None` which may break consensus.
+ ([\#1455](https://github.com/anoma/namada/pull/1455))
+- Client: Fixed an off-by-one error to stop waiting for start or catch-up when
+ max tries are reached. ([\#1456](https://github.com/anoma/namada/pull/1456))
+- Include the wasm tx hash instead of the wasm blob when constructing a
+ transaction ([#1474](https://github.com/anoma/namada/pull/1474))
+- Fix a client block query to avoid seeing pre-committed blocks.
+ ([\#1534](https://github.com/anoma/namada/pull/1534))
### DOCS
- Adds specs for gas and fee ([#889](https://github.com/anoma/namada/pull/889))
+### FEATURES
+
+- The implementation of the cubic slashing system that touches virtually all
+ parts of the proof-of-stake system. Slashes tokens are currently kept in the
+ PoS address rather than being transferred to the Slash Pool address. This PR
+ also includes significant testing infrastructure, highlighted by the PoS state
+ machine test with slashing. ([#892](https://github.com/anoma/namada/pull/892))
+- Implements HD wallet derivation / recovery from a given mnemonic code
+ ([\#1110](https://github.com/anoma/namada/pull/1110))
+- PoS: Added a client command `find-validator --tm-address
`
+ to find validator's Namada address by Tendermint address.
+ ([\#1344](https://github.com/anoma/namada/pull/1344))
+
+### IMPROVEMENTS
+
+- Make Namada transactions signable on hardware constrained wallets by making
+ them smaller. ([#1093](https://github.com/anoma/namada/pull/1093))
+- Added `multicore` feature flag to the namada and namada_core
+ crate that can be switched off for JS WASM build.
+ Additionally, changed the `trait ShieldedUtils` to be async.
+ ([\#1238](https://github.com/anoma/namada/pull/1238))
+- Zeroizes memory containing passphrases in wallet.
+ ([\#1425](https://github.com/anoma/namada/issues/1425))
+- Added some missing cli option for cli wallet
+ ([#1432](https://github.com/anoma/namada/pull/1432))
+- Improve logging error when submiting an invalid validator commission change tx
+ ([#1434](https://github.com/anoma/namada/pull/1434))
+- Correct a typo in the error change commission error handling
+ ([#1435](https://github.com/anoma/namada/pull/1435))
+- Improve the reveal tx naming in cli
+ ([#1436](https://github.com/anoma/namada/pull/1436))
+- Improve computations readability when calculating inflations
+ ([#1444](https://github.com/anoma/namada/pull/1444))
+- Remove abci++ dependencies ([#1449](https://github.com/anoma/namada/pull/1449))
+- Reorganize the structure of transactions
+ ([#1462](https://github.com/anoma/namada/pull/1462))
+- Improved log entries related to PoS system.
+ ([\#1509](https://github.com/anoma/namada/pull/1509))
+
## v0.16.0
Namada 0.16.0 is a regular release focused on providing the Namada SDK
@@ -26,7 +80,7 @@ applications). ([#925](https://github.com/anoma/namada/pull/925))
## v0.15.4
-Namada 0.15.4 is a maintenance release addressing the invalid creation of blocks due to missing replay protection checks during prepare
+Namada 0.15.4 is a maintenance release addressing the invalid creation of blocks due to missing replay protection checks during prepare
proposal.
### BUG FIXES
diff --git a/Cargo.lock b/Cargo.lock
index d6cde05ddb..f69107f711 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3915,7 +3915,7 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "namada"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"assert_matches",
"async-std",
@@ -3983,7 +3983,7 @@ dependencies = [
[[package]]
name = "namada_apps"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"ark-serialize",
"ark-std",
@@ -4070,7 +4070,7 @@ dependencies = [
[[package]]
name = "namada_core"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"ark-bls12-381",
"ark-ec",
@@ -4119,7 +4119,7 @@ dependencies = [
[[package]]
name = "namada_encoding_spec"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"borsh",
"itertools",
@@ -4130,7 +4130,7 @@ dependencies = [
[[package]]
name = "namada_macros"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"proc-macro2",
"quote",
@@ -4139,7 +4139,7 @@ dependencies = [
[[package]]
name = "namada_proof_of_stake"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"borsh",
"data-encoding",
@@ -4160,7 +4160,7 @@ dependencies = [
[[package]]
name = "namada_test_utils"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"borsh",
"namada_core",
@@ -4169,7 +4169,7 @@ dependencies = [
[[package]]
name = "namada_tests"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"assert_cmd",
"borsh",
@@ -4216,7 +4216,7 @@ dependencies = [
[[package]]
name = "namada_tx_prelude"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"borsh",
"masp_primitives",
@@ -4231,7 +4231,7 @@ dependencies = [
[[package]]
name = "namada_vm_env"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"borsh",
"hex",
@@ -4241,7 +4241,7 @@ dependencies = [
[[package]]
name = "namada_vp_prelude"
-version = "0.16.0"
+version = "0.17.1"
dependencies = [
"borsh",
"namada_core",
diff --git a/apps/Cargo.toml b/apps/Cargo.toml
index 6aadde0c47..c65c55c69c 100644
--- a/apps/Cargo.toml
+++ b/apps/Cargo.toml
@@ -6,7 +6,7 @@ license = "GPL-3.0"
name = "namada_apps"
readme = "../README.md"
resolver = "2"
-version = "0.16.0"
+version = "0.17.1"
default-run = "namada"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs
index fee77d993f..9907fd0f86 100644
--- a/apps/src/lib/client/rpc.rs
+++ b/apps/src/lib/client/rpc.rs
@@ -79,8 +79,19 @@ pub async fn query_and_print_epoch<
/// Query the last committed block
pub async fn query_block(
client: &C,
-) -> crate::facade::tendermint_rpc::endpoint::block::Response {
- namada::ledger::rpc::query_block(client).await
+) {
+ let block = namada::ledger::rpc::query_block(client).await;
+ match block {
+ Some(block) => {
+ println!(
+ "Last committed block ID: {}, height: {}, time: {}",
+ block.hash, block.height, block.time
+ );
+ }
+ None => {
+ println!("No block has been committed yet.");
+ }
+ }
}
/// Query the results of the last committed block
diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs
index a215c2104d..e992544051 100644
--- a/apps/src/lib/node/ledger/shell/finalize_block.rs
+++ b/apps/src/lib/node/ledger/shell/finalize_block.rs
@@ -536,7 +536,7 @@ where
hash: BlockHash,
byzantine_validators: Vec,
) -> (BlockHeight, bool) {
- let height = self.wl_storage.storage.last_height + 1;
+ let height = self.wl_storage.storage.get_last_block_height() + 1;
self.gas_meter.reset();
diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs
index 6b9dec5a76..ad2eb1b501 100644
--- a/apps/src/lib/node/ledger/shell/mod.rs
+++ b/apps/src/lib/node/ledger/shell/mod.rs
@@ -663,7 +663,7 @@ where
tracing::info!(
"Committed block hash: {}, height: {}",
root,
- self.wl_storage.storage.last_height,
+ self.wl_storage.storage.get_last_block_height(),
);
response.data = root.0;
response
diff --git a/apps/src/lib/node/ledger/storage/mod.rs b/apps/src/lib/node/ledger/storage/mod.rs
index e9222ab213..5b42c0dc77 100644
--- a/apps/src/lib/node/ledger/storage/mod.rs
+++ b/apps/src/lib/node/ledger/storage/mod.rs
@@ -354,14 +354,16 @@ mod tests {
let is_last_write = blocks_write_value.last().unwrap().1;
// The upper bound is arbitrary.
- for height in storage.last_height.0..storage.last_height.0 + 10 {
+ for height in storage.get_last_block_height().0
+ ..storage.get_last_block_height().0 + 10
+ {
let height = BlockHeight::from(height);
let (value_bytes, _gas) = storage.read_with_height(&key, height)?;
if is_last_write {
let value_bytes =
value_bytes.expect("Should have been written");
let value: BlockHeight = types::decode(value_bytes).unwrap();
- assert_eq!(value, storage.last_height);
+ assert_eq!(value, storage.get_last_block_height());
} else if value_bytes.is_some() {
let value: BlockHeight =
types::decode(value_bytes.unwrap()).unwrap();
diff --git a/apps/src/lib/node/ledger/storage/rocksdb.rs b/apps/src/lib/node/ledger/storage/rocksdb.rs
index 8b3f77bc1b..615ee0e4b9 100644
--- a/apps/src/lib/node/ledger/storage/rocksdb.rs
+++ b/apps/src/lib/node/ledger/storage/rocksdb.rs
@@ -23,6 +23,7 @@
//! - `root`: root hash
//! - `store`: the tree's store
//! - `hash`: block hash
+//! - `time`: block time
//! - `epoch`: block epoch
//! - `address_gen`: established address generator
//! - `header`: block's header
@@ -570,6 +571,7 @@ impl DB for RocksDB {
read_opts.set_iterate_upper_bound(next_height_prefix);
let mut merkle_tree_stores = MerkleTreeStoresRead::default();
let mut hash = None;
+ let mut time = None;
let mut epoch = None;
let mut pred_epochs = None;
let mut address_gen = None;
@@ -618,6 +620,11 @@ impl DB for RocksDB {
types::decode(bytes).map_err(Error::CodingError)?,
)
}
+ "time" => {
+ time = Some(
+ types::decode(bytes).map_err(Error::CodingError)?,
+ )
+ }
"epoch" => {
epoch = Some(
types::decode(bytes).map_err(Error::CodingError)?,
@@ -638,22 +645,27 @@ impl DB for RocksDB {
None => unknown_key_error(path)?,
}
}
- match (hash, epoch, pred_epochs, address_gen) {
- (Some(hash), Some(epoch), Some(pred_epochs), Some(address_gen)) => {
- Ok(Some(BlockStateRead {
- merkle_tree_stores,
- hash,
- height,
- epoch,
- pred_epochs,
- results,
- next_epoch_min_start_height,
- next_epoch_min_start_time,
- update_epoch_blocks_delay,
- address_gen,
- tx_queue,
- }))
- }
+ match (hash, time, epoch, pred_epochs, address_gen) {
+ (
+ Some(hash),
+ Some(time),
+ Some(epoch),
+ Some(pred_epochs),
+ Some(address_gen),
+ ) => Ok(Some(BlockStateRead {
+ merkle_tree_stores,
+ hash,
+ height,
+ time,
+ epoch,
+ pred_epochs,
+ results,
+ next_epoch_min_start_height,
+ next_epoch_min_start_time,
+ update_epoch_blocks_delay,
+ address_gen,
+ tx_queue,
+ })),
_ => Err(Error::Temporary {
error: "Essential data couldn't be read from the DB"
.to_string(),
@@ -672,6 +684,7 @@ impl DB for RocksDB {
header,
hash,
height,
+ time,
epoch,
pred_epochs,
next_epoch_min_start_height,
@@ -803,6 +816,15 @@ impl DB for RocksDB {
.0
.put_cf(block_cf, key.to_string(), types::encode(&hash));
}
+ // Block time
+ {
+ let key = prefix_key
+ .push(&"time".to_owned())
+ .map_err(Error::KeyError)?;
+ batch
+ .0
+ .put_cf(block_cf, key.to_string(), types::encode(&time));
+ }
// Block epoch
{
let key = prefix_key
@@ -1444,6 +1466,7 @@ mod test {
let merkle_tree = MerkleTree::::default();
let merkle_tree_stores = merkle_tree.stores();
let hash = BlockHash::default();
+ let time = DateTimeUtc::now();
let epoch = Epoch::default();
let pred_epochs = Epochs::default();
let height = BlockHeight::default();
@@ -1458,6 +1481,7 @@ mod test {
header: None,
hash: &hash,
height,
+ time,
epoch,
results: &results,
pred_epochs: &pred_epochs,
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 427ae6c406..9d5107f402 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -4,7 +4,7 @@ edition = "2021"
license = "GPL-3.0"
name = "namada_core"
resolver = "2"
-version = "0.16.0"
+version = "0.17.1"
[features]
default = ["multicore"]
diff --git a/core/src/ledger/storage/mockdb.rs b/core/src/ledger/storage/mockdb.rs
index bcec9962ba..e53178b157 100644
--- a/core/src/ledger/storage/mockdb.rs
+++ b/core/src/ledger/storage/mockdb.rs
@@ -101,6 +101,7 @@ impl DB for MockDB {
let upper_prefix = format!("{}/", height.next_height().raw());
let mut merkle_tree_stores = MerkleTreeStoresRead::default();
let mut hash = None;
+ let mut time = None;
let mut epoch = None;
let mut pred_epochs = None;
let mut address_gen = None;
@@ -137,6 +138,11 @@ impl DB for MockDB {
types::decode(bytes).map_err(Error::CodingError)?,
)
}
+ "time" => {
+ time = Some(
+ types::decode(bytes).map_err(Error::CodingError)?,
+ )
+ }
"epoch" => {
epoch = Some(
types::decode(bytes).map_err(Error::CodingError)?,
@@ -157,23 +163,28 @@ impl DB for MockDB {
None => unknown_key_error(path)?,
}
}
- match (hash, epoch, pred_epochs, address_gen) {
- (Some(hash), Some(epoch), Some(pred_epochs), Some(address_gen)) => {
- Ok(Some(BlockStateRead {
- merkle_tree_stores,
- hash,
- height,
- epoch,
- pred_epochs,
- next_epoch_min_start_height,
- next_epoch_min_start_time,
- update_epoch_blocks_delay,
- address_gen,
- results,
- #[cfg(feature = "ferveo-tpke")]
- tx_queue,
- }))
- }
+ match (hash, time, epoch, pred_epochs, address_gen) {
+ (
+ Some(hash),
+ Some(time),
+ Some(epoch),
+ Some(pred_epochs),
+ Some(address_gen),
+ ) => Ok(Some(BlockStateRead {
+ merkle_tree_stores,
+ hash,
+ height,
+ time,
+ epoch,
+ pred_epochs,
+ next_epoch_min_start_height,
+ next_epoch_min_start_time,
+ update_epoch_blocks_delay,
+ address_gen,
+ results,
+ #[cfg(feature = "ferveo-tpke")]
+ tx_queue,
+ })),
_ => Err(Error::Temporary {
error: "Essential data couldn't be read from the DB"
.to_string(),
@@ -191,6 +202,7 @@ impl DB for MockDB {
merkle_tree_stores,
header,
hash,
+ time,
height,
epoch,
pred_epochs,
@@ -270,6 +282,15 @@ impl DB for MockDB {
.borrow_mut()
.insert(key.to_string(), types::encode(&hash));
}
+ // Block time
+ {
+ let key = prefix_key
+ .push(&"time".to_owned())
+ .map_err(Error::KeyError)?;
+ self.0
+ .borrow_mut()
+ .insert(key.to_string(), types::encode(&time));
+ }
// Block epoch
{
let key = prefix_key
diff --git a/core/src/ledger/storage/mod.rs b/core/src/ledger/storage/mod.rs
index 658dea661f..bece612b56 100644
--- a/core/src/ledger/storage/mod.rs
+++ b/core/src/ledger/storage/mod.rs
@@ -13,6 +13,7 @@ pub mod write_log;
use core::fmt::Debug;
use std::cmp::Ordering;
+use borsh::{BorshDeserialize, BorshSerialize};
pub use merkle_tree::{
MembershipProof, MerkleTree, MerkleTreeStoresRead, MerkleTreeStoresWrite,
StoreType,
@@ -75,9 +76,8 @@ where
/// going to be committed. After a block is committed, this is reset to
/// `None` until the next `FinalizeBlock` phase is reached.
pub header: Option,
- /// The height of the most recently committed block, or `BlockHeight(0)` if
- /// no block has been committed for this chain yet.
- pub last_height: BlockHeight,
+ /// The most recently committed block, if any.
+ pub last_block: Option,
/// The epoch of the most recently committed block. If it is `Epoch(0)`,
/// then no block may have been committed for this chain yet.
pub last_epoch: Epoch,
@@ -104,6 +104,17 @@ where
pub storage_read_past_height_limit: Option,
}
+/// Last committed block
+#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
+pub struct LastBlock {
+ /// Block height
+ pub height: BlockHeight,
+ /// Block hash
+ pub hash: BlockHash,
+ /// Block time
+ pub time: DateTimeUtc,
+}
+
/// The block storage data
#[derive(Debug)]
pub struct BlockStorage {
@@ -160,6 +171,8 @@ pub struct BlockStateRead {
pub hash: BlockHash,
/// Height of the block
pub height: BlockHeight,
+ /// Time of the block
+ pub time: DateTimeUtc,
/// Epoch of the block
pub epoch: Epoch,
/// Predecessor block epochs
@@ -189,6 +202,8 @@ pub struct BlockStateWrite<'a> {
pub hash: &'a BlockHash,
/// Height of the block
pub height: BlockHeight,
+ /// Time of the block
+ pub time: DateTimeUtc,
/// Epoch of the block
pub epoch: Epoch,
/// Predecessor block epochs
@@ -379,7 +394,7 @@ where
chain_id,
block,
header: None,
- last_height: BlockHeight(0),
+ last_block: None,
last_epoch: Epoch::default(),
next_epoch_min_start_height: BlockHeight::default(),
next_epoch_min_start_time: DateTimeUtc::now(),
@@ -403,6 +418,7 @@ where
merkle_tree_stores,
hash,
height,
+ time,
epoch,
pred_epochs,
next_epoch_min_start_height,
@@ -414,12 +430,12 @@ where
tx_queue,
}) = self.db.read_last_block()?
{
- self.block.hash = hash;
+ self.block.hash = hash.clone();
self.block.height = height;
self.block.epoch = epoch;
self.block.results = results;
self.block.pred_epochs = pred_epochs;
- self.last_height = height;
+ self.last_block = Some(LastBlock { height, hash, time });
self.last_epoch = epoch;
self.next_epoch_min_start_height = next_epoch_min_start_height;
self.next_epoch_min_start_time = next_epoch_min_start_time;
@@ -471,11 +487,30 @@ where
// All states are written only when the first height or a new epoch
let is_full_commit =
self.block.height.0 == 1 || self.last_epoch != self.block.epoch;
+
+ // For convenience in tests, fill-in a header if it's missing.
+ // Normally, the header is added in `FinalizeBlock`.
+ #[cfg(any(test, feature = "testing"))]
+ {
+ if self.header.is_none() {
+ self.header = Some(Header {
+ hash: Hash::default(),
+ time: DateTimeUtc::now(),
+ next_validators_hash: Hash::default(),
+ });
+ }
+ }
+
let state = BlockStateWrite {
merkle_tree_stores: self.block.tree.stores(),
header: self.header.as_ref(),
hash: &self.block.hash,
height: self.block.height,
+ time: self
+ .header
+ .as_ref()
+ .expect("Must have a block header on commit")
+ .time,
epoch: self.block.epoch,
results: &self.block.results,
pred_epochs: &self.block.pred_epochs,
@@ -487,9 +522,16 @@ where
tx_queue: &self.tx_queue,
};
self.db.write_block(state, &mut batch, is_full_commit)?;
- self.last_height = self.block.height;
+ let header = self
+ .header
+ .take()
+ .expect("Must have a block header on commit");
+ self.last_block = Some(LastBlock {
+ height: self.block.height,
+ hash: header.hash.into(),
+ time: header.time,
+ });
self.last_epoch = self.block.epoch;
- self.header = None;
if is_full_commit {
// prune old merkle tree stores
self.prune_merkle_tree_stores(&mut batch)?;
@@ -532,13 +574,13 @@ where
key: &Key,
height: BlockHeight,
) -> Result<(Option>, u64)> {
- if height >= self.last_height {
+ if height >= self.get_last_block_height() {
self.read(key)
} else {
match self.db.read_subspace_val_with_height(
key,
height,
- self.last_height,
+ self.get_last_block_height(),
)? {
Some(v) => {
let gas = key.len() + v.len();
@@ -742,7 +784,7 @@ where
) -> Result {
use std::array;
- if height > self.last_height {
+ if height > self.get_last_block_height() {
Err(Error::Temporary {
error: format!(
"The block at the height {} hasn't committed yet",
@@ -767,7 +809,7 @@ where
key: &Key,
height: BlockHeight,
) -> Result {
- if height > self.last_height {
+ if height > self.get_last_block_height() {
Err(Error::Temporary {
error: format!(
"The block at the height {} hasn't committed yet",
@@ -918,11 +960,11 @@ where
batch: &mut D::WriteBatch,
) -> Result<()> {
if let Some(limit) = self.storage_read_past_height_limit {
- if self.last_height.0 <= limit {
+ if self.get_last_block_height().0 <= limit {
return Ok(());
}
- let min_height = (self.last_height.0 - limit).into();
+ let min_height = (self.get_last_block_height().0 - limit).into();
if let Some(epoch) = self.block.pred_epochs.get_epoch(min_height) {
if epoch.0 == 0 {
return Ok(());
@@ -941,6 +983,15 @@ where
}
Ok(())
}
+
+ /// Get the height of the last committed block or 0 if no block has been
+ /// committed yet. The first block is at height 1.
+ pub fn get_last_block_height(&self) -> BlockHeight {
+ self.last_block
+ .as_ref()
+ .map(|b| b.height)
+ .unwrap_or_default()
+ }
}
impl From for Error {
@@ -984,7 +1035,7 @@ pub mod testing {
chain_id,
block,
header: None,
- last_height: BlockHeight(0),
+ last_block: None,
last_epoch: Epoch::default(),
next_epoch_min_start_height: BlockHeight::default(),
next_epoch_min_start_time: DateTimeUtc::now(),
diff --git a/core/src/types/storage.rs b/core/src/types/storage.rs
index cedb58164f..e61e1e98dc 100644
--- a/core/src/types/storage.rs
+++ b/core/src/types/storage.rs
@@ -9,7 +9,7 @@ use std::str::FromStr;
use arse_merkle_tree::traits::Value;
use arse_merkle_tree::{InternalKey, Key as TreeKey};
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
-use data_encoding::BASE32HEX_NOPAD;
+use data_encoding::{BASE32HEX_NOPAD, HEXUPPER};
use index_set::vec::VecIndexSet;
use serde::{Deserialize, Serialize};
use thiserror::Error;
@@ -208,6 +208,12 @@ impl From for u64 {
)]
pub struct BlockHash(pub [u8; BLOCK_HASH_LENGTH]);
+impl Display for BlockHash {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", HEXUPPER.encode(&self.0))
+ }
+}
+
impl From for BlockHash {
fn from(hash: Hash) -> Self {
BlockHash(hash.0)
diff --git a/core/src/types/time.rs b/core/src/types/time.rs
index 3923894404..0670392f94 100644
--- a/core/src/types/time.rs
+++ b/core/src/types/time.rs
@@ -112,6 +112,12 @@ pub struct Rfc3339String(pub String);
#[serde(try_from = "Rfc3339String", into = "Rfc3339String")]
pub struct DateTimeUtc(pub DateTime);
+impl Display for DateTimeUtc {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.to_rfc3339())
+ }
+}
+
impl DateTimeUtc {
/// Returns a DateTimeUtc which corresponds to the current date.
pub fn now() -> Self {
diff --git a/encoding_spec/Cargo.toml b/encoding_spec/Cargo.toml
index a2aba121a8..1d997a1e30 100644
--- a/encoding_spec/Cargo.toml
+++ b/encoding_spec/Cargo.toml
@@ -6,7 +6,7 @@ license = "GPL-3.0"
name = "namada_encoding_spec"
readme = "../README.md"
resolver = "2"
-version = "0.16.0"
+version = "0.17.1"
[features]
default = ["abciplus"]
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
index 1030215fb6..13ddbdb702 100644
--- a/macros/Cargo.toml
+++ b/macros/Cargo.toml
@@ -4,7 +4,7 @@ edition = "2021"
license = "GPL-3.0"
name = "namada_macros"
resolver = "2"
-version = "0.16.0"
+version = "0.17.1"
[lib]
proc-macro = true
diff --git a/proof_of_stake/Cargo.toml b/proof_of_stake/Cargo.toml
index 2447b63500..3315e336ee 100644
--- a/proof_of_stake/Cargo.toml
+++ b/proof_of_stake/Cargo.toml
@@ -6,7 +6,7 @@ license = "GPL-3.0"
name = "namada_proof_of_stake"
readme = "../README.md"
resolver = "2"
-version = "0.16.0"
+version = "0.17.1"
[features]
default = ["abciplus"]
diff --git a/proof_of_stake/src/pos_queries.rs b/proof_of_stake/src/pos_queries.rs
index a92cd14ebe..251350e414 100644
--- a/proof_of_stake/src/pos_queries.rs
+++ b/proof_of_stake/src/pos_queries.rs
@@ -258,7 +258,7 @@ where
#[inline]
/// Retrieves the [`BlockHeight`] that is currently being decided.
pub fn get_current_decision_height(self) -> BlockHeight {
- self.wl_storage.storage.last_height + 1
+ self.wl_storage.storage.get_last_block_height() + 1
}
/// Retrieve the `max_proposal_bytes` consensus parameter from storage.
diff --git a/shared/Cargo.toml b/shared/Cargo.toml
index a4f207e998..469871f350 100644
--- a/shared/Cargo.toml
+++ b/shared/Cargo.toml
@@ -4,7 +4,7 @@ edition = "2021"
license = "GPL-3.0"
name = "namada"
resolver = "2"
-version = "0.16.0"
+version = "0.17.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/shared/src/ledger/queries/mod.rs b/shared/src/ledger/queries/mod.rs
index 8808478107..0f7c5769b9 100644
--- a/shared/src/ledger/queries/mod.rs
+++ b/shared/src/ledger/queries/mod.rs
@@ -57,7 +57,7 @@ where
H: 'static + StorageHasher + Sync,
{
if request.height != BlockHeight(0)
- && request.height != ctx.wl_storage.storage.last_height
+ && request.height != ctx.wl_storage.storage.get_last_block_height()
{
return Err(storage_api::Error::new_const(
"This query doesn't support arbitrary block heights, only the \
diff --git a/shared/src/ledger/queries/shell.rs b/shared/src/ledger/queries/shell.rs
index e26e38a36d..6620d3b1f8 100644
--- a/shared/src/ledger/queries/shell.rs
+++ b/shared/src/ledger/queries/shell.rs
@@ -2,6 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
use masp_primitives::asset_type::AssetType;
use masp_primitives::merkle_tree::MerklePath;
use masp_primitives::sapling::Node;
+use namada_core::ledger::storage::LastBlock;
use namada_core::types::address::Address;
use namada_core::types::hash::Hash;
use namada_core::types::storage::{BlockResults, KeySeg};
@@ -29,6 +30,9 @@ router! {SHELL,
// Epoch of the last committed block
( "epoch" ) -> Epoch = epoch,
+ // Query the last committed block
+ ( "last_block" ) -> Option = last_block,
+
// Raw storage access - read value
( "value" / [storage_key: storage::Key] )
-> Vec = (with_options storage_value),
@@ -184,6 +188,16 @@ where
Ok(data)
}
+fn last_block(
+ ctx: RequestCtx<'_, D, H>,
+) -> storage_api::Result