From 1684774dfc66af2bf49b01899e7b299089f47e58 Mon Sep 17 00:00:00 2001 From: noot <36753753+noot@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:52:05 -0400 Subject: [PATCH] feat(sequencer)!: update to ABCI v0.38 (#831) ## Summary updates the sequencer app to use ABCI v0.38, which replaces `begin_block`/`deliver_tx`/`end_block` with one call, `finalize_block`. relevant penumbra PRs: - update penumbra-tower-trace to re-add instrumentation to the ABCI methods (done in https://github.com/penumbra-zone/penumbra/pull/4160) - update cnidarium to be able to get the root hash of the state without calling `commit` (done in https://github.com/penumbra-zone/penumbra/pull/4122) ## Background this was inevitable, also it cleans up the block execution flow inside the sequencer application. (removed `processed_txs` and `current_sequencer_block_builder` from the app) ## Changes - implement `finalize_block`; for the most part, I left the `begin_block`/`deliver_tx`/`end_block` as they are but called them inside `finalize_block` - however the block execution flow is cleaned up as we no longer need to track how many txs have been delivered (for the commitments) and we can construct the `SequencerBlock` at the end of `finalize_block` without needing to track things between calls ## Testing unit tests ran it with cometbft release [v0.38.6](https://github.com/cometbft/cometbft/releases/tag/v0.38.6) ## Breaking Changelist - the sequencer app will now only work with a cometbft version that supports ABCI v0.38 ## Related Issues closes #679 --- Cargo.lock | 231 +++---- Cargo.toml | 7 +- charts/sequencer/Chart.yaml | 2 +- charts/sequencer/values.yaml | 4 +- crates/astria-sequencer/Cargo.toml | 6 +- crates/astria-sequencer/README.md | 2 +- crates/astria-sequencer/TESTNET.md | 2 +- crates/astria-sequencer/src/app.rs | 604 ++++++++++-------- crates/astria-sequencer/src/sequencer.rs | 7 +- .../astria-sequencer/src/service/consensus.rs | 166 ++--- .../astria-sequencer/src/service/info/mod.rs | 8 +- .../astria-sequencer/src/service/mempool.rs | 8 +- .../astria-sequencer/src/service/snapshot.rs | 5 +- 13 files changed, 484 insertions(+), 568 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72c87abdc1..bf1f474866 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "ark-bls12-377" @@ -742,7 +742,7 @@ dependencies = [ "astria-merkle", "astria-telemetry", "async-trait", - "borsh 1.4.0", + "borsh", "bytes", "cnidarium", "cnidarium-component", @@ -940,9 +940,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2 1.0.79", "quote", @@ -1298,39 +1298,16 @@ dependencies = [ "thiserror", ] -[[package]] -name = "borsh" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" -dependencies = [ - "borsh-derive 0.10.3", - "hashbrown 0.13.2", -] - [[package]] name = "borsh" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6" dependencies = [ - "borsh-derive 1.4.0", + "borsh-derive", "cfg_aliases", ] -[[package]] -name = "borsh-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2 1.0.79", - "syn 1.0.109", -] - [[package]] name = "borsh-derive" version = "1.4.0" @@ -1345,28 +1322,6 @@ dependencies = [ "syn_derive", ] -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ - "proc-macro2 1.0.79", - "quote", - "syn 1.0.109", -] - [[package]] name = "bs58" version = "0.5.1" @@ -1390,9 +1345,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-slice-cast" @@ -1476,9 +1431,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" dependencies = [ "jobserver", "libc", @@ -1753,12 +1708,12 @@ dependencies = [ [[package]] name = "cnidarium" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "async-trait", - "borsh 0.10.3", + "borsh", "futures", "hex", "ibc-types", @@ -1781,8 +1736,8 @@ dependencies = [ [[package]] name = "cnidarium-component" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "async-trait", @@ -2244,8 +2199,8 @@ dependencies = [ [[package]] name = "decaf377-fmd" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "ark-ff 0.4.2", "ark-serialize 0.4.2", @@ -2258,8 +2213,8 @@ dependencies = [ [[package]] name = "decaf377-ka" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "ark-ff 0.4.2", "decaf377 0.5.0", @@ -2589,9 +2544,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -3060,9 +3015,9 @@ dependencies = [ [[package]] name = "figment" -version = "0.10.15" +version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7270677e7067213e04f323b55084586195f18308cd7546cfac9f873344ccceb6" +checksum = "fdefe49ed1057d124dc81a0681c30dd07de56ad96e32adc7b64e8f28eaab31c4" dependencies = [ "atomic", "parking_lot", @@ -3330,9 +3285,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "js-sys", @@ -4187,12 +4142,12 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jmt" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2950721a65dff82492e30fe67076127135d0d710aa0140f21efafda2aee7849" +checksum = "a9a3bf1a303934c6f75533bd3a563730a0730f9361023c49ed6aee9fcb5b98f8" dependencies = [ "anyhow", - "borsh 0.10.3", + "borsh", "digest 0.10.7", "hashbrown 0.13.2", "hex", @@ -4209,9 +4164,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "f08474e32172238f2827bd160c67871cdb2801430f65c3979184dc362e3ca118" dependencies = [ "libc", ] @@ -4772,9 +4727,9 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "names" @@ -5338,8 +5293,8 @@ dependencies = [ [[package]] name = "penumbra-asset" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "ark-ff 0.4.2", @@ -5376,8 +5331,8 @@ dependencies = [ [[package]] name = "penumbra-ibc" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "ark-ff 0.4.2", @@ -5411,8 +5366,8 @@ dependencies = [ [[package]] name = "penumbra-keys" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "aes", "anyhow", @@ -5455,8 +5410,8 @@ dependencies = [ [[package]] name = "penumbra-num" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "ark-ff 0.4.2", @@ -5491,8 +5446,8 @@ dependencies = [ [[package]] name = "penumbra-proto" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "async-trait", @@ -5520,8 +5475,8 @@ dependencies = [ [[package]] name = "penumbra-sct" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "ark-ff 0.4.2", @@ -5554,8 +5509,8 @@ dependencies = [ [[package]] name = "penumbra-tct" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "ark-ed-on-bls12-377", "ark-ff 0.4.2", @@ -5582,8 +5537,8 @@ dependencies = [ [[package]] name = "penumbra-tower-trace" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "futures", "hex", @@ -5604,8 +5559,8 @@ dependencies = [ [[package]] name = "penumbra-txhash" -version = "0.69.1" -source = "git+https://github.com/penumbra-zone/penumbra.git?tag=v0.69.1#b3e62ece950a55f25982c962c88dcfec0b603174" +version = "0.71.0" +source = "git+https://github.com/penumbra-zone/penumbra.git?rev=8b06546af43bf073fd99f3f9d82b8afb51872489#8b06546af43bf073fd99f3f9d82b8afb51872489" dependencies = [ "anyhow", "blake2b_simd 1.0.2", @@ -5788,7 +5743,7 @@ dependencies = [ "anyhow", "ark-ff 0.4.2", "ark-std 0.4.0", - "getrandom 0.2.12", + "getrandom 0.2.14", "merlin", "num", "num-bigint", @@ -5902,15 +5857,6 @@ dependencies = [ "uint", ] -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml 0.5.11", -] - [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -6011,9 +5957,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", "prost-derive", @@ -6021,13 +5967,13 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" +checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.11.0", + "heck 0.5.0", + "itertools 0.12.1", "log", "multimap", "once_cell", @@ -6038,17 +5984,16 @@ dependencies = [ "regex", "syn 2.0.58", "tempfile", - "which", ] [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2 1.0.79", "quote", "syn 2.0.58", @@ -6056,9 +6001,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" dependencies = [ "prost", ] @@ -6089,9 +6034,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2 1.0.79", ] @@ -6161,7 +6106,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.14", ] [[package]] @@ -6235,7 +6180,7 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.14", "libredox", "thiserror", ] @@ -6365,7 +6310,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.14", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -6596,9 +6541,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "ryu" @@ -6673,9 +6618,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.1" +version = "2.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" +checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" dependencies = [ "cfg-if", "derive_more", @@ -6685,9 +6630,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.1" +version = "2.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac" +checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.79", @@ -6890,9 +6835,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2 1.0.79", "quote", @@ -7390,9 +7335,9 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" -version = "0.34.1" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b8090d0eef9ad57b1b913b5e358e26145c86017e87338136509b94383a4af25" +checksum = "74994da9de4b1144837a367ca2c60c650f5526a7c1a54760a3020959b522e474" dependencies = [ "derive_more", "flex-error", @@ -7430,7 +7375,7 @@ dependencies = [ "bytes", "flex-error", "futures", - "getrandom 0.2.12", + "getrandom 0.2.14", "peg", "pin-project", "rand 0.8.5", @@ -7533,9 +7478,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -7556,9 +7501,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", @@ -7796,7 +7741,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.5", + "winnow 0.6.6", ] [[package]] @@ -7920,9 +7865,9 @@ dependencies = [ [[package]] name = "tower-abci" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4826f3df3e9a37083d978cae73f020bcdf6143956b7dfc1bd6050b4e16367c" +checksum = "6e2b02beb06df7f231ff03017b97c697a8b9fc93e2ed2ac227d783ee06a2e07b" dependencies = [ "bytes", "futures", @@ -8334,7 +8279,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.14", "serde", ] @@ -8711,9 +8656,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index d716312cbf..764dd0a545 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,9 +76,10 @@ serde_json = "1" metrics = "0.22.1" pbjson-types = "0.6" # Note that when updating the penumbra versions, vendored types in `proto/sequencerapis/astria_vendored` may need to be updated as well. -penumbra-ibc = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.69.1", default-features = false } -penumbra-proto = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.69.1" } -penumbra-tower-trace = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.69.1" } +# update once https://github.com/penumbra-zone/penumbra/commit/8b06546af43bf073fd99f3f9d82b8afb51872489 makes it into a release +penumbra-ibc = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "8b06546af43bf073fd99f3f9d82b8afb51872489", default-features = false } +penumbra-proto = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "8b06546af43bf073fd99f3f9d82b8afb51872489" } +penumbra-tower-trace = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "8b06546af43bf073fd99f3f9d82b8afb51872489" } prost = "0.12" rand = "0.8.5" regex = "1.9" diff --git a/charts/sequencer/Chart.yaml b/charts/sequencer/Chart.yaml index 25509b0317..46385f64fe 100644 --- a/charts/sequencer/Chart.yaml +++ b/charts/sequencer/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.11.5 +version: 0.11.6 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/sequencer/values.yaml b/charts/sequencer/values.yaml index 57222d62ca..892559fd9b 100644 --- a/charts/sequencer/values.yaml +++ b/charts/sequencer/values.yaml @@ -13,8 +13,8 @@ global: images: cometBFT: repo: docker.io/cometbft/cometbft - tag: v0.37.x - devTag: v0.37.x + tag: v0.38.6 + devTag: v0.38.6 sequencer: repo: ghcr.io/astriaorg/sequencer tag: "0.10.1" diff --git a/crates/astria-sequencer/Cargo.toml b/crates/astria-sequencer/Cargo.toml index 965fec06f5..ed76da436f 100644 --- a/crates/astria-sequencer/Cargo.toml +++ b/crates/astria-sequencer/Cargo.toml @@ -28,10 +28,10 @@ anyhow = "1" borsh = { version = "1", features = ["derive"] } matchit = "0.7.2" tower = "0.4" -tower-abci = "0.11.0" +tower-abci = "0.12.0" tower-actor = "0.1.0" -cnidarium = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.69.1" } -cnidarium-component = { git = "https://github.com/penumbra-zone/penumbra.git", tag = "v0.69.1" } +cnidarium = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "8b06546af43bf073fd99f3f9d82b8afb51872489" } +cnidarium-component = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "8b06546af43bf073fd99f3f9d82b8afb51872489" } async-trait = { workspace = true } bytes = { workspace = true } diff --git a/crates/astria-sequencer/README.md b/crates/astria-sequencer/README.md index 413256e1b4..b6a39774a9 100644 --- a/crates/astria-sequencer/README.md +++ b/crates/astria-sequencer/README.md @@ -50,7 +50,7 @@ Ensure `~/go` is in your `PATH`, or `GOPATH` is set to some other place in your ```sh git clone https://github.com/cometbft/cometbft cd cometbft -git checkout origin/v0.37.x +git checkout origin/v0.38.6 export GOPATH=~/go make install ``` diff --git a/crates/astria-sequencer/TESTNET.md b/crates/astria-sequencer/TESTNET.md index a3524f65e1..bf671d5eb7 100644 --- a/crates/astria-sequencer/TESTNET.md +++ b/crates/astria-sequencer/TESTNET.md @@ -10,7 +10,7 @@ Ensure `~/go` is in your `PATH`, or `GOPATH` is set to some other place in your ```sh git clone https://github.com/cometbft/cometbft cd cometbft -git checkout origin/v0.37.x +git checkout origin/v export GOPATH=~/go make install ``` diff --git a/crates/astria-sequencer/src/app.rs b/crates/astria-sequencer/src/app.rs index f45d52088a..aa87546a2b 100644 --- a/crates/astria-sequencer/src/app.rs +++ b/crates/astria-sequencer/src/app.rs @@ -16,19 +16,16 @@ use astria_core::{ generated::sequencer::v1 as raw, sequencer::v1::{ transaction::Action, + AbciErrorCode, Address, - RollupId, SignedTransaction, }, - sequencerblock::v1alpha1::block::{ - Deposit, - SequencerBlock, - }, + sequencerblock::v1alpha1::block::SequencerBlock, }; use cnidarium::{ ArcStateDeltaExt, - RootHash, Snapshot, + StagedWriteBatch, StateDelta, Storage, }; @@ -44,6 +41,7 @@ use tendermint::{ Event, }, account, + AppHash, Hash, }; use tracing::{ @@ -60,6 +58,7 @@ use crate::{ StateWriteExt as _, }, }, + api_state_ext::StateWriteExt as _, authority::{ component::{ AuthorityComponent, @@ -102,7 +101,6 @@ type InterBlockState = Arc>; /// See also the [Penumbra reference] implementation. /// /// [Penumbra reference]: https://github.com/penumbra-zone/penumbra/blob/9cc2c644e05c61d21fdc7b507b96016ba6b9a935/app/src/app/mod.rs#L42 -#[derive(Debug)] pub(crate) struct App { state: InterBlockState, @@ -129,25 +127,24 @@ pub(crate) struct App { // cleared at the end of each block. execution_result: HashMap<[u8; 32], anyhow::Result>>, - /// set to `0` when `begin_block` is called, and set to `1` or `2` when - /// `deliver_tx` is called for the first two times. - /// this is a hack to allow the `sequence_actions_commitment` and `chain_ids_commitment` - /// to pass `deliver_tx`, as they're the first two "tx"s delivered. - /// - /// when the app is fully updated to ABCI++, `begin_block`, `deliver_tx`, - /// and `end_block` will all become one function `finalize_block`, so - /// this will not be needed. - processed_txs: u32, - // proposer of the block being currently executed; set in begin_block // and cleared in end_block. // this is used only to determine who to transfer the block fees to // at the end of the block. current_proposer: Option, - // builder of the current `SequencerBlock`. - // initialized during `begin_block`, completed and written to state during `end_block`. - current_sequencer_block_builder: Option, + // the current `StagedWriteBatch` which contains the rocksdb write batch + // of the current block being executed, created from the state delta, + // and set after `finalize_block`. + // this is committed to the state when `commit` is called, and set to `None`. + write_batch: Option, + + // the currently committed `AppHash` of the application state. + // set whenever `commit` is called. + // + // allow clippy because we need be specific as to what hash this is. + #[allow(clippy::struct_field_names)] + app_hash: AppHash, } impl App { @@ -163,19 +160,20 @@ impl App { validator_address: None, executed_proposal_hash: Hash::default(), execution_result: HashMap::new(), - processed_txs: 0, current_proposer: None, - current_sequencer_block_builder: None, + write_batch: None, + app_hash: AppHash::default(), } } #[instrument(name = "App:init_chain", skip_all)] pub(crate) async fn init_chain( &mut self, + storage: Storage, genesis_state: GenesisState, genesis_validators: Vec, chain_id: String, - ) -> anyhow::Result<()> { + ) -> anyhow::Result { let mut state_tx = self .state .try_begin_transaction() @@ -208,7 +206,13 @@ impl App { .context("failed to call init_chain on IbcComponent")?; state_tx.apply(); - Ok(()) + + let app_hash = self + .prepare_commit(storage) + .await + .context("failed to prepare commit")?; + debug!(app_hash = %telemetry::display::base64(&app_hash), "init_chain completed"); + Ok(app_hash) } fn update_state_for_new_round(&mut self, storage: &Storage) { @@ -220,7 +224,6 @@ impl App { // clear the cache of transaction execution results self.execution_result.clear(); - self.processed_txs = 0; self.executed_proposal_hash = Hash::default(); } @@ -503,22 +506,206 @@ impl App { tx_hash } + #[instrument(name = "App::finalize_block", skip_all)] + pub(crate) async fn finalize_block( + &mut self, + finalize_block: abci::request::FinalizeBlock, + storage: Storage, + ) -> anyhow::Result { + use tendermint::{ + abci::types::ExecTxResult, + block::Header, + }; + + use crate::transaction::InvalidNonce; + + let data_hash = astria_core::sequencerblock::v1alpha1::block::merkle_tree_from_data( + finalize_block.txs.iter().map(std::convert::AsRef::as_ref), + ) + .root(); + + let chain_id: tendermint::chain::Id = self + .state + .get_chain_id() + .await + .context("failed to get chain ID from state")? + .try_into() + .context("invalid chain ID")?; + + // call begin_block on all components + // NOTE: the fields marked `unused` are not used by any of the components; + // however, we need to still construct a `BeginBlock` type for now as + // the penumbra IBC implementation still requires it as a parameter. + let begin_block = abci::request::BeginBlock { + hash: finalize_block.hash, + byzantine_validators: finalize_block.misbehavior.clone(), + header: Header { + app_hash: self.app_hash.clone(), + chain_id: chain_id.clone(), + consensus_hash: Hash::default(), // unused + data_hash: Some(Hash::try_from(data_hash.to_vec()).unwrap()), + evidence_hash: Some(Hash::default()), // unused + height: finalize_block.height, + last_block_id: None, // unused + last_commit_hash: Some(Hash::default()), // unused + last_results_hash: Some(Hash::default()), // unused + next_validators_hash: finalize_block.next_validators_hash, + proposer_address: finalize_block.proposer_address, + time: finalize_block.time, + validators_hash: Hash::default(), // unused + version: tendermint::block::header::Version { + // unused + app: 0, + block: 0, + }, + }, + last_commit_info: finalize_block.decided_last_commit.clone(), + }; + + self.begin_block(&begin_block, storage.clone()) + .await + .context("failed to call begin_block")?; + + ensure!( + finalize_block.txs.len() >= 2, + "block must contain at least two transactions: the rollup transactions commitment and \ + rollup IDs commitment" + ); + + // cometbft expects a result for every tx in the block, so we need to return a + // tx result for the commitments, even though they're not actually user txs. + let mut tx_results: Vec = Vec::with_capacity(finalize_block.txs.len()); + tx_results.extend(std::iter::repeat(ExecTxResult::default()).take(2)); + + for tx in finalize_block.txs.iter().skip(2) { + match self.deliver_tx_after_proposal(tx).await { + Ok(events) => tx_results.push(ExecTxResult { + events, + ..Default::default() + }), + Err(e) => { + // this is actually a protocol error, as only valid txs should be finalized + tracing::error!( + error = AsRef::::as_ref(&e), + "failed to finalize transaction; ignoring it", + ); + let code = if e.downcast_ref::().is_some() { + AbciErrorCode::INVALID_NONCE + } else { + AbciErrorCode::INTERNAL_ERROR + }; + tx_results.push(ExecTxResult { + code: code.into(), + info: code.to_string(), + log: format!("{e:?}"), + ..Default::default() + }); + } + } + } + + let end_block = self + .end_block(&abci::request::EndBlock { + height: finalize_block.height.into(), + }) + .await?; + + // get and clear block deposits from state + let mut state_tx = StateDelta::new(self.state.clone()); + let deposits = self + .state + .get_block_deposits() + .await + .context("failed to get block deposits in end_block")?; + state_tx + .clear_block_deposits() + .await + .context("failed to clear block deposits")?; + + let Hash::Sha256(block_hash) = finalize_block.hash else { + anyhow::bail!("finalized block hash is empty; this should not occur") + }; + + let sequencer_block = SequencerBlock::try_from_block_info_and_data( + block_hash, + chain_id, + finalize_block.height, + finalize_block.time, + finalize_block.proposer_address, + finalize_block + .txs + .into_iter() + .map(std::convert::Into::into) + .collect(), + deposits, + ) + .context("failed to convert block info and data to SequencerBlock")?; + state_tx + .put_sequencer_block(sequencer_block) + .context("failed to write sequencer block to state")?; + // events that occur after end_block are ignored here; + // there should be none anyways. + let _ = self.apply(state_tx); + + // prepare the `StagedWriteBatch` for a later commit. + let app_hash = self + .prepare_commit(storage.clone()) + .await + .context("failed to prepare commit")?; + + Ok(abci::response::FinalizeBlock { + events: end_block.events, + validator_updates: end_block.validator_updates, + consensus_param_updates: end_block.consensus_param_updates, + tx_results, + app_hash, + }) + } + + async fn prepare_commit(&mut self, storage: Storage) -> anyhow::Result { + // extract the state we've built up to so we can prepare it as a `StagedWriteBatch`. + let dummy_state = StateDelta::new(storage.latest_snapshot()); + let mut state = Arc::try_unwrap(std::mem::replace(&mut self.state, Arc::new(dummy_state))) + .expect("we have exclusive ownership of the State at commit()"); + + // store the storage version indexed by block height + let new_version = storage.latest_version().wrapping_add(1); + let height = state + .get_block_height() + .await + .expect("block height must be set, as `put_block_height` was already called"); + state.put_storage_version_by_height(height, new_version); + debug!( + height, + version = new_version, + "stored storage version for height" + ); + + let write_batch = storage + .prepare_commit(state) + .await + .context("failed to prepare commit")?; + let app_hash = write_batch + .root_hash() + .0 + .to_vec() + .try_into() + .context("failed to convert app hash")?; + self.write_batch = Some(write_batch); + Ok(app_hash) + } + #[instrument(name = "App::begin_block", skip_all)] pub(crate) async fn begin_block( &mut self, begin_block: &abci::request::BeginBlock, storage: Storage, ) -> anyhow::Result> { - // clear the processed_txs count when beginning block execution - self.processed_txs = 0; // set the current proposer self.current_proposer = Some(begin_block.header.proposer_address); - self.current_sequencer_block_builder = - Some(SequencerBlockBuilder::new(begin_block.header.clone())); - - // If we previously executed txs in a different proposal than is being processed reset - // cached state changes. + // If we previously executed txs in a different proposal than is being processed, + // reset cached state changes. if self.executed_proposal_hash != begin_block.hash { self.update_state_for_new_round(&storage); } @@ -559,44 +746,24 @@ impl App { /// Note that the first two "transactions" in the block, which are the proposer-generated /// commitments, are ignored. #[instrument(name = "App::deliver_tx_after_proposal", skip_all, fields( - tx_hash = %telemetry::display::base64(&Sha256::digest(&tx.tx)), + tx_hash = %telemetry::display::base64(&Sha256::digest(tx)), ))] pub(crate) async fn deliver_tx_after_proposal( &mut self, - tx: abci::request::DeliverTx, - ) -> Option>> { - self.current_sequencer_block_builder - .as_mut() - .expect( - "begin_block must be called before deliver_tx, thus \ - current_sequencer_block_builder must be set", - ) - .push_transaction(tx.tx.to_vec()); - - if self.processed_txs < 2 { - self.processed_txs += 1; - return Some(Ok(vec![])); - } - + tx: &bytes::Bytes, + ) -> anyhow::Result> { // When the hash is not empty, we have already executed and cached the results if !self.executed_proposal_hash.is_empty() { - let tx_hash: [u8; 32] = sha2::Sha256::digest(&tx.tx).into(); - return self.execution_result.remove(&tx_hash); + let tx_hash: [u8; 32] = sha2::Sha256::digest(tx).into(); + return self + .execution_result + .remove(&tx_hash) + .unwrap_or_else(|| Err(anyhow!("transaction not executed during proposal phase"))); } - let signed_tx = match signed_transaction_from_bytes(&tx.tx) { - Err(e) => { - // this is actually a protocol error, as only valid txs should be finalized - debug!( - error = AsRef::::as_ref(&e), - "failed to decode deliver tx payload to signed transaction; ignoring it", - ); - return None; - } - Ok(tx) => tx, - }; - - Some(self.deliver_tx(signed_tx).await) + let signed_tx = signed_transaction_from_bytes(tx) + .context("protocol error; only valid txs should be finalized")?; + self.deliver_tx(signed_tx).await } /// Executes a signed transaction. @@ -658,8 +825,6 @@ impl App { &mut self, end_block: &abci::request::EndBlock, ) -> anyhow::Result { - use crate::api_state_ext::StateWriteExt as _; - let state_tx = StateDelta::new(self.state.clone()); let mut arc_state_tx = Arc::new(state_tx); @@ -718,38 +883,6 @@ impl App { state_tx.clear_block_fees().await; self.current_proposer = None; - // get and clear block deposits from state - let deposits = self - .state - .get_block_deposits() - .await - .context("failed to get block deposits in end_block")?; - self.current_sequencer_block_builder - .as_mut() - .expect( - "begin_block must be called before end_block, thus \ - current_sequencer_block_builder must be set", - ) - .deposits(deposits); - state_tx - .clear_block_deposits() - .await - .context("failed to clear block deposits")?; - - // store the `SequencerBlock` in the state - let sequencer_block = self - .current_sequencer_block_builder - .take() - .expect( - "begin_block must be called before end_block, thus \ - current_sequencer_block_builder must be set", - ) - .build() - .context("failed to build sequencer block")?; - state_tx - .put_sequencer_block(sequencer_block) - .context("failed to write sequencer block to state")?; - let events = self.apply(state_tx); Ok(abci::response::EndBlock { @@ -760,40 +893,25 @@ impl App { } #[instrument(name = "App::commit", skip_all)] - pub(crate) async fn commit(&mut self, storage: Storage) -> RootHash { - // We need to extract the State we've built up to commit it. Fill in a dummy state. - let dummy_state = StateDelta::new(storage.latest_snapshot()); - - let mut state = Arc::try_unwrap(std::mem::replace(&mut self.state, Arc::new(dummy_state))) - .expect("we have exclusive ownership of the State at commit()"); - - // store the storage version indexed by block height - let new_version = storage.latest_version().wrapping_add(1); - let height = state - .get_block_height() - .await - .expect("block height must be set, as `begin_block` is always called before `commit`"); - state.put_storage_version_by_height(height, new_version); - debug!( - height, - version = new_version, - "stored storage version for height" - ); - + pub(crate) async fn commit(&mut self, storage: Storage) { // Commit the pending writes, clearing the state. let app_hash = storage - .commit(state) - .await + .commit_batch(self.write_batch.take().expect( + "write batch must be set, as `finalize_block` is always called before `commit`", + )) .expect("must be able to successfully commit to storage"); tracing::debug!( app_hash = %telemetry::display::base64(&app_hash), "finished committing state", ); + self.app_hash = app_hash + .0 + .to_vec() + .try_into() + .expect("root hash to app hash conversion must succeed"); // Get the latest version of the state, now that we've committed it. self.state = Arc::new(StateDelta::new(storage.latest_snapshot())); - - app_hash } // StateDelta::apply only works when the StateDelta wraps an underlying @@ -818,36 +936,6 @@ impl App { } } -#[derive(Debug)] -struct SequencerBlockBuilder { - header: tendermint::block::Header, - data: Vec>, - deposits: HashMap>, -} - -impl SequencerBlockBuilder { - fn new(header: tendermint::block::Header) -> Self { - Self { - header, - data: Vec::new(), - deposits: HashMap::new(), - } - } - - fn push_transaction(&mut self, tx: Vec) { - self.data.push(tx); - } - - fn deposits(&mut self, deposits: HashMap>) { - self.deposits = deposits; - } - - fn build(self) -> anyhow::Result { - SequencerBlock::try_from_cometbft_header_and_data(self.header, self.data, self.deposits) - .map_err(Into::into) - } -} - fn signed_transaction_from_bytes(bytes: &[u8]) -> anyhow::Result { let raw = raw::SignedTransaction::decode(bytes) .context("failed to decode protobuf to signed transaction")?; @@ -893,17 +981,21 @@ pub(crate) mod test_utils { mod test { #[cfg(feature = "mint")] use astria_core::sequencer::v1::transaction::action::MintAction; - use astria_core::sequencer::v1::{ - asset, - asset::DEFAULT_NATIVE_ASSET_DENOM, - transaction::action::{ - BridgeLockAction, - IbcRelayerChangeAction, - SequenceAction, - SudoAddressChangeAction, - TransferAction, + use astria_core::{ + sequencer::v1::{ + asset, + asset::DEFAULT_NATIVE_ASSET_DENOM, + transaction::action::{ + BridgeLockAction, + IbcRelayerChangeAction, + SequenceAction, + SudoAddressChangeAction, + TransferAction, + }, + RollupId, + UnsignedTransaction, }, - UnsignedTransaction, + sequencerblock::v1alpha1::block::Deposit, }; use ed25519_consensus::SigningKey; use penumbra_ibc::params::IBCParameters; @@ -915,7 +1007,6 @@ mod test { Height, Round, }, - AppHash, Time, }; @@ -990,9 +1081,15 @@ mod test { allowed_fee_assets: vec![DEFAULT_NATIVE_ASSET_DENOM.to_owned().into()], }); - app.init_chain(genesis_state, genesis_validators, "test".to_string()) - .await - .unwrap(); + app.init_chain( + storage.clone(), + genesis_state, + genesis_validators, + "test".to_string(), + ) + .await + .unwrap(); + app.commit(storage.clone()).await; (app, storage.clone()) } @@ -1932,9 +2029,6 @@ mod test { .unwrap(); app.apply(state_tx); - let (_, sequencer_block_builder) = block_data_from_txs_no_sequence_actions(vec![]); - app.current_sequencer_block_builder = Some(sequencer_block_builder); - let resp = app .end_block(&abci::request::EndBlock { height: 1u32.into(), @@ -2033,9 +2127,12 @@ mod test { } // commit should write the changes to the underlying storage + app.prepare_commit(storage.clone()).await.unwrap(); app.commit(storage.clone()).await; + let snapshot = storage.latest_snapshot(); assert_eq!(snapshot.get_block_height().await.unwrap(), 0); + for Account { address, balance, @@ -2075,46 +2172,35 @@ mod test { }; let signed_tx = tx.into_signed(&alice_signing_key); - let (header, sequencer_block_builder) = - block_data_from_txs_no_sequence_actions(vec![signed_tx.to_raw().encode_to_vec()]); - let mut begin_block = abci::request::BeginBlock { - header, - hash: Hash::default(), - last_commit_info: CommitInfo { + let proposer_address: tendermint::account::Id = [99u8; 20].to_vec().try_into().unwrap(); + let sequencer_proposer_address = + Address::try_from_slice(proposer_address.as_bytes()).unwrap(); + + let commitments = generate_rollup_datas_commitment(&[signed_tx.clone()], HashMap::new()); + + let finalize_block = abci::request::FinalizeBlock { + hash: Hash::try_from([0u8; 32].to_vec()).unwrap(), + height: 1u32.into(), + time: Time::now(), + next_validators_hash: Hash::default(), + proposer_address, + txs: commitments.into_transactions(vec![signed_tx.to_raw().encode_to_vec().into()]), + decided_last_commit: CommitInfo { votes: vec![], round: Round::default(), }, - byzantine_validators: vec![], + misbehavior: vec![], }; - begin_block.header.height = 1u8.into(); - let proposer_address = - Address::try_from_slice(begin_block.header.proposer_address.as_bytes()).unwrap(); - - app.begin_block(&begin_block, storage).await.unwrap(); - assert_eq!(app.state.get_block_height().await.unwrap(), 1); - assert_eq!( - app.state.get_block_timestamp().await.unwrap(), - begin_block.header.time - ); - assert_eq!( - app.current_proposer.unwrap(), - begin_block.header.proposer_address - ); - - app.deliver_tx(signed_tx).await.unwrap(); - - app.current_sequencer_block_builder = Some(sequencer_block_builder); - app.end_block(&abci::request::EndBlock { - height: 1u32.into(), - }) - .await - .unwrap(); + app.finalize_block(finalize_block, storage.clone()) + .await + .unwrap(); + app.commit(storage).await; // assert that transaction fees were transferred to the block proposer assert_eq!( app.state - .get_account_balance(proposer_address, native_asset) + .get_account_balance(sequencer_proposer_address, native_asset) .await .unwrap(), TRANSFER_FEE, @@ -2124,6 +2210,13 @@ mod test { #[tokio::test] async fn app_create_sequencer_block_with_sequenced_data_and_deposits() { + use astria_core::{ + generated::sequencerblock::v1alpha1::RollupData as RawRollupData, + sequencerblock::v1alpha1::block::RollupData, + }; + + use crate::api_state_ext::StateReadExt as _; + let (alice_signing_key, _) = get_alice_signing_key_and_address(); let (mut app, storage) = initialize_app_with_storage(None, vec![]).await; @@ -2137,6 +2230,8 @@ mod test { .put_bridge_account_asset_ids(&bridge_address, &[asset_id]) .unwrap(); app.apply(state_tx); + app.prepare_commit(storage.clone()).await.unwrap(); + app.commit(storage.clone()).await; let amount = 100; let lock_action = BridgeLockAction { @@ -2166,101 +2261,44 @@ mod test { "nootwashere".to_string(), ); let deposits = HashMap::from_iter(vec![(rollup_id, vec![expected_deposit.clone()])]); + let commitments = generate_rollup_datas_commitment(&[signed_tx.clone()], deposits.clone()); - let (header, commitments) = - block_data_from_txs_with_sequence_actions_and_deposits(&[signed_tx.clone()], deposits); - - let begin_block = abci::request::BeginBlock { - header, - hash: Hash::default(), - last_commit_info: CommitInfo { + let finalize_block = abci::request::FinalizeBlock { + hash: Hash::try_from([0u8; 32].to_vec()).unwrap(), + height: 1u32.into(), + time: Time::now(), + next_validators_hash: Hash::default(), + proposer_address: [0u8; 20].to_vec().try_into().unwrap(), + txs: commitments.into_transactions(vec![signed_tx.to_raw().encode_to_vec().into()]), + decided_last_commit: CommitInfo { votes: vec![], round: Round::default(), }, - byzantine_validators: vec![], + misbehavior: vec![], }; - app.begin_block(&begin_block, storage).await.unwrap(); - - // deliver the commitments and the signed tx to simulate the - // action block execution and put them in the `app.current_sequencer_block_builder` - app.deliver_tx_after_proposal(abci::request::DeliverTx { - tx: commitments.rollup_datas_root.to_vec().into(), - }) - .await - .unwrap() - .unwrap(); - app.deliver_tx_after_proposal(abci::request::DeliverTx { - tx: commitments.rollup_ids_root.to_vec().into(), - }) - .await - .unwrap() - .unwrap(); - app.deliver_tx_after_proposal(abci::request::DeliverTx { - tx: signed_tx.to_raw().encode_to_vec().into(), - }) - .await - .unwrap() - .unwrap(); - let deposits = app.state.get_deposit_events(&rollup_id).await.unwrap(); - assert_eq!(deposits.len(), 1); - assert_eq!(deposits[0], expected_deposit); - - app.end_block(&abci::request::EndBlock { - height: 1u32.into(), - }) - .await - .unwrap(); + app.finalize_block(finalize_block, storage.clone()) + .await + .unwrap(); + app.commit(storage).await; // ensure deposits are cleared at the end of the block let deposit_events = app.state.get_deposit_events(&rollup_id).await.unwrap(); assert_eq!(deposit_events.len(), 0); - } - - fn block_data_from_txs_no_sequence_actions( - txs: Vec>, - ) -> (Header, SequencerBlockBuilder) { - let empty_hash = merkle::Tree::from_leaves(Vec::>::new()).root(); - let mut block_data = vec![empty_hash.to_vec(), empty_hash.to_vec()]; - block_data.extend(txs); - - let data_hash = merkle::Tree::from_leaves(block_data.iter().map(Sha256::digest)).root(); - let mut header = default_header(); - header.data_hash = Some(Hash::try_from(data_hash.to_vec()).unwrap()); - - let mut sequencer_block_builder = SequencerBlockBuilder::new(header.clone()); - for tx in block_data { - sequencer_block_builder.push_transaction(tx); - } - (header, sequencer_block_builder) - } - fn block_data_from_txs_with_sequence_actions_and_deposits( - txs: &[SignedTransaction], - deposits: HashMap>, - ) -> (Header, GeneratedCommitments) { - let GeneratedCommitments { - rollup_datas_root, - rollup_ids_root, - } = generate_rollup_datas_commitment(txs, deposits.clone()); - let mut block_data = vec![rollup_datas_root.to_vec(), rollup_ids_root.to_vec()]; - block_data.extend(txs.iter().map(|tx| tx.to_raw().encode_to_vec())); - - let data_hash = merkle::Tree::from_leaves(block_data.iter().map(Sha256::digest)).root(); - let mut header = default_header(); - header.data_hash = Some(Hash::try_from(data_hash.to_vec()).unwrap()); - - let mut sequencer_block_builder = SequencerBlockBuilder::new(header.clone()); - for tx in block_data { - sequencer_block_builder.push_transaction(tx); + let block = app.state.get_sequencer_block_by_height(1).await.unwrap(); + let mut deposits = vec![]; + for (_, rollup_data) in block.rollup_transactions() { + for tx in rollup_data.transactions() { + let rollup_data = + RollupData::try_from_raw(RawRollupData::decode(tx.as_slice()).unwrap()) + .unwrap(); + if let RollupData::Deposit(deposit) = rollup_data { + deposits.push(deposit); + } + } } - sequencer_block_builder.deposits = deposits; - ( - header, - GeneratedCommitments { - rollup_datas_root, - rollup_ids_root, - }, - ) + assert_eq!(deposits.len(), 1); + assert_eq!(deposits[0], expected_deposit); } #[tokio::test] diff --git a/crates/astria-sequencer/src/sequencer.rs b/crates/astria-sequencer/src/sequencer.rs index 3895a3ef89..da66d4f3b0 100644 --- a/crates/astria-sequencer/src/sequencer.rs +++ b/crates/astria-sequencer/src/sequencer.rs @@ -6,9 +6,9 @@ use anyhow::{ use astria_core::generated::sequencerblock::v1alpha1::sequencer_service_server::SequencerServiceServer; use penumbra_tower_trace::{ trace::request_span, - v037::RequestExt as _, + v038::RequestExt as _, }; -use tendermint::v0_37::abci::ConsensusRequest; +use tendermint::v0_38::abci::ConsensusRequest; use tokio::{ select, signal::unix::{ @@ -21,7 +21,7 @@ use tokio::{ }, task::JoinHandle, }; -use tower_abci::v037::Server; +use tower_abci::v038::Server; use tracing::{ error, info, @@ -87,6 +87,7 @@ impl Sequencer { } let app = App::new(snapshot); + let consensus_service = tower::ServiceBuilder::new() .layer(request_span::layer(|req: &ConsensusRequest| { req.create_span() diff --git a/crates/astria-sequencer/src/service/consensus.rs b/crates/astria-sequencer/src/service/consensus.rs index 8f02db57e7..9703d5ecac 100644 --- a/crates/astria-sequencer/src/service/consensus.rs +++ b/crates/astria-sequencer/src/service/consensus.rs @@ -2,13 +2,8 @@ use anyhow::{ bail, Context, }; -use astria_core::sequencer::v1::AbciErrorCode; use cnidarium::Storage; -use sha2::{ - Digest as _, - Sha256, -}; -use tendermint::v0_37::abci::{ +use tendermint::v0_38::abci::{ request, response, ConsensusRequest, @@ -62,7 +57,7 @@ impl Consensus { warn!( parent: &span, error = e, - "failed processing concensus request; returning error back to sender", + "failed processing consensus request; returning error back to sender", ); } // `send` returns the sent message if sending fail, so we are dropping it. @@ -108,18 +103,18 @@ impl Consensus { }, ) } - ConsensusRequest::BeginBlock(begin_block) => ConsensusResponse::BeginBlock( - self.begin_block(begin_block) - .await - .context("failed to begin block")?, - ), - ConsensusRequest::DeliverTx(deliver_tx) => { - ConsensusResponse::DeliverTx(self.deliver_tx(deliver_tx).await) + ConsensusRequest::ExtendVote(_) => { + ConsensusResponse::ExtendVote(response::ExtendVote { + vote_extension: vec![].into(), + }) } - ConsensusRequest::EndBlock(end_block) => ConsensusResponse::EndBlock( - self.end_block(end_block) + ConsensusRequest::VerifyVoteExtension(_) => { + ConsensusResponse::VerifyVoteExtension(response::VerifyVoteExtension::Accept) + } + ConsensusRequest::FinalizeBlock(finalize_block) => ConsensusResponse::FinalizeBlock( + self.finalize_block(finalize_block) .await - .context("failed to end block")?, + .context("failed to finalize block")?, ), ConsensusRequest::Commit => { ConsensusResponse::Commit(self.commit().await.context("failed to commit")?) @@ -143,23 +138,20 @@ impl Consensus { let genesis_state: GenesisState = serde_json::from_slice(&init_chain.app_state_bytes) .context("failed to parse app_state in genesis file")?; - self.app + let app_hash = self + .app .init_chain( + self.storage.clone(), genesis_state, init_chain.validators.clone(), init_chain.chain_id, ) .await .context("failed to call init_chain")?; + self.app.commit(self.storage.clone()).await; - // commit the state and return the app hash - let app_hash = self.app.commit(self.storage.clone()).await; Ok(response::InitChain { - app_hash: app_hash - .0 - .to_vec() - .try_into() - .context("failed to convert app hash")?, + app_hash, consensus_params: Some(init_chain.consensus_params), validators: init_chain.validators, }) @@ -193,80 +185,33 @@ impl Consensus { ) -> anyhow::Result<()> { self.app .process_proposal(process_proposal, self.storage.clone()) - .await + .await?; + tracing::debug!("proposal processed"); + Ok(()) } #[instrument(skip_all, fields( - hash = %begin_block.hash, - height = %begin_block.header.height, - time = %begin_block.header.time, - proposer = %begin_block.header.proposer_address + hash = %finalize_block.hash, + height = %finalize_block.height, + time = %finalize_block.time, + proposer = %finalize_block.proposer_address ))] - async fn begin_block( + async fn finalize_block( &mut self, - begin_block: request::BeginBlock, - ) -> anyhow::Result { - let events = self + finalize_block: request::FinalizeBlock, + ) -> anyhow::Result { + let finalize_block = self .app - .begin_block(&begin_block, self.storage.clone()) + .finalize_block(finalize_block, self.storage.clone()) .await - .context("failed to call App::begin_block")?; - Ok(response::BeginBlock { - events, - }) - } - - #[instrument(skip_all, fields( - tx_hash = %telemetry::display::base64(&Sha256::digest(&deliver_tx.tx)) - ))] - async fn deliver_tx(&mut self, deliver_tx: request::DeliverTx) -> response::DeliverTx { - use crate::transaction::InvalidNonce; - - match self - .app - .deliver_tx_after_proposal(deliver_tx) - .await - .expect("transactions must be executable or previously executed during proposal phases") - { - Ok(events) => response::DeliverTx { - events, - ..Default::default() - }, - Err(e) => { - let code = if e.downcast_ref::().is_some() { - AbciErrorCode::INVALID_NONCE - } else { - AbciErrorCode::INTERNAL_ERROR - }; - tracing::warn!( - error = AsRef::::as_ref(&e), - "failed serving deliver tx request" - ); - response::DeliverTx { - code: code.into(), - info: code.to_string(), - log: e.to_string(), - ..Default::default() - } - } - } - } - - #[instrument(skip_all, fields(height = %end_block.height))] - async fn end_block( - &mut self, - end_block: request::EndBlock, - ) -> anyhow::Result { - self.app.end_block(&end_block).await + .context("failed to call App::finalize_block")?; + Ok(finalize_block) } #[instrument(skip_all)] async fn commit(&mut self) -> anyhow::Result { - let app_hash = self.app.commit(self.storage.clone()).await; - Ok(response::Commit { - data: app_hash.0.to_vec().into(), - ..Default::default() - }) + self.app.commit(self.storage.clone()).await; + Ok(response::Commit::default()) } } @@ -536,7 +481,7 @@ mod test { let storage = cnidarium::TempStorage::new().await.unwrap(); let snapshot = storage.latest_snapshot(); let mut app = App::new(snapshot); - app.init_chain(genesis_state, vec![], "test".to_string()) + app.init_chain(storage.clone(), genesis_state, vec![], "test".to_string()) .await .unwrap(); app.commit(storage.clone()).await; @@ -547,6 +492,8 @@ mod test { #[tokio::test] async fn block_lifecycle() { + use sha2::Digest as _; + let signing_key = SigningKey::new(OsRng); let mut consensus_service = new_consensus_service(Some(signing_key.verification_key())).await; @@ -558,7 +505,8 @@ mod test { let res = generate_rollup_datas_commitment(&vec![signed_tx], HashMap::new()); let block_data = res.into_transactions(txs.clone()); - let data_hash = merkle::Tree::from_leaves(block_data.iter().map(Sha256::digest)).root(); + let data_hash = + merkle::Tree::from_leaves(block_data.iter().map(sha2::Sha256::digest)).root(); let mut header = default_header(); header.data_hash = Some(Hash::try_from(data_hash.to_vec()).unwrap()); @@ -568,39 +516,21 @@ mod test { .await .unwrap(); - let begin_block = request::BeginBlock { - hash: Hash::default(), - header, - last_commit_info: tendermint::abci::types::CommitInfo { + let finalize_block = request::FinalizeBlock { + hash: Hash::try_from([0u8; 32].to_vec()).unwrap(), + height: 1u32.into(), + time: Time::now(), + next_validators_hash: Hash::default(), + proposer_address: [0u8; 20].to_vec().try_into().unwrap(), + decided_last_commit: tendermint::abci::types::CommitInfo { round: 0u16.into(), votes: vec![], }, - byzantine_validators: vec![], - }; - consensus_service - .handle_request(ConsensusRequest::BeginBlock(begin_block)) - .await - .unwrap(); - - for tx in block_data { - let deliver_tx = request::DeliverTx { - tx, - }; - consensus_service - .handle_request(ConsensusRequest::DeliverTx(deliver_tx)) - .await - .unwrap(); - } - - let end_block = request::EndBlock { - height: 1u32.into(), + misbehavior: vec![], + txs: block_data, }; consensus_service - .handle_request(ConsensusRequest::EndBlock(end_block)) - .await - .unwrap(); - consensus_service - .handle_request(ConsensusRequest::Commit) + .handle_request(ConsensusRequest::FinalizeBlock(finalize_block)) .await .unwrap(); } diff --git a/crates/astria-sequencer/src/service/info/mod.rs b/crates/astria-sequencer/src/service/info/mod.rs index 779535d85b..6df0a6fd0e 100644 --- a/crates/astria-sequencer/src/service/info/mod.rs +++ b/crates/astria-sequencer/src/service/info/mod.rs @@ -13,8 +13,8 @@ use futures::{ Future, FutureExt, }; -use penumbra_tower_trace::v037::RequestExt as _; -use tendermint::v0_37::abci::{ +use penumbra_tower_trace::v038::RequestExt as _; +use tendermint::v0_38::abci::{ request, response::{ self, @@ -27,7 +27,7 @@ use tower::Service; use tower_abci::BoxError; use tracing::{ instrument, - Instrument, + Instrument as _, }; mod abci_query_router; @@ -153,7 +153,7 @@ mod test { Address, }; use cnidarium::StateDelta; - use tendermint::v0_37::abci::{ + use tendermint::v0_38::abci::{ request, InfoRequest, InfoResponse, diff --git a/crates/astria-sequencer/src/service/mempool.rs b/crates/astria-sequencer/src/service/mempool.rs index 4ab349f32b..fdc664f1f8 100644 --- a/crates/astria-sequencer/src/service/mempool.rs +++ b/crates/astria-sequencer/src/service/mempool.rs @@ -19,7 +19,7 @@ use futures::{ FutureExt, }; use prost::Message as _; -use tendermint::v0_37::abci::{ +use tendermint::v0_38::abci::{ request, response, MempoolRequest, @@ -27,7 +27,7 @@ use tendermint::v0_37::abci::{ }; use tower::Service; use tower_abci::BoxError; -use tracing::Instrument; +use tracing::Instrument as _; use crate::{ accounts::state_ext::StateReadExt, @@ -39,7 +39,7 @@ const MAX_TX_SIZE: usize = 256_000; // 256 KB /// Mempool handles [`request::CheckTx`] abci requests. // /// It performs a stateless check of the given transaction, -/// returning a [`tendermint::v0_37::abci::response::CheckTx`]. +/// returning a [`tendermint::v0_38::abci::response::CheckTx`]. #[derive(Clone)] pub(crate) struct Mempool { storage: Storage, @@ -63,7 +63,7 @@ impl Service for Mempool { } fn call(&mut self, req: MempoolRequest) -> Self::Future { - use penumbra_tower_trace::v037::RequestExt as _; + use penumbra_tower_trace::v038::RequestExt as _; let span = req.create_span(); let storage = self.storage.clone(); async move { diff --git a/crates/astria-sequencer/src/service/snapshot.rs b/crates/astria-sequencer/src/service/snapshot.rs index f7ac592fa1..df6aae7961 100644 --- a/crates/astria-sequencer/src/service/snapshot.rs +++ b/crates/astria-sequencer/src/service/snapshot.rs @@ -10,8 +10,8 @@ use futures::{ Future, FutureExt, }; -use penumbra_tower_trace::v037::RequestExt as _; -use tendermint::v0_37::abci::{ +use penumbra_tower_trace::v038::RequestExt as _; +use tendermint::v0_38::abci::{ response::{ ApplySnapshotChunk, ListSnapshots, @@ -40,6 +40,7 @@ impl Service for Snapshot { fn call(&mut self, req: SnapshotRequest) -> Self::Future { let span = req.create_span(); + async move { Ok(match req { SnapshotRequest::ListSnapshots => {