diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 14c97ee..0cbc794 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ on: env: JS_PACKAGES: "['clients-js']" - RUST_PACKAGES: "['clients-rust', 'interface', 'program']" + RUST_PACKAGES: "['clients-rust', 'interface', 'program', 'pinocchio-interface']" SBPF_PROGRAM_PACKAGES: "['program']" WASM_PACKAGES: "['interface', 'program']" IDL_PACKAGES: "['interface']" diff --git a/Cargo.lock b/Cargo.lock index d3ec163..d244caa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -302,7 +302,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -544,7 +544,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -692,7 +692,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -764,7 +764,7 @@ checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -860,7 +860,7 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -923,7 +923,7 @@ dependencies = [ "derive_more", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -935,7 +935,7 @@ dependencies = [ "cargo_toml", "proc-macro2", "serde_json", - "syn 2.0.98", + "syn 2.0.111", "thiserror 2.0.17", ] @@ -963,7 +963,7 @@ dependencies = [ "codama-nodes", "codama-syn-helpers", "serde_json", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -979,7 +979,7 @@ dependencies = [ "codama-syn-helpers", "derive_more", "proc-macro2", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -994,7 +994,7 @@ dependencies = [ "codama-stores", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1021,7 +1021,7 @@ dependencies = [ "derive_more", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1033,7 +1033,7 @@ dependencies = [ "cargo_toml", "codama-errors", "proc-macro2", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1046,7 +1046,7 @@ dependencies = [ "derive_more", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1267,7 +1267,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1291,7 +1291,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1302,7 +1302,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1385,7 +1385,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1405,7 +1405,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1452,7 +1452,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1475,7 +1475,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1630,7 +1630,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1643,7 +1643,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -1908,7 +1908,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -2397,7 +2397,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -2584,7 +2584,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -3115,7 +3115,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -3188,7 +3188,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -3250,7 +3250,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -3300,6 +3300,18 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "p-stake-interface" +version = "0.1.0" +dependencies = [ + "bincode", + "proptest", + "solana-clock", + "solana-pubkey", + "solana-stake-interface 2.0.2", + "wincode", +] + [[package]] name = "parking" version = "2.2.1" @@ -3385,7 +3397,7 @@ checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -3520,9 +3532,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -3563,7 +3575,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -3646,9 +3658,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.38" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -3826,7 +3838,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -4294,7 +4306,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -4359,7 +4371,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -4384,7 +4396,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -5351,7 +5363,7 @@ checksum = "38e4bb0f5232668866a7f6f5cbc3222bbd9eebbff6afe392e3394498e8c9b1fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -6340,7 +6352,7 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -7477,7 +7489,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -7505,9 +7517,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -7543,7 +7555,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -7629,7 +7641,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -7640,7 +7652,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", "test-case-core", ] @@ -7670,7 +7682,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -7681,7 +7693,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -7778,7 +7790,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -7970,7 +7982,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -8241,7 +8253,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", "wasm-bindgen-shared", ] @@ -8276,7 +8288,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8384,6 +8396,28 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wincode" +version = "0.2.3" +source = "git+https://github.com/anza-xyz/wincode?rev=19a7dc6f56e20ff7978cd4f4b4ae7e0ae74f2457#19a7dc6f56e20ff7978cd4f4b4ae7e0ae74f2457" +dependencies = [ + "proc-macro2", + "quote", + "thiserror 2.0.17", + "wincode-derive", +] + +[[package]] +name = "wincode-derive" +version = "0.2.2" +source = "git+https://github.com/anza-xyz/wincode?rev=19a7dc6f56e20ff7978cd4f4b4ae7e0ae74f2457#19a7dc6f56e20ff7978cd4f4b4ae7e0ae74f2457" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -8709,7 +8743,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", "synstructure 0.13.1", ] @@ -8731,7 +8765,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -8751,7 +8785,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", "synstructure 0.13.1", ] @@ -8772,7 +8806,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] @@ -8794,7 +8828,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.111", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ac4fc77..a62d54a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "clients/rust", "interface", "program", + "pinocchio/interface", ] [workspace.package] diff --git a/pinocchio/interface/Cargo.lock b/pinocchio/interface/Cargo.lock new file mode 100644 index 0000000..a14e0be --- /dev/null +++ b/pinocchio/interface/Cargo.lock @@ -0,0 +1,866 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "five8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_const" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "solana-account-info" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" +dependencies = [ + "solana-address 2.0.0", + "solana-program-error", + "solana-program-memory", +] + +[[package]] +name = "solana-address" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" +dependencies = [ + "solana-address 2.0.0", +] + +[[package]] +name = "solana-address" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37320fd2945c5d654b2c6210624a52d66c3f1f73b653ed211ab91a703b35bdd" +dependencies = [ + "borsh", + "five8", + "five8_const", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-sanitize", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-atomic-u64" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a933ff1e50aff72d02173cfcd7511bd8540b027ee720b75f353f594f834216d0" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-clock" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-cpi" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.0.0", + "solana-stable-layout", +] + +[[package]] +name = "solana-define-syscall" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" + +[[package]] +name = "solana-define-syscall" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" + +[[package]] +name = "solana-epoch-rewards" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-schedule" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5481e72cc4d52c169db73e4c0cd16de8bc943078aac587ec4817a75cc6388f" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a73cc03ca4bed871ca174558108835f8323e85917bb38b9c81c7af2ab853efe" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" +dependencies = [ + "solana-hash 4.0.1", +] + +[[package]] +name = "solana-hash" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5d48a6ee7b91fc7b998944ab026ed7b3e2fc8ee3bc58452644a86c2648152f" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "five8", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", +] + +[[package]] +name = "solana-instruction" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1b699a2c1518028a9982e255e0eca10c44d90006542d9d7f9f40dbce3f7c78" +dependencies = [ + "bincode", + "borsh", + "serde", + "serde_derive", + "solana-define-syscall 4.0.1", + "solana-instruction-error", + "solana-pubkey 4.0.0", +] + +[[package]] +name = "solana-instruction-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04259e03c05faf38a8c24217b5cfe4c90572ae6184ab49cddb1584fdd756d3f" +dependencies = [ + "num-traits", + "solana-program-error", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-msg" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "264275c556ea7e22b9d3f87d56305546a38d4eee8ec884f3b126236cb7dcbbb4" +dependencies = [ + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-program-entrypoint" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-pubkey 4.0.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" +dependencies = [ + "borsh", +] + +[[package]] +name = "solana-program-memory" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4068648649653c2c50546e9a7fb761791b5ab0cda054c771bb5808d3a4b9eb52" +dependencies = [ + "solana-define-syscall 4.0.1", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "solana-address 1.1.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f7104d456b58e1418c21a8581e89810278d1190f70f27ece7fc0b2c9282a57" +dependencies = [ + "solana-address 2.0.0", +] + +[[package]] +name = "solana-rent" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b702d8c43711e3c8a9284a4f1bbc6a3de2553deb25b0c8142f9a44ef0ce5ddc1" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sdk-ids" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" +dependencies = [ + "solana-address 2.0.0", +] + +[[package]] +name = "solana-sdk-macro" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "solana-sha256-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2", + "solana-define-syscall 4.0.1", + "solana-hash 4.0.1", +] + +[[package]] +name = "solana-slot-hashes" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f914f6b108f5bba14a280b458d023e3621c9973f27f015a4d755b50e88d89e97" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" +dependencies = [ + "solana-instruction", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-stake-interface" +version = "2.0.1" +dependencies = [ + "borsh", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-system-interface", + "solana-sysvar", +] + +[[package]] +name = "solana-stake-interface-pinocchio" +version = "0.1.0" +dependencies = [ + "bincode", + "borsh", + "solana-clock", + "solana-pubkey 3.0.0", + "solana-stake-interface", +] + +[[package]] +name = "solana-system-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-sysvar" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3205cc7db64a0f1a20b7eb2405773fa64e45f7fe0fc7a73e50e90eca6b2b0be7" +dependencies = [ + "base64", + "bincode", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall 4.0.1", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash 4.0.1", + "solana-instruction", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey 4.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" +dependencies = [ + "solana-address 2.0.0", + "solana-sdk-ids", +] + + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] diff --git a/pinocchio/interface/Cargo.toml b/pinocchio/interface/Cargo.toml new file mode 100644 index 0000000..fe46116 --- /dev/null +++ b/pinocchio/interface/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "p-stake-interface" +version = "0.1.0" +edition = "2021" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } + +[dependencies] +solana-pubkey = "3.0.0" +wincode = { git = "https://github.com/anza-xyz/wincode", rev = "19a7dc6f56e20ff7978cd4f4b4ae7e0ae74f2457", default-features = false, features = ["alloc", "derive"] } +solana-clock = "3" + +[dev-dependencies] +bincode = "1.3.3" +proptest = "1.6.0" +solana-stake-interface = { path = "../../interface", features = ["bincode"] } diff --git a/pinocchio/interface/src/error.rs b/pinocchio/interface/src/error.rs new file mode 100644 index 0000000..b89eb37 --- /dev/null +++ b/pinocchio/interface/src/error.rs @@ -0,0 +1,39 @@ +// TODO: These may not be backward compatible with StakeStakeV2 serialization errs in interface/src/state.rs +// Need to think about this. +#[derive(Debug)] +pub enum StakeStateError { + WrongLength { expected: usize, actual: usize }, + Read(wincode::ReadError), +} + +impl From for StakeStateError { + #[inline(always)] + fn from(e: wincode::ReadError) -> Self { + Self::Read(e) + } +} + +#[inline(always)] +pub(crate) fn invalid_tag(tag: u32) -> StakeStateError { + StakeStateError::Read(wincode::error::invalid_tag_encoding(tag as usize)) +} + +#[inline(always)] +pub(crate) fn slice_as_array(s: &[u8]) -> Result<&[u8; N], StakeStateError> { + s.try_into().map_err(|_| { + StakeStateError::Read(wincode::ReadError::Custom( + "slice length mismatch for array", + )) + }) +} + +#[inline(always)] +pub(crate) fn slice_as_array_mut( + s: &mut [u8], +) -> Result<&mut [u8; N], StakeStateError> { + s.try_into().map_err(|_| { + StakeStateError::Read(wincode::ReadError::Custom( + "slice length mismatch for array", + )) + }) +} diff --git a/pinocchio/interface/src/lib.rs b/pinocchio/interface/src/lib.rs new file mode 100644 index 0000000..5d43226 --- /dev/null +++ b/pinocchio/interface/src/lib.rs @@ -0,0 +1,3 @@ +pub mod error; +pub mod pod; +pub mod state; diff --git a/pinocchio/interface/src/pod.rs b/pinocchio/interface/src/pod.rs new file mode 100644 index 0000000..9680de8 --- /dev/null +++ b/pinocchio/interface/src/pod.rs @@ -0,0 +1,70 @@ +//! Alignment-1 primitives for zero-copy deserialization + +// TODO: Document why this is necessary + +use solana_pubkey::Pubkey; +use wincode::{SchemaRead, SchemaWrite}; + +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct PodU32(pub [u8; 4]); + +impl PodU32 { + #[inline(always)] + pub fn get(self) -> u32 { + u32::from_le_bytes(self.0) + } + #[inline(always)] + pub fn set(&mut self, v: u32) { + self.0 = v.to_le_bytes(); + } +} + +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct PodU64(pub [u8; 8]); + +impl PodU64 { + #[inline(always)] + pub fn get(self) -> u64 { + u64::from_le_bytes(self.0) + } + #[inline(always)] + pub fn set(&mut self, v: u64) { + self.0 = v.to_le_bytes(); + } +} + +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct PodI64(pub [u8; 8]); + +impl PodI64 { + #[inline(always)] + pub fn get(self) -> i64 { + i64::from_le_bytes(self.0) + } + #[inline(always)] + pub fn set(&mut self, v: i64) { + self.0 = v.to_le_bytes(); + } +} + +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct PodPubkey(pub [u8; 32]); + +impl PodPubkey { + #[inline(always)] + pub fn to_pubkey(self) -> Pubkey { + Pubkey::new_from_array(self.0) + } + #[inline(always)] + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + #[inline(always)] + pub fn from_pubkey(pk: Pubkey) -> Self { + Self(pk.to_bytes()) + } +} diff --git a/pinocchio/interface/src/state.rs b/pinocchio/interface/src/state.rs new file mode 100644 index 0000000..aea4636 --- /dev/null +++ b/pinocchio/interface/src/state.rs @@ -0,0 +1,236 @@ +use crate::error::{invalid_tag, slice_as_array, slice_as_array_mut, StakeStateError}; +use crate::pod::{PodI64, PodPubkey, PodU32, PodU64}; +use core::mem::size_of; +use wincode::{SchemaRead, SchemaWrite}; + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct AuthorizedBytes { + pub staker: PodPubkey, + pub withdrawer: PodPubkey, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct LockupBytes { + pub unix_timestamp: PodI64, + pub epoch: PodU64, + pub custodian: PodPubkey, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct MetaBytes { + pub rent_exempt_reserve: PodU64, + pub authorized: AuthorizedBytes, + pub lockup: LockupBytes, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct DelegationBytes { + pub voter_pubkey: PodPubkey, + pub stake: PodU64, + pub activation_epoch: PodU64, + pub deactivation_epoch: PodU64, + pub _reserved: [u8; 8], +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct StakeBytes { + pub delegation: DelegationBytes, + pub credits_observed: PodU64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaWrite, SchemaRead)] +pub struct StakeStateV2Bytes { + pub tag: PodU32, + pub payload: [u8; 196], +} + +impl StakeStateV2Bytes { + pub const SIZE: usize = 200; + + pub const TAG_UNINITIALIZED: u32 = 0; + pub const TAG_INITIALIZED: u32 = 1; + pub const TAG_STAKE: u32 = 2; + pub const TAG_REWARDS_POOL: u32 = 3; + + pub const META_SIZE: usize = size_of::(); + pub const STAKE_SIZE: usize = size_of::(); + + // After meta + stake, payload has: [stake_flags:1][padding:3] = 4 bytes + pub const FLAGS_OFFSET_IN_PAYLOAD: usize = Self::META_SIZE + Self::STAKE_SIZE; + pub const TAIL_SIZE: usize = 4; + + #[inline(always)] + pub fn tag_u32(&self) -> u32 { + self.tag.get() + } +} + +// Compile-time layout guard +const _: [(); StakeStateV2Bytes::SIZE] = [(); core::mem::size_of::()]; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum StakeStateV2View<'a> { + Uninitialized, + Initialized(&'a MetaBytes), + Stake { + meta: &'a MetaBytes, + stake: &'a StakeBytes, + stake_flags: u8, + padding: &'a [u8; 3], + }, + RewardsPool, +} + +impl<'a> StakeStateV2View<'a> { + #[inline] + pub fn from_account_data(data: &'a [u8]) -> Result { + if data.len() != StakeStateV2Bytes::SIZE { + return Err(StakeStateError::WrongLength { + expected: StakeStateV2Bytes::SIZE, + actual: data.len(), + }); + } + + let raw: &'a StakeStateV2Bytes = wincode::deserialize_ref(data)?; + let tag = raw.tag_u32(); + + match tag { + StakeStateV2Bytes::TAG_UNINITIALIZED => Ok(Self::Uninitialized), + StakeStateV2Bytes::TAG_REWARDS_POOL => Ok(Self::RewardsPool), + StakeStateV2Bytes::TAG_INITIALIZED => { + let meta_bytes = &raw.payload[..StakeStateV2Bytes::META_SIZE]; + let meta: &'a MetaBytes = wincode::deserialize_ref(meta_bytes)?; + Ok(Self::Initialized(meta)) + } + + StakeStateV2Bytes::TAG_STAKE => { + // meta + let meta_bytes = &raw.payload[..StakeStateV2Bytes::META_SIZE]; + let meta: &'a MetaBytes = wincode::deserialize_ref(meta_bytes)?; + + // stake + let stake_start = StakeStateV2Bytes::META_SIZE; + let stake_end = stake_start + StakeStateV2Bytes::STAKE_SIZE; + let stake_bytes = &raw.payload[stake_start..stake_end]; + let stake: &'a StakeBytes = wincode::deserialize_ref(stake_bytes)?; + + // flags + 3-byte padding tail + let tail_start = StakeStateV2Bytes::FLAGS_OFFSET_IN_PAYLOAD; + let tail = &raw.payload[tail_start..]; + if tail.len() != StakeStateV2Bytes::TAIL_SIZE { + return Err(StakeStateError::Read(wincode::ReadError::Custom( + "stake tail length mismatch", + ))); + } + let stake_flags = tail[0]; + let padding: &'a [u8; 3] = slice_as_array(&tail[1..4])?; + + Ok(Self::Stake { + meta, + stake, + stake_flags, + padding, + }) + } + + other => Err(invalid_tag(other)), + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub enum StakeStateV2ViewMut<'a> { + Uninitialized { + tag: &'a mut PodU32, + payload: &'a mut [u8; 196], + }, + Initialized { + tag: &'a mut PodU32, + meta: &'a mut MetaBytes, + }, + Stake { + tag: &'a mut PodU32, + meta: &'a mut MetaBytes, + stake: &'a mut StakeBytes, + stake_flags: &'a mut u8, + padding: &'a mut [u8; 3], + }, + RewardsPool { + tag: &'a mut PodU32, + payload: &'a mut [u8; 196], + }, +} + +impl<'a> StakeStateV2ViewMut<'a> { + #[inline(always)] + fn split_account( + data: &'a mut [u8], + ) -> Result<(&'a mut PodU32, &'a mut [u8; 196]), StakeStateError> { + if data.len() != StakeStateV2Bytes::SIZE { + return Err(StakeStateError::WrongLength { + expected: StakeStateV2Bytes::SIZE, + actual: data.len(), + }); + } + + let (tag_region, payload_region) = data.split_at_mut(4); + + let tag: &'a mut PodU32 = wincode::deserialize_mut(tag_region)?; + let payload: &'a mut [u8; 196] = slice_as_array_mut(payload_region)?; + + Ok((tag, payload)) + } + + #[inline] + pub fn from_account_data(data: &'a mut [u8]) -> Result { + let (tag, payload) = Self::split_account(data)?; + let tag_u32 = (*tag).get(); + + match tag_u32 { + StakeStateV2Bytes::TAG_UNINITIALIZED => Ok(Self::Uninitialized { tag, payload }), + StakeStateV2Bytes::TAG_REWARDS_POOL => Ok(Self::RewardsPool { tag, payload }), + + StakeStateV2Bytes::TAG_INITIALIZED => { + let meta_region = &mut payload[..StakeStateV2Bytes::META_SIZE]; + let meta: &'a mut MetaBytes = wincode::deserialize_mut(meta_region)?; + Ok(Self::Initialized { tag, meta }) + } + + StakeStateV2Bytes::TAG_STAKE => { + // Split payload into meta | stake | tail(4) + let (meta_region, rest) = payload.split_at_mut(StakeStateV2Bytes::META_SIZE); + let (stake_region, tail) = rest.split_at_mut(StakeStateV2Bytes::STAKE_SIZE); + + if tail.len() != StakeStateV2Bytes::TAIL_SIZE { + return Err(StakeStateError::Read(wincode::ReadError::Custom( + "stake tail length mismatch", + ))); + } + + let meta: &'a mut MetaBytes = wincode::deserialize_mut(meta_region)?; + let stake: &'a mut StakeBytes = wincode::deserialize_mut(stake_region)?; + + // tail = [flags(1)][padding(3)] + let (flags_region, pad_region) = tail.split_at_mut(1); + let stake_flags: &'a mut u8 = &mut flags_region[0]; + let padding: &'a mut [u8; 3] = slice_as_array_mut(pad_region)?; + + Ok(Self::Stake { + tag, + meta, + stake, + stake_flags, + padding, + }) + } + + other => Err(invalid_tag(other)), + } + } +} diff --git a/pinocchio/interface/tests/state.rs b/pinocchio/interface/tests/state.rs new file mode 100644 index 0000000..7a7ceb5 --- /dev/null +++ b/pinocchio/interface/tests/state.rs @@ -0,0 +1,613 @@ +#![allow(deprecated)] +#![allow(clippy::arithmetic_side_effects)] + +use { + bincode::Options, + core::mem::size_of, + p_stake_interface::{ + error::StakeStateError, + pod::{PodI64, PodPubkey, PodU32, PodU64}, + state::{MetaBytes, StakeBytes, StakeStateV2Bytes, StakeStateV2View, StakeStateV2ViewMut}, + }, + proptest::prelude::*, + solana_pubkey::Pubkey, + solana_stake_interface::{ + stake_flags::StakeFlags as OldStakeFlags, + state::{ + Authorized as OldAuthorized, Delegation as OldDelegation, Lockup as OldLockup, + Meta as OldMeta, Stake as OldStake, StakeStateV2 as OldStakeStateV2, + }, + }, + wincode::ReadError, +}; + +fn serialize_old(state: &OldStakeStateV2) -> Vec { + let mut data = bincode::DefaultOptions::new() + .with_fixint_encoding() + .serialize(state) + .unwrap(); + data.resize(StakeStateV2Bytes::SIZE, 0); + data +} + +fn deserialize_old(data: &[u8]) -> OldStakeStateV2 { + bincode::DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize::(data) + .unwrap() +} + +fn pk(bytes: [u8; 32]) -> Pubkey { + Pubkey::new_from_array(bytes) +} + +#[test] +fn layout_sanity() { + assert_eq!(StakeStateV2Bytes::SIZE, 200); + assert_eq!(size_of::(), 200); + + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 8); + assert_eq!(size_of::(), 8); + assert_eq!(size_of::(), 32); + + // Must exactly match on-chain bincode layout pieces. + assert_eq!(size_of::(), 120); + assert_eq!(size_of::(), 72); + + // Tag (4) + Meta (120) + Stake (72) = 196. StakeFlags lives at byte 196. + assert_eq!(StakeStateV2Bytes::FLAGS_OFFSET_IN_PAYLOAD, 192); // within payload +} + +#[test] +fn view_wrong_length_errors() { + let data = vec![0u8; 199]; + let err = StakeStateV2View::from_account_data(&data).unwrap_err(); + assert!(matches!( + err, + StakeStateError::WrongLength { + expected: 200, + actual: 199 + } + )); +} + +#[test] +fn view_mut_wrong_length_errors() { + let mut data = vec![0u8; 201]; + let err = StakeStateV2ViewMut::from_account_data(&mut data).unwrap_err(); + assert!(matches!( + err, + StakeStateError::WrongLength { + expected: 200, + actual: 201 + } + )); +} + +#[test] +fn view_invalid_tag_errors() { + let mut data = [0u8; 200]; + data[0..4].copy_from_slice(&999u32.to_le_bytes()); + + let err = StakeStateV2View::from_account_data(&data).unwrap_err(); + assert!(matches!( + err, + StakeStateError::Read(ReadError::InvalidTagEncoding(_)) + )); +} + +#[test] +fn view_mut_invalid_tag_errors() { + let mut data = [0u8; 200]; + data[0..4].copy_from_slice(&999u32.to_le_bytes()); + + let err = StakeStateV2ViewMut::from_account_data(&mut data).unwrap_err(); + assert!(matches!( + err, + StakeStateError::Read(ReadError::InvalidTagEncoding(_)) + )); +} + +#[test] +fn view_borrows_expected_offsets_initialized() { + let old_meta = OldMeta { + rent_exempt_reserve: 0x1122334455667788, + authorized: OldAuthorized { + staker: pk([1u8; 32]), + withdrawer: pk([2u8; 32]), + }, + lockup: OldLockup { + unix_timestamp: -123, + epoch: 456, + custodian: pk([3u8; 32]), + }, + }; + let old_state = OldStakeStateV2::Initialized(old_meta); + let data = serialize_old(&old_state); + + let view = StakeStateV2View::from_account_data(&data).unwrap(); + let StakeStateV2View::Initialized(meta) = view else { + panic!("expected Initialized"); + }; + + // Prove it's borrowing into the original buffer (no memcpy of MetaBytes). + let meta_ptr = meta as *const MetaBytes as *const u8; + let expected_ptr = unsafe { data.as_ptr().add(4) }; + assert_eq!(meta_ptr, expected_ptr); + + assert_eq!(meta.rent_exempt_reserve.get(), old_meta.rent_exempt_reserve); + assert_eq!( + meta.authorized.staker.to_pubkey(), + old_meta.authorized.staker + ); + assert_eq!( + meta.authorized.withdrawer.to_pubkey(), + old_meta.authorized.withdrawer + ); + assert_eq!( + meta.lockup.unix_timestamp.get(), + old_meta.lockup.unix_timestamp + ); + assert_eq!(meta.lockup.epoch.get(), old_meta.lockup.epoch); + assert_eq!(meta.lockup.custodian.to_pubkey(), old_meta.lockup.custodian); +} + +#[test] +fn view_borrows_expected_offsets_stake() { + let old_meta = OldMeta { + rent_exempt_reserve: 7, + authorized: OldAuthorized { + staker: pk([11u8; 32]), + withdrawer: pk([22u8; 32]), + }, + lockup: OldLockup { + unix_timestamp: 1, + epoch: 2, + custodian: pk([33u8; 32]), + }, + }; + + let old_delegation = OldDelegation { + voter_pubkey: pk([44u8; 32]), + stake: 123, + activation_epoch: 9, + deactivation_epoch: 10, + #[allow(deprecated)] + warmup_cooldown_rate: f64::from_le_bytes([9u8; 8]), + }; + let old_stake = OldStake { + delegation: old_delegation, + credits_observed: 777, + }; + + let mut old_flags = OldStakeFlags::empty(); + #[allow(deprecated)] + old_flags.set(OldStakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED); + + let old_state = OldStakeStateV2::Stake(old_meta, old_stake, old_flags); + let data = serialize_old(&old_state); + + let view = StakeStateV2View::from_account_data(&data).unwrap(); + let StakeStateV2View::Stake { + meta, + stake, + stake_flags, + .. + } = view + else { + panic!("expected Stake"); + }; + + // Borrowed offsets: + let meta_ptr = meta as *const MetaBytes as *const u8; + let stake_ptr = stake as *const StakeBytes as *const u8; + + let expected_meta_ptr = unsafe { data.as_ptr().add(4) }; + let expected_stake_ptr = unsafe { data.as_ptr().add(4 + size_of::()) }; + + assert_eq!(meta_ptr, expected_meta_ptr); + assert_eq!(stake_ptr, expected_stake_ptr); + + // Fields: + assert_eq!(meta.rent_exempt_reserve.get(), old_meta.rent_exempt_reserve); + assert_eq!( + meta.authorized.staker.to_pubkey(), + old_meta.authorized.staker + ); + assert_eq!( + meta.authorized.withdrawer.to_pubkey(), + old_meta.authorized.withdrawer + ); + assert_eq!( + meta.lockup.unix_timestamp.get(), + old_meta.lockup.unix_timestamp + ); + assert_eq!(meta.lockup.epoch.get(), old_meta.lockup.epoch); + assert_eq!(meta.lockup.custodian.to_pubkey(), old_meta.lockup.custodian); + + assert_eq!( + stake.delegation.voter_pubkey.to_pubkey(), + old_stake.delegation.voter_pubkey + ); + assert_eq!(stake.delegation.stake.get(), old_stake.delegation.stake); + assert_eq!( + stake.delegation.activation_epoch.get(), + old_stake.delegation.activation_epoch + ); + assert_eq!( + stake.delegation.deactivation_epoch.get(), + old_stake.delegation.deactivation_epoch + ); + assert_eq!( + stake.delegation._reserved, + old_stake.delegation.warmup_cooldown_rate.to_le_bytes() + ); + assert_eq!(stake.credits_observed.get(), old_stake.credits_observed); + + // Old stake_flags is a bit-wrapper; bincode layout is a single u8 "bits". + assert_eq!(stake_flags, 0b0000_0001); + + // Also sanity-check the exact byte position in the raw account data. + assert_eq!(data[196], 0b0000_0001); + assert_eq!(&data[197..200], &[0u8; 3]); +} + +#[test] +fn view_uninitialized_and_rewards_pool() { + for (tag, expected) in [ + (StakeStateV2Bytes::TAG_UNINITIALIZED, "Uninitialized"), + (StakeStateV2Bytes::TAG_REWARDS_POOL, "RewardsPool"), + ] { + let mut data = [0u8; 200]; + data[0..4].copy_from_slice(&tag.to_le_bytes()); + + let view = StakeStateV2View::from_account_data(&data).unwrap(); + match (view, expected) { + (StakeStateV2View::Uninitialized, "Uninitialized") => {} + (StakeStateV2View::RewardsPool, "RewardsPool") => {} + _ => panic!("unexpected variant for tag {tag}"), + } + } +} + +#[test] +fn view_mut_initialized_updates_in_place() { + let old_meta = OldMeta { + rent_exempt_reserve: 1, + authorized: OldAuthorized { + staker: pk([1u8; 32]), + withdrawer: pk([2u8; 32]), + }, + lockup: OldLockup { + unix_timestamp: 3, + epoch: 4, + custodian: pk([5u8; 32]), + }, + }; + let old_state = OldStakeStateV2::Initialized(old_meta); + let mut data = serialize_old(&old_state); + + let new_rent: u64 = 0xAABBCCDDEEFF0011; + let mut new_cust = [9u8; 32]; + new_cust[0] = 0x42; + + // Capture pointer before mutable borrow + let expected_ptr = unsafe { data.as_mut_ptr().add(4) }; + + { + let view = StakeStateV2ViewMut::from_account_data(&mut data).unwrap(); + let StakeStateV2ViewMut::Initialized { meta, .. } = view else { + panic!("expected Initialized"); + }; + + // Prove borrow is into the original buffer. + let meta_ptr = meta as *mut MetaBytes as *mut u8; + assert_eq!(meta_ptr, expected_ptr); + + meta.rent_exempt_reserve.set(new_rent); + meta.lockup.custodian.0 = new_cust; + } + + // Exact bytes for rent_exempt_reserve live at offset 4..12. + assert_eq!(&data[4..12], &new_rent.to_le_bytes()); + + // Check with zero-copy ref: + let view = StakeStateV2View::from_account_data(&data).unwrap(); + let StakeStateV2View::Initialized(meta) = view else { + panic!("expected Initialized"); + }; + assert_eq!(meta.rent_exempt_reserve.get(), new_rent); + assert_eq!(meta.lockup.custodian.to_pubkey(), pk(new_cust)); + + // Check bincode compatibility: + let decoded = deserialize_old(&data); + let OldStakeStateV2::Initialized(decoded_meta) = decoded else { + panic!("expected Initialized"); + }; + assert_eq!(decoded_meta.rent_exempt_reserve, new_rent); + assert_eq!(decoded_meta.lockup.custodian, pk(new_cust)); +} + +#[test] +fn view_mut_stake_updates_in_place() { + let old_meta = OldMeta { + rent_exempt_reserve: 10, + authorized: OldAuthorized { + staker: pk([10u8; 32]), + withdrawer: pk([20u8; 32]), + }, + lockup: OldLockup { + unix_timestamp: -10, + epoch: 999, + custodian: pk([30u8; 32]), + }, + }; + + let old_delegation = OldDelegation { + voter_pubkey: pk([40u8; 32]), + stake: 1234, + activation_epoch: 5, + deactivation_epoch: 6, + #[allow(deprecated)] + warmup_cooldown_rate: f64::from_le_bytes([7u8; 8]), + }; + let old_stake = OldStake { + delegation: old_delegation, + credits_observed: 111, + }; + + let mut old_flags = OldStakeFlags::empty(); + #[allow(deprecated)] + old_flags.set(OldStakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED); + + let old_state = OldStakeStateV2::Stake(old_meta, old_stake, old_flags); + let mut data = serialize_old(&old_state); + + let new_credits: u64 = 9_999_999; + let new_stake_amt: u64 = 8_888_888; + let new_flags: u8 = 0; + + // Capture pointers before mutable borrow + let expected_meta_ptr = unsafe { data.as_mut_ptr().add(4) }; + let expected_stake_ptr = unsafe { data.as_mut_ptr().add(4 + size_of::()) }; + + { + let view = StakeStateV2ViewMut::from_account_data(&mut data).unwrap(); + let StakeStateV2ViewMut::Stake { + meta, + stake, + stake_flags, + .. + } = view + else { + panic!("expected Stake"); + }; + + // Borrowed offsets (no memcpy): + let meta_ptr = meta as *mut MetaBytes as *mut u8; + let stake_ptr = stake as *mut StakeBytes as *mut u8; + assert_eq!(meta_ptr, expected_meta_ptr); + assert_eq!(stake_ptr, expected_stake_ptr); + + // Mutate fields in place: + stake.credits_observed.set(new_credits); + stake.delegation.stake.set(new_stake_amt); + *stake_flags = new_flags; + } + + // flags byte is exactly at index 196 + assert_eq!(data[196], new_flags); + assert_eq!(&data[197..200], &[0u8; 3]); + + // Check via zero-copy ref: + let view = StakeStateV2View::from_account_data(&data).unwrap(); + let StakeStateV2View::Stake { + stake, stake_flags, .. + } = view + else { + panic!("expected Stake"); + }; + assert_eq!(stake.credits_observed.get(), new_credits); + assert_eq!(stake.delegation.stake.get(), new_stake_amt); + assert_eq!(stake_flags, new_flags); + + // Check bincode compatibility: + let decoded = deserialize_old(&data); + let OldStakeStateV2::Stake(_m, decoded_stake, decoded_flags) = decoded else { + panic!("expected Stake"); + }; + assert_eq!(decoded_stake.credits_observed, new_credits); + assert_eq!(decoded_stake.delegation.stake, new_stake_amt); + assert_eq!(decoded_flags, OldStakeFlags::empty()); +} + +proptest! { + #[test] + fn prop_view_matches_bincode_for_all_variants( + variant in 0u8..=3u8, + + rent_exempt_reserve in any::(), + staker_bytes in any::<[u8; 32]>(), + withdrawer_bytes in any::<[u8; 32]>(), + lockup_timestamp in any::(), + lockup_epoch in any::(), + custodian_bytes in any::<[u8; 32]>(), + + voter_bytes in any::<[u8; 32]>(), + stake_amount in any::(), + activation_epoch in any::(), + deactivation_epoch in any::(), + reserved in any::<[u8; 8]>(), + credits_observed in any::(), + + stake_flags_bits in any::(), + ) { + let old_meta = OldMeta { + rent_exempt_reserve, + authorized: OldAuthorized { + staker: pk(staker_bytes), + withdrawer: pk(withdrawer_bytes), + }, + lockup: OldLockup { + unix_timestamp: lockup_timestamp, + epoch: lockup_epoch, + custodian: pk(custodian_bytes), + }, + }; + + let old_delegation = OldDelegation { + voter_pubkey: pk(voter_bytes), + stake: stake_amount, + activation_epoch, + deactivation_epoch, + #[allow(deprecated)] + warmup_cooldown_rate: f64::from_le_bytes(reserved), + }; + + let old_stake = OldStake { + delegation: old_delegation, + credits_observed, + }; + + let mut old_flags = OldStakeFlags::empty(); + #[allow(deprecated)] + if stake_flags_bits != 0 { + old_flags.set(OldStakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED); + } + let expected_flags_byte: u8 = if stake_flags_bits != 0 { 1 } else { 0 }; + + let old_state = match variant { + 0 => OldStakeStateV2::Uninitialized, + 1 => OldStakeStateV2::Initialized(old_meta), + 2 => OldStakeStateV2::Stake(old_meta, old_stake, old_flags), + 3 => OldStakeStateV2::RewardsPool, + _ => unreachable!(), + }; + + let data = serialize_old(&old_state); + let view = StakeStateV2View::from_account_data(&data).unwrap(); + + match (variant, view) { + (0, StakeStateV2View::Uninitialized) => {} + (3, StakeStateV2View::RewardsPool) => {} + (1, StakeStateV2View::Initialized(meta)) => { + prop_assert_eq!(meta.rent_exempt_reserve.get(), rent_exempt_reserve); + prop_assert_eq!(meta.authorized.staker.to_pubkey(), pk(staker_bytes)); + prop_assert_eq!(meta.authorized.withdrawer.to_pubkey(), pk(withdrawer_bytes)); + prop_assert_eq!(meta.lockup.unix_timestamp.get(), lockup_timestamp); + prop_assert_eq!(meta.lockup.epoch.get(), lockup_epoch); + prop_assert_eq!(meta.lockup.custodian.to_pubkey(), pk(custodian_bytes)); + } + (2, StakeStateV2View::Stake { meta, stake, stake_flags, .. }) => { + prop_assert_eq!(meta.rent_exempt_reserve.get(), rent_exempt_reserve); + prop_assert_eq!(meta.authorized.staker.to_pubkey(), pk(staker_bytes)); + prop_assert_eq!(meta.authorized.withdrawer.to_pubkey(), pk(withdrawer_bytes)); + prop_assert_eq!(meta.lockup.unix_timestamp.get(), lockup_timestamp); + prop_assert_eq!(meta.lockup.epoch.get(), lockup_epoch); + prop_assert_eq!(meta.lockup.custodian.to_pubkey(), pk(custodian_bytes)); + + prop_assert_eq!(stake.delegation.voter_pubkey.to_pubkey(), pk(voter_bytes)); + prop_assert_eq!(stake.delegation.stake.get(), stake_amount); + prop_assert_eq!(stake.delegation.activation_epoch.get(), activation_epoch); + prop_assert_eq!(stake.delegation.deactivation_epoch.get(), deactivation_epoch); + prop_assert_eq!(stake.delegation._reserved, reserved); + prop_assert_eq!(stake.credits_observed.get(), credits_observed); + + prop_assert_eq!(stake_flags, expected_flags_byte); + prop_assert_eq!(data[196], expected_flags_byte); + } + _ => prop_assert!(false, "unexpected (variant, view) pairing"), + } + } + + #[test] + fn prop_view_mut_stake_persists_updates( + rent_exempt_reserve in any::(), + staker_bytes in any::<[u8; 32]>(), + withdrawer_bytes in any::<[u8; 32]>(), + lockup_timestamp in any::(), + lockup_epoch in any::(), + custodian_bytes in any::<[u8; 32]>(), + + voter_bytes in any::<[u8; 32]>(), + stake_amount in any::(), + activation_epoch in any::(), + deactivation_epoch in any::(), + reserved in any::<[u8; 8]>(), + credits_observed in any::(), + + // new values + new_rent_exempt_reserve in any::(), + new_credits_observed in any::(), + new_stake_amount in any::(), + new_flags in any::(), + ) { + let old_meta = OldMeta { + rent_exempt_reserve, + authorized: OldAuthorized { + staker: pk(staker_bytes), + withdrawer: pk(withdrawer_bytes), + }, + lockup: OldLockup { + unix_timestamp: lockup_timestamp, + epoch: lockup_epoch, + custodian: pk(custodian_bytes), + }, + }; + + let old_delegation = OldDelegation { + voter_pubkey: pk(voter_bytes), + stake: stake_amount, + activation_epoch, + deactivation_epoch, + #[allow(deprecated)] + warmup_cooldown_rate: f64::from_le_bytes(reserved), + }; + + let old_stake = OldStake { + delegation: old_delegation, + credits_observed, + }; + + let old_state = OldStakeStateV2::Stake(old_meta, old_stake, OldStakeFlags::empty()); + let mut data = serialize_old(&old_state); + + let view = StakeStateV2ViewMut::from_account_data(&mut data).unwrap(); + let StakeStateV2ViewMut::Stake { meta, stake, stake_flags, .. } = view else { + prop_assert!(false, "expected Stake"); + return Ok(()); + }; + + meta.rent_exempt_reserve.set(new_rent_exempt_reserve); + stake.credits_observed.set(new_credits_observed); + stake.delegation.stake.set(new_stake_amount); + *stake_flags = new_flags; + + let view = StakeStateV2View::from_account_data(&data).unwrap(); + let StakeStateV2View::Stake { meta, stake, stake_flags, .. } = view else { + prop_assert!(false, "expected Stake"); + return Ok(()); + }; + + prop_assert_eq!(meta.rent_exempt_reserve.get(), new_rent_exempt_reserve); + prop_assert_eq!(stake.credits_observed.get(), new_credits_observed); + prop_assert_eq!(stake.delegation.stake.get(), new_stake_amount); + prop_assert_eq!(stake_flags, new_flags); + + // bincode compatibility check + let decoded = deserialize_old(&data); + let OldStakeStateV2::Stake(decoded_meta, decoded_stake, _) = decoded else { + prop_assert!(false, "expected Stake (bincode)"); + return Ok(()); + }; + prop_assert_eq!(decoded_meta.rent_exempt_reserve, new_rent_exempt_reserve); + prop_assert_eq!(decoded_stake.credits_observed, new_credits_observed); + prop_assert_eq!(decoded_stake.delegation.stake, new_stake_amount); + + // We only assert that the byte in account data + // is the one we set (index 196) and that bincode successfully parsed. + prop_assert_eq!(data[196], new_flags); + } +}