diff --git a/Cargo.lock b/Cargo.lock index 223c8d0f..7e8ee613 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,7 +41,7 @@ dependencies = [ [[package]] name = "agave-bls12-381" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "blst", "blstrs", @@ -54,13 +54,13 @@ dependencies = [ [[package]] name = "agave-feature-set" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "ahash", "solana-epoch-schedule", - "solana-hash 3.1.0", + "solana-hash 4.2.0", "solana-keypair", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sha256-hasher", "solana-svm-feature-set", ] @@ -68,7 +68,7 @@ dependencies = [ [[package]] name = "agave-logger" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "env_logger", "libc", @@ -79,7 +79,7 @@ dependencies = [ [[package]] name = "agave-precompiles" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "agave-feature-set", "bincode", @@ -91,7 +91,7 @@ dependencies = [ "solana-ed25519-program", "solana-message", "solana-precompile-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids", "solana-secp256k1-program", "solana-secp256r1-program", @@ -100,7 +100,7 @@ dependencies = [ [[package]] name = "agave-syscalls" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "agave-bls12-381", "bincode", @@ -114,25 +114,25 @@ dependencies = [ "solana-clock", "solana-cpi", "solana-curve25519", - "solana-hash 3.1.0", + "solana-hash 4.2.0", "solana-instruction", "solana-keccak-hasher", "solana-loader-v3-interface", "solana-poseidon", "solana-program-entrypoint", "solana-program-runtime", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sbpf", "solana-sdk-ids", "solana-secp256k1-recover", "solana-sha256-hasher", "solana-stable-layout", "solana-stake-interface", - "solana-svm-callback 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=a48940a24d)", + "solana-svm-callback 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=cc74332e59)", "solana-svm-feature-set", "solana-svm-log-collector", "solana-svm-measure", - "solana-svm-timings 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=a48940a24d)", + "solana-svm-timings 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=cc74332e59)", "solana-svm-type-overrides", "solana-sysvar", "solana-sysvar-id", @@ -235,9 +235,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "ark-bn254" @@ -356,7 +356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -382,7 +382,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -457,7 +457,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -557,9 +557,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitmaps" @@ -663,7 +663,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -683,9 +683,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bv" @@ -720,7 +720,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -731,9 +731,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cast" @@ -743,9 +743,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.54" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "shlex", @@ -771,7 +771,7 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -813,9 +813,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -823,9 +823,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -835,21 +835,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "colorchoice" @@ -893,9 +893,9 @@ dependencies = [ [[package]] name = "criterion" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" dependencies = [ "alloca", "anes", @@ -918,9 +918,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" dependencies = [ "cast", "itertools 0.13.0", @@ -971,9 +971,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1038,7 +1038,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1062,7 +1062,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1073,7 +1073,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1215,7 +1215,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1260,7 +1260,7 @@ checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1280,14 +1280,14 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", "regex", @@ -1295,9 +1295,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", @@ -1353,18 +1353,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" - -[[package]] -name = "five8" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" -dependencies = [ - "five8_core", -] +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "five8" @@ -1386,9 +1377,9 @@ dependencies = [ [[package]] name = "five8_core" -version = "0.1.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" [[package]] name = "fixedbitset" @@ -1402,6 +1393,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1425,9 +1422,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1440,9 +1437,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1450,15 +1447,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1467,38 +1464,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1508,7 +1505,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1543,9 +1539,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1586,6 +1582,19 @@ dependencies = [ "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "glob" version = "0.3.3" @@ -1647,6 +1656,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", + "foldhash", ] [[package]] @@ -1718,6 +1728,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -1748,6 +1764,8 @@ checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -1800,9 +1818,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jiff" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +checksum = "c867c356cc096b33f4981825ab281ecba3db0acefe60329f044c1789d94c6543" dependencies = [ "jiff-static", "log", @@ -1813,20 +1831,20 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +checksum = "f7946b4325269738f270bb55b3c19ab5c5040525f83fd625259422a9d25d9be5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "d36139f1c97c42c0c86a411910b04e48d4939a0376e6e0f989420cbdee0120e5" dependencies = [ "once_cell", "wasm-bindgen", @@ -1848,9 +1866,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures", ] @@ -1861,11 +1879,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.180" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libsecp256k1" @@ -1974,9 +1998,9 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" @@ -2067,7 +2091,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2140,7 +2164,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2173,7 +2197,7 @@ version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "foreign-types", "libc", @@ -2190,14 +2214,14 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "openssl-src" -version = "300.5.4+3.5.4" +version = "300.5.5+3.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" +checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" dependencies = [ "cc", ] @@ -2269,6 +2293,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" + [[package]] name = "pbkdf2" version = "0.11.0" @@ -2309,12 +2339,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkcs8" version = "0.10.2" @@ -2373,15 +2397,15 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" dependencies = [ "portable-atomic", ] @@ -2405,6 +2429,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -2446,7 +2480,7 @@ dependencies = [ "log", "multimap", "petgraph", - "prettyplease", + "prettyplease 0.1.25", "prost", "prost-types", "regex", @@ -2504,7 +2538,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2681,14 +2715,14 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -2698,9 +2732,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -2709,9 +2743,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "rfc6979" @@ -2744,7 +2778,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2757,7 +2791,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.11.0", @@ -2857,7 +2891,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2892,7 +2926,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2919,6 +2953,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + [[package]] name = "sha3" version = "0.10.8" @@ -3002,9 +3042,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -3026,7 +3066,7 @@ dependencies = [ "solana-account-info", "solana-clock", "solana-instruction-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids", "solana-sysvar", ] @@ -3039,7 +3079,7 @@ checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" dependencies = [ "bincode", "serde_core", - "solana-address 2.0.0", + "solana-address 2.2.0", "solana-program-error", "solana-program-memory", ] @@ -3050,29 +3090,31 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.2.0", ] [[package]] name = "solana-address" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37320fd2945c5d654b2c6210624a52d66c3f1f73b653ed211ab91a703b35bdd" +checksum = "68c5d02824391b072dc5cd0aaa85fb0af9784a21d23286a767994d1e8a322131" dependencies = [ "borsh", "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", - "five8 1.0.0", + "five8", "five8_const", - "rand 0.8.5", + "rand 0.9.2", "serde", "serde_derive", + "sha2-const-stable", "solana-atomic-u64", - "solana-define-syscall 4.0.1", + "solana-define-syscall 5.0.0", "solana-program-error", "solana-sanitize", "solana-sha256-hasher", + "wincode", ] [[package]] @@ -3082,16 +3124,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e8df0b083c10ce32490410f3795016b1b5d9b4d094658c0a5e496753645b7cd" dependencies = [ "solana-clock", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids", "solana-slot-hashes", ] [[package]] name = "solana-atomic-u64" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a933ff1e50aff72d02173cfcd7511bd8540b027ee720b75f353f594f834216d0" +checksum = "085db4906d89324cef2a30840d59eaecf3d4231c560ec7c9f6614a93c652f501" dependencies = [ "parking_lot", ] @@ -3126,7 +3168,7 @@ checksum = "7116e1d942a2432ca3f514625104757ab8a56233787e95144c93950029e31176" dependencies = [ "blake3", "solana-define-syscall 4.0.1", - "solana-hash 4.0.1", + "solana-hash 4.2.0", ] [[package]] @@ -3176,7 +3218,7 @@ dependencies = [ "rand 0.9.2", "solana-account", "solana-bincode", - "solana-bpf-loader-program 4.0.0-alpha.0", + "solana-bpf-loader-program", "solana-clock", "solana-epoch-rewards", "solana-epoch-schedule", @@ -3189,8 +3231,8 @@ dependencies = [ "solana-program", "solana-program-entrypoint", "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sbpf", "solana-sdk-ids", "solana-slot-hashes", @@ -3199,54 +3241,26 @@ dependencies = [ "solana-svm-log-collector", "solana-svm-measure", "solana-svm-type-overrides", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-transaction-context", "static_assertions", "test-case", ] -[[package]] -name = "solana-bpf-loader-program" -version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" -dependencies = [ - "agave-syscalls", - "bincode", - "qualifier_attr", - "solana-account", - "solana-bincode", - "solana-clock", - "solana-instruction", - "solana-loader-v3-interface", - "solana-loader-v4-interface", - "solana-packet", - "solana-program-entrypoint", - "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-sbpf", - "solana-sdk-ids", - "solana-svm-feature-set", - "solana-svm-log-collector", - "solana-svm-measure", - "solana-svm-type-overrides", - "solana-system-interface 3.0.0", - "solana-transaction-context", -] - [[package]] name = "solana-builtins" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "agave-feature-set", - "solana-bpf-loader-program 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=a48940a24d)", - "solana-compute-budget-program 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=a48940a24d)", - "solana-hash 3.1.0", - "solana-loader-v4-program 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=a48940a24d)", + "solana-bpf-loader-program", + "solana-compute-budget-program 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=cc74332e59)", + "solana-hash 4.2.0", + "solana-loader-v4-program", "solana-program-runtime", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids", - "solana-system-program 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=a48940a24d)", + "solana-system-program 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=cc74332e59)", "solana-vote-program", "solana-zk-elgamal-proof-program", "solana-zk-token-proof-program", @@ -3254,9 +3268,9 @@ dependencies = [ [[package]] name = "solana-clock" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" +checksum = "95cf11109c3b6115cc510f1e31f06fdd52f504271bc24ef5f1249fbbcae5f9f3" dependencies = [ "serde", "serde_derive", @@ -3295,7 +3309,7 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "solana-program-runtime", ] @@ -3310,7 +3324,7 @@ dependencies = [ "solana-define-syscall 4.0.1", "solana-instruction", "solana-program-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-stable-layout", ] @@ -3371,13 +3385,13 @@ dependencies = [ [[package]] name = "solana-epoch-rewards" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" +checksum = "f5e7b0ba210593ba8ddd39d6d234d81795d1671cebf3026baa10d5dc23ac42f0" dependencies = [ "serde", "serde_derive", - "solana-hash 3.1.0", + "solana-hash 4.2.0", "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", @@ -3398,12 +3412,12 @@ dependencies = [ [[package]] name = "solana-epoch-stake" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc6693d0ea833b880514b9b88d95afb80b42762dca98b0712465d1fcbbcb89e" +checksum = "027e6d0b9e7daac5b2ac7c3f9ca1b727861121d9ef05084cf435ff736051e7c2" dependencies = [ - "solana-define-syscall 3.0.0", - "solana-pubkey 3.0.0", + "solana-define-syscall 5.0.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -3429,9 +3443,9 @@ dependencies = [ [[package]] name = "solana-fee-calculator" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a73cc03ca4bed871ca174558108835f8323e85917bb38b9c81c7af2ab853efe" +checksum = "4b2a5675b2cf8d407c672dc1776492b1f382337720ddf566645ae43237a3d8c3" dependencies = [ "log", "serde", @@ -3449,9 +3463,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10284a0ca713bcce197cff2c5408efe06ebe6b6bcc868074d4ccb71b5c60028" +checksum = "659e4b26dd0f4d3ed47cacd23fde923f4986bab1d1f04d49235d326fec77e3e3" dependencies = [ "bincode", "boxcar", @@ -3480,7 +3494,7 @@ checksum = "5396c179ca7d76f866b102eb3819ca3922bdaa33c9ada8005f4e98fd59ab65f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3489,45 +3503,46 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" dependencies = [ - "solana-hash 4.0.1", + "solana-hash 4.2.0", ] [[package]] name = "solana-hash" -version = "4.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5d48a6ee7b91fc7b998944ab026ed7b3e2fc8ee3bc58452644a86c2648152f" +checksum = "8064ea1d591ec791be95245058ca40f4f5345d390c200069d0f79bbf55bfae55" dependencies = [ "borsh", "bytemuck", "bytemuck_derive", - "five8 1.0.0", + "five8", "serde", "serde_derive", "solana-atomic-u64", "solana-sanitize", + "wincode", ] [[package]] name = "solana-instruction" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee1b699a2c1518028a9982e255e0eca10c44d90006542d9d7f9f40dbce3f7c78" +checksum = "c6a6d22d0a6fdf345be294bb9afdcd40c296cdc095e64e7ceaa3bb3c2f608c1c" dependencies = [ "bincode", "borsh", "serde", "serde_derive", - "solana-define-syscall 4.0.1", + "solana-define-syscall 5.0.0", "solana-instruction-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] name = "solana-instruction-error" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04259e03c05faf38a8c24217b5cfe4c90572ae6184ab49cddb1584fdd756d3f" +checksum = "7d3d048edaaeef5a3dc8c01853e585539a74417e4c2d43a9e2c161270045b838" dependencies = [ "num-traits", "serde", @@ -3541,7 +3556,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "solana-account-info", "solana-instruction", "solana-instruction-error", @@ -3561,19 +3576,19 @@ checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" dependencies = [ "sha3", "solana-define-syscall 4.0.1", - "solana-hash 4.0.1", + "solana-hash 4.2.0", ] [[package]] name = "solana-keypair" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8be597c9e231b0cab2928ce3bc3e4ee77d9c0ad92977b9d901f3879f25a7a" +checksum = "c9d3c6690dc56679545e3a31f72f590b3f5deaf48d9ea03efd2922c6a5984ed4" dependencies = [ "ed25519-dalek 2.2.0", - "five8 1.0.0", - "rand 0.8.5", - "solana-address 2.0.0", + "five8", + "rand 0.9.2", + "solana-address 2.2.0", "solana-seed-phrase", "solana-signature", "solana-signer", @@ -3630,14 +3645,14 @@ dependencies = [ "log", "solana-account", "solana-bincode", - "solana-bpf-loader-program 4.0.0-alpha.0", + "solana-bpf-loader-program", "solana-clock", "solana-instruction", "solana-loader-v3-interface", "solana-loader-v4-interface", "solana-packet", "solana-program-runtime", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sbpf", "solana-sdk-ids", "solana-svm-log-collector", @@ -3647,42 +3662,19 @@ dependencies = [ "solana-transaction-context", ] -[[package]] -name = "solana-loader-v4-program" -version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" -dependencies = [ - "log", - "solana-account", - "solana-bincode", - "solana-bpf-loader-program 4.0.0-alpha.0 (git+https://github.com/anza-xyz/agave?rev=a48940a24d)", - "solana-instruction", - "solana-loader-v3-interface", - "solana-loader-v4-interface", - "solana-packet", - "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-sbpf", - "solana-sdk-ids", - "solana-svm-log-collector", - "solana-svm-measure", - "solana-svm-type-overrides", - "solana-transaction-context", -] - [[package]] name = "solana-message" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85666605c9fd727f865ed381665db0a8fc29f984a030ecc1e40f43bfb2541623" +checksum = "0448b1fd891c5f46491e5dc7d9986385ba3c852c340db2911dd29faa01d2b08d" dependencies = [ "bincode", "blake3", "lazy_static", "serde", "serde_derive", - "solana-address 1.1.0", - "solana-hash 3.1.0", + "solana-address 2.2.0", + "solana-hash 4.2.0", "solana-instruction", "solana-sanitize", "solana-sdk-ids", @@ -3692,11 +3684,11 @@ dependencies = [ [[package]] name = "solana-msg" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "264275c556ea7e22b9d3f87d56305546a38d4eee8ec884f3b126236cb7dcbbb4" +checksum = "726b7cbbc6be6f1c6f29146ac824343b9415133eee8cce156452ad1db93f8008" dependencies = [ - "solana-define-syscall 3.0.0", + "solana-define-syscall 5.0.0", ] [[package]] @@ -3707,15 +3699,15 @@ checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" [[package]] name = "solana-nonce" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abbdc6c8caf1c08db9f36a50967539d0f72b9f1d4aea04fec5430f532e5afadc" +checksum = "cbc469152a63284ef959b80c59cda015262a021da55d3b8fe42171d89c4b64f8" dependencies = [ "serde", "serde_derive", "solana-fee-calculator", - "solana-hash 3.1.0", - "solana-pubkey 3.0.0", + "solana-hash 4.2.0", + "solana-pubkey 4.1.0", "solana-sha256-hasher", ] @@ -3733,12 +3725,12 @@ dependencies = [ [[package]] name = "solana-packet" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84c0811f3a9ee1d89050d538fcff77445f54449d2e09380a5aeeafe7425e7cc" +checksum = "0ad62e1045c2347a0c0e219a6ceb0abfe904be622920996bfcac8d116fabe3c7" dependencies = [ - "bitflags 2.10.0", - "solana-pubkey 4.0.0", + "bitflags 2.11.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -3796,7 +3788,7 @@ dependencies = [ "solana-program-option", "solana-program-pack", "solana-pubkey 3.0.0", - "solana-rent", + "solana-rent 3.1.0", "solana-sdk-ids", "solana-secp256k1-recover", "solana-serde-varint", @@ -3818,8 +3810,8 @@ dependencies = [ "serde", "solana-account", "solana-loader-v3-interface", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sdk-ids", "spl-generic-token", ] @@ -3833,7 +3825,7 @@ dependencies = [ "solana-account-info", "solana-define-syscall 4.0.1", "solana-program-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -3863,9 +3855,9 @@ checksum = "8e7b4ddb464f274deb4a497712664c3b612e3f5f82471d4e47710fc4ab1c3095" [[package]] name = "solana-program-pack" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c169359de21f6034a63ebf96d6b380980307df17a8d371344ff04a883ec4e9d0" +checksum = "3d7701cb15b90667ae1c89ef4ac35a59c61e66ce58ddee13d729472af7f41d59" dependencies = [ "solana-program-error", ] @@ -3900,8 +3892,8 @@ dependencies = [ "solana-loader-v3-interface", "solana-program-entrypoint", "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sbpf", "solana-sdk-ids", "solana-signer", @@ -3915,7 +3907,7 @@ dependencies = [ "solana-svm-timings 4.0.0-alpha.0", "solana-svm-transaction", "solana-svm-type-overrides", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-sysvar", "solana-sysvar-id", "solana-transaction", @@ -3935,19 +3927,19 @@ dependencies = [ [[package]] name = "solana-pubkey" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f7104d456b58e1418c21a8581e89810278d1190f70f27ece7fc0b2c9282a57" +checksum = "1b06bd918d60111ee1f97de817113e2040ca0cedb740099ee8d646233f6b906c" dependencies = [ - "rand 0.8.5", - "solana-address 2.0.0", + "rand 0.9.2", + "solana-address 2.2.0", ] [[package]] name = "solana-rent" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b702d8c43711e3c8a9284a4f1bbc6a3de2553deb25b0c8142f9a44ef0ce5ddc1" +checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" dependencies = [ "serde", "serde_derive", @@ -3956,6 +3948,15 @@ dependencies = [ "solana-sysvar-id", ] +[[package]] +name = "solana-rent" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1771d726d4854f1818c750e14aff40b19d84720d0b1b6d53e50e8f16cb6bd62" +dependencies = [ + "solana-sdk-macro", +] + [[package]] name = "solana-sanitize" version = "3.0.1" @@ -3964,9 +3965,9 @@ checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" [[package]] name = "solana-sbpf" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a642316efc0f73abc02da804f391f98aefecfa885a1472e31e4eeed93d8d3f8" +checksum = "733b3657a0fab205102b799dbe17f85d3972cf984232c1b0b108fa6ba438e382" dependencies = [ "byteorder", "combine", @@ -3987,26 +3988,26 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.2.0", ] [[package]] name = "solana-sdk-macro" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" +checksum = "8765316242300c48242d84a41614cb3388229ec353ba464f6fe62a733e41806f" dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "solana-secp256k1-program" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8efa767b0188f577edae7080e8bf080e5db9458e2b6ee5beaa73e2e6bb54e99d" +checksum = "ad4cf8232f7aef9ff2dd95d701f63e3c11909dec2400def5c361be29d24291e7" dependencies = [ "bincode", "digest 0.10.7", @@ -4021,12 +4022,12 @@ dependencies = [ [[package]] name = "solana-secp256k1-recover" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de18cfdab99eeb940fbedd8c981fa130c0d76252da75d05446f22fae8b51932" +checksum = "e7c5f18893d62e6c73117dcba48f8f5e3266d90e5ec3d0a0a90f9785adac36c1" dependencies = [ "k256", - "solana-define-syscall 4.0.1", + "solana-define-syscall 5.0.0", "thiserror 2.0.18", ] @@ -4064,21 +4065,21 @@ dependencies = [ [[package]] name = "solana-serde-varint" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5174c57d5ff3c1995f274d17156964664566e2cde18a07bba1586d35a70d3b" +checksum = "950e5b83e839dc0f92c66afc124bb8f40e89bc90f0579e8ec5499296d27f54e3" dependencies = [ "serde", ] [[package]] name = "solana-serialize-utils" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e41dd8feea239516c623a02f0a81c2367f4b604d7965237fed0751aeec33ed" +checksum = "5d7cc401931d178472358e6b78dc72d031dc08f752d7410f0e8bd259dd6f02fa" dependencies = [ "solana-instruction-error", - "solana-pubkey 3.0.0", + "solana-pubkey 4.1.0", "solana-sanitize", ] @@ -4090,31 +4091,32 @@ checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" dependencies = [ "sha2 0.10.9", "solana-define-syscall 4.0.1", - "solana-hash 4.0.1", + "solana-hash 4.2.0", ] [[package]] name = "solana-short-vec" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79fb1809a32cfcf7d9c47b7070a92fa17cdb620ab5829e9a8a9ff9d138a7a175" +checksum = "de3bd991c2cc415291c86bb0b6b4d53e93d13bb40344e4c5a2884e0e4f5fa93f" dependencies = [ "serde_core", ] [[package]] name = "solana-signature" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb8057cc0e9f7b5e89883d49de6f407df655bb6f3a71d0b7baf9986a2218fd9" +checksum = "132a93134f1262aa832f1849b83bec6c9945669b866da18661a427943b9e801e" dependencies = [ "ed25519-dalek 2.2.0", - "five8 0.2.1", - "rand 0.8.5", + "five8", + "rand 0.9.2", "serde", "serde-big-array", "serde_derive", "solana-sanitize", + "wincode", ] [[package]] @@ -4130,13 +4132,13 @@ dependencies = [ [[package]] name = "solana-slot-hashes" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" +checksum = "2585f70191623887329dfb5078da3a00e15e3980ea67f42c2e10b07028419f43" dependencies = [ "serde", "serde_derive", - "solana-hash 3.1.0", + "solana-hash 4.2.0", "solana-sdk-ids", "solana-sysvar-id", ] @@ -4156,12 +4158,12 @@ dependencies = [ [[package]] name = "solana-stable-layout" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" +checksum = "c9f6a291ba063a37780af29e7db14bdd3dc447584d8ba5b3fc4b88e2bbc982fa" dependencies = [ "solana-instruction", - "solana-pubkey 3.0.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -4202,7 +4204,7 @@ dependencies = [ "serde", "shuttle", "solana-account", - "solana-bpf-loader-program 4.0.0-alpha.0", + "solana-bpf-loader-program", "solana-clock", "solana-compute-budget", "solana-compute-budget-interface", @@ -4219,7 +4221,7 @@ dependencies = [ "solana-keypair", "solana-loader-v3-interface", "solana-loader-v4-interface", - "solana-loader-v4-program 4.0.0-alpha.0", + "solana-loader-v4-program", "solana-message", "solana-native-token", "solana-nonce", @@ -4229,8 +4231,8 @@ dependencies = [ "solana-program-entrypoint", "solana-program-pack", "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sbpf", "solana-sdk-ids", "solana-secp256k1-program", @@ -4245,7 +4247,7 @@ dependencies = [ "solana-svm-timings 4.0.0-alpha.0", "solana-svm-transaction", "solana-svm-type-overrides", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-system-program 4.0.0-alpha.0", "solana-system-transaction", "solana-sysvar", @@ -4266,18 +4268,18 @@ dependencies = [ "solana-account", "solana-clock", "solana-precompile-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] name = "solana-svm-callback" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "solana-account", "solana-clock", "solana-precompile-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -4318,7 +4320,7 @@ dependencies = [ "solana-account", "solana-instruction", "solana-instruction-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-svm-feature-set", "thiserror 2.0.18", ] @@ -4341,11 +4343,12 @@ dependencies = [ "solana-instruction", "solana-instruction-error", "solana-last-restart-slot", + "solana-loader-v4-interface", "solana-message", "solana-precompile-error", "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sdk-ids", "solana-svm", "solana-svm-callback 4.0.0-alpha.0", @@ -4364,17 +4367,17 @@ version = "4.0.0-alpha.0" dependencies = [ "eager", "enum-iterator", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] name = "solana-svm-timings" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "eager", "enum-iterator", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -4384,10 +4387,10 @@ dependencies = [ "solana-hash 3.1.0", "solana-message", "solana-nonce", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids", "solana-signature", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-transaction", "static_assertions", "test-case", @@ -4419,14 +4422,14 @@ dependencies = [ [[package]] name = "solana-system-interface" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14591d6508042ebefb110305d3ba761615927146a26917ade45dc332d8e1ecde" +checksum = "a95a6f2e23ed861d6444ad4a6d6896c418d7d101b960787e65a8e33157cee81b" dependencies = [ "num-traits", "serde", "serde_derive", - "solana-address 2.0.0", + "solana-address 2.2.0", "solana-instruction", "solana-msg", "solana-program-error", @@ -4451,15 +4454,15 @@ dependencies = [ "solana-nonce-account", "solana-packet", "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sdk-ids", "solana-sha256-hasher", "solana-svm-callback 4.0.0-alpha.0", "solana-svm-feature-set", "solana-svm-log-collector", "solana-svm-type-overrides", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-system-program 4.0.0-alpha.0", "solana-sysvar", "solana-transaction-context", @@ -4468,7 +4471,7 @@ dependencies = [ [[package]] name = "solana-system-program" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "bincode", "log", @@ -4481,11 +4484,11 @@ dependencies = [ "solana-nonce-account", "solana-packet", "solana-program-runtime", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids", "solana-svm-log-collector", "solana-svm-type-overrides", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-sysvar", "solana-transaction-context", ] @@ -4524,14 +4527,14 @@ dependencies = [ "solana-epoch-rewards", "solana-epoch-schedule", "solana-fee-calculator", - "solana-hash 4.0.1", + "solana-hash 4.2.0", "solana-instruction", "solana-last-restart-slot", "solana-program-entrypoint", "solana-program-error", "solana-program-memory", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sdk-ids", "solana-sdk-macro", "solana-slot-hashes", @@ -4545,21 +4548,21 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.2.0", "solana-sdk-ids", ] [[package]] name = "solana-transaction" -version = "3.0.2" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ceb2efbf427a91b884709ffac4dac29117752ce1e37e9ae04977e450aa0bb76" +checksum = "96697cff5075a028265324255efed226099f6d761ca67342b230d09f72cc48d2" dependencies = [ "bincode", "serde", "serde_derive", - "solana-address 2.0.0", - "solana-hash 4.0.1", + "solana-address 2.2.0", + "solana-hash 4.2.0", "solana-instruction", "solana-instruction-error", "solana-message", @@ -4583,21 +4586,21 @@ dependencies = [ "solana-instruction", "solana-instructions-sysvar", "solana-program-entrypoint", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sbpf", "solana-sdk-ids", "solana-signature", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-transaction-context", "static_assertions", ] [[package]] name = "solana-transaction-error" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4222065402340d7e6aec9dc3e54d22992ddcf923d91edcd815443c2bfca3144a" +checksum = "8396904805b0b385b9de115a652fe80fd01e5b98ce0513f4fcd8184ada9bb792" dependencies = [ "serde", "serde_derive", @@ -4607,9 +4610,9 @@ dependencies = [ [[package]] name = "solana-vote-interface" -version = "5.0.0" +version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7b4fb47dbad5a777e08ac4b1259e1fc5839c2e250512902a6d3b814f5c6040f" +checksum = "d444ce30b6b4f9c281ba06061ea96638d063b53c2171b1e41ba02ebff79ed28f" dependencies = [ "bincode", "cfg_eval", @@ -4619,22 +4622,22 @@ dependencies = [ "serde_derive", "serde_with", "solana-clock", - "solana-hash 4.0.1", + "solana-hash 4.2.0", "solana-instruction", "solana-instruction-error", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 4.1.0", "solana-sdk-ids", "solana-serde-varint", "solana-serialize-utils", "solana-short-vec", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", ] [[package]] name = "solana-vote-program" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "agave-feature-set", "bincode", @@ -4647,17 +4650,17 @@ dependencies = [ "solana-bls-signatures", "solana-clock", "solana-epoch-schedule", - "solana-hash 3.1.0", + "solana-hash 4.2.0", "solana-instruction", "solana-keypair", "solana-packet", "solana-program-runtime", - "solana-pubkey 4.0.0", - "solana-rent", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sdk-ids", "solana-signer", "solana-slot-hashes", - "solana-system-interface 3.0.0", + "solana-system-interface 3.1.0", "solana-transaction", "solana-transaction-context", "solana-vote-interface", @@ -4667,7 +4670,7 @@ dependencies = [ [[package]] name = "solana-zk-elgamal-proof-program" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "agave-feature-set", "bytemuck", @@ -4682,9 +4685,9 @@ dependencies = [ [[package]] name = "solana-zk-sdk" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89042b5867c7440526d47085db2cd11a7ae557461a4f41a3b3a569799dd9d6" +checksum = "09670ff59f60e6ddc2209c2e4353992a9b9f01d4e244f3e9d67bd5146e33d388" dependencies = [ "aes-gcm-siv", "base64 0.22.1", @@ -4701,7 +4704,7 @@ dependencies = [ "serde_derive", "serde_json", "sha3", - "solana-address 2.0.0", + "solana-address 2.2.0", "solana-derivation-path", "solana-instruction", "solana-sdk-ids", @@ -4717,7 +4720,7 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" version = "4.0.0-alpha.0" -source = "git+https://github.com/anza-xyz/agave?rev=a48940a24d#a48940a24d513041beb6fa09225d3843b459b4e7" +source = "git+https://github.com/anza-xyz/agave?rev=cc74332e59#cc74332e5951f66f63555848fc186bcc267059eb" dependencies = [ "solana-program-runtime", ] @@ -4793,9 +4796,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -4810,12 +4813,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.24.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.1", "once_cell", "rustix 1.1.3", "windows-sys 0.61.2", @@ -4839,7 +4842,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4850,7 +4853,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "test-case-core", ] @@ -4880,7 +4883,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4891,7 +4894,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4951,9 +4954,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow", ] @@ -4985,9 +4988,15 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -5073,11 +5082,20 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "9ff9c7baef35ac3c0e17d8bfc9ad75eb62f85a2f02bccc906699dadb0aa9c622" dependencies = [ "cfg-if", "once_cell", @@ -5088,9 +5106,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "39455e84ad887a0bbc93c116d72403f1bb0a39e37dd6f235a43e2128a0c7f1fd" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5098,31 +5116,65 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "dff4761f60b0b51fd13fec8764167b7bbcc34498ce3e52805fe1db6f2d56b6d6" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "bc6a171c53d98021a93a474c4a4579d76ba97f9517d871bc12e27640f218b6dd" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "668fa5d00434e890a452ab060d24e3904d1be93f7bb01b70e5603baa2b8ab23b" dependencies = [ "js-sys", "wasm-bindgen", @@ -5171,6 +5223,31 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wincode" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "466e67917609b2d40a838a5b972d1a6237c9749600cb8de8f65559b90d48485b" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.18", + "wincode-derive", +] + +[[package]] +name = "wincode-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26a7a568eda854acc9945ed136a9d50b8c6d31911584624958808ae96eee3912" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -5282,6 +5359,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease 0.2.37", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease 0.2.37", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "wyz" @@ -5294,22 +5453,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.34" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.34" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5329,11 +5488,11 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "zmij" -version = "1.0.17" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 53dfacf1..f9aad2b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ level = "warn" check-cfg = [ 'cfg(target_os, values("solana"))', 'cfg(feature, values("frozen-abi", "no-entrypoint"))', + 'cfg(target_arch, values("sbf"))', ] # Clippy lint configuration that can not be applied in clippy.toml @@ -65,12 +66,12 @@ manual_let_else = "deny" used_underscore_binding = "deny" [workspace.dependencies] -agave-feature-set = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } -agave-logger = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } -agave-precompiles = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } -agave-reserved-account-keys = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } -agave-syscalls = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } -agave-validator = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +agave-feature-set = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } +agave-logger = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } +agave-precompiles = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } +agave-reserved-account-keys = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } +agave-syscalls = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } +agave-validator = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } ahash = "0.8.12" anyhow = "1.0.100" arbitrary = "1.4.2" @@ -105,10 +106,7 @@ hex = "0.4.3" hmac = "0.12.1" itertools = "0.14.0" libc = "0.2.180" -libsecp256k1 = { version = "0.6.0", default-features = false, features = [ - "std", - "static-context", -] } +libsecp256k1 = { version = "0.6.0", default-features = false, features = ["std", "static-context"] } log = "0.4.29" memmap2 = "0.9.9" num-derive = "0.4" @@ -131,19 +129,19 @@ sha2 = "0.10.9" sha3 = "0.10.8" shuttle = "0.7.1" solana-account = "3.4.0" -solana-account-decoder = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-account-decoder = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-account-info = "3.1.0" -solana-accounts-db = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-accounts-db = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-big-mod-exp = "3.0.0" solana-bincode = "3.1.0" solana-bn254 = "3.2.1" solana-borsh = "3.0.0" solana-bpf-loader-program = { path = "programs/bpf_loader", version = "=4.0.0-alpha.0", features = ["agave-unstable-api"] } -solana-builtins = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } -solana-cli-output = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-builtins = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } +solana-cli-output = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-clock = "3.0.0" solana-compute-budget = { path = "compute-budget", version = "=4.0.0-alpha.0", features = ["agave-unstable-api"] } -solana-compute-budget-instruction = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-compute-budget-instruction = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-compute-budget-interface = "3.0.0" solana-compute-budget-program = { path = "programs/compute-budget", version = "=4.0.0-alpha.0", features = ["agave-unstable-api"] } solana-curve25519 = "4.0.0" @@ -163,11 +161,11 @@ solana-instruction-error = "2.1.0" solana-instructions-sysvar = "3.0.0" solana-keypair = "3.1.0" solana-last-restart-slot = "3.0.0" -solana-ledger = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-ledger = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-loader-v3-interface = "6.1.0" solana-loader-v4-interface = "3.1.0" -solana-loader-v4-program = { path = "programs/loader-v4", version = "=4.0.0-alpha.0", features = ["agave-unstable-api"] } -solana-measure = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-loader-v4-program = { path = "programs/loader-v4", version = "=4.0.0-alpha.0", default-features = false, features = ["agave-unstable-api"] } +solana-measure = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-message = "3.0.1" solana-native-token = "3.0.0" solana-nonce = "3.0.0" @@ -185,8 +183,8 @@ solana-program-pack = "3.0.0" solana-program-runtime = { path = "program-runtime", version = "=4.0.0-alpha.0", features = ["agave-unstable-api"] } solana-pubkey = "4.0.0" solana-rent = "3.0.0" -solana-runtime = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } -solana-runtime-transaction = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-runtime = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } +solana-runtime-transaction = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-sanitize = "3.0.1" solana-sbpf = "0.14.1" solana-sdk-ids = "3.1.0" @@ -221,11 +219,11 @@ solana-sysvar-id = "3.1.0" solana-transaction = "3.0.2" solana-transaction-context = { path = "transaction-context", version = "=4.0.0-alpha.0", features = ["agave-unstable-api", "bincode"] } solana-transaction-error = "3.0.0" -solana-transaction-status = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-transaction-status = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-version = "3.1.0" -solana-vote = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", features = ["agave-unstable-api"] } +solana-vote = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", features = ["agave-unstable-api"] } solana-vote-interface = "3.0.0" -solana-vote-program = { git = "https://github.com/anza-xyz/agave", rev = "a48940a24d", default-features = false, features = ["agave-unstable-api"] } +solana-vote-program = { git = "https://github.com/anza-xyz/agave", rev = "cc74332e59", default-features = false, features = ["agave-unstable-api"] } solana-zk-elgamal-proof-program = "3.0.0" solana-zk-sdk = "5.0.0" solana-zk-token-proof-program = "3.0.0" @@ -244,3 +242,5 @@ solana-svm-measure = { path = "measure" } solana-program-runtime = { path = "program-runtime" } solana-transaction-context = { path = "transaction-context" } solana-svm-type-overrides = { path = "type-overrides" } +solana-bpf-loader-program = { path = "programs/bpf_loader" } +solana-loader-v4-program = { path = "programs/loader-v4" } diff --git a/compute-budget/Cargo.toml b/compute-budget/Cargo.toml index fbd9251f..f58041c9 100644 --- a/compute-budget/Cargo.toml +++ b/compute-budget/Cargo.toml @@ -20,9 +20,7 @@ frozen-abi = ["dep:solana-frozen-abi", "solana-fee-structure/frozen-abi"] [dependencies] qualifier_attr = { workspace = true, optional = true } solana-fee-structure = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } +solana-frozen-abi = { workspace = true, optional = true, features = ["frozen-abi"] } solana-program-runtime = { workspace = true } [lints] diff --git a/compute-budget/src/compute_budget.rs b/compute-budget/src/compute_budget.rs index 7eb44948..ae7b725d 100644 --- a/compute-budget/src/compute_budget.rs +++ b/compute-budget/src/compute_budget.rs @@ -1,6 +1,6 @@ pub use solana_program_runtime::execution_budget::{ - SVMTransactionExecutionBudget, SVMTransactionExecutionCost, MAX_CALL_DEPTH, - MAX_INSTRUCTION_STACK_DEPTH, STACK_FRAME_SIZE, + MAX_CALL_DEPTH, MAX_INSTRUCTION_STACK_DEPTH, STACK_FRAME_SIZE, SVMTransactionExecutionBudget, + SVMTransactionExecutionCost, }; use { solana_fee_structure::FeeDetails, diff --git a/feature-set/src/lib.rs b/feature-set/src/lib.rs index 3172d342..ba4699e2 100644 --- a/feature-set/src/lib.rs +++ b/feature-set/src/lib.rs @@ -51,6 +51,7 @@ pub struct SVMFeatureSet { pub custom_commission_collector: bool, pub enable_bls12_381_syscall: bool, pub block_revenue_sharing: bool, + pub vote_account_initialize_v2: bool, } impl SVMFeatureSet { @@ -106,6 +107,7 @@ impl SVMFeatureSet { custom_commission_collector: true, enable_bls12_381_syscall: true, block_revenue_sharing: true, + vote_account_initialize_v2: true, } } } diff --git a/program-runtime/Cargo.toml b/program-runtime/Cargo.toml index 87e8befb..65df9637 100644 --- a/program-runtime/Cargo.toml +++ b/program-runtime/Cargo.toml @@ -42,12 +42,8 @@ solana-clock = { workspace = true } solana-epoch-rewards = { workspace = true } solana-epoch-schedule = { workspace = true } solana-fee-structure = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } +solana-frozen-abi = { workspace = true, optional = true, features = ["frozen-abi"] } +solana-frozen-abi-macro = { workspace = true, optional = true, features = ["frozen-abi"] } solana-hash = { workspace = true } solana-instruction = { workspace = true } solana-last-restart-slot = { workspace = true } @@ -83,9 +79,7 @@ solana-program-runtime = { path = ".", features = ["dev-context-only-utils"] } solana-pubkey = { workspace = true, features = ["rand"] } solana-signer = { workspace = true } solana-transaction = { workspace = true, features = ["dev-context-only-utils"] } -solana-transaction-context = { workspace = true, features = [ - "dev-context-only-utils", -] } +solana-transaction-context = { workspace = true, features = ["dev-context-only-utils"] } test-case = { workspace = true } [lints] diff --git a/program-runtime/src/cpi.rs b/program-runtime/src/cpi.rs index 280ab63c..e5eb23dc 100644 --- a/program-runtime/src/cpi.rs +++ b/program-runtime/src/cpi.rs @@ -880,7 +880,7 @@ pub fn cpi_common( check_aligned, )?; check_authorized_program(&instruction.program_id, &instruction.data, invoke_context)?; - invoke_context.prepare_next_instruction(instruction, &signers)?; + invoke_context.prepare_next_cpi_instruction(instruction, &signers)?; let mut accounts = S::translate_accounts( account_infos_addr, @@ -1454,7 +1454,7 @@ mod tests { ); $invoke_context .transaction_context - .configure_next_instruction_for_tests( + .configure_top_level_instruction_for_tests( $program_account, instruction_accounts, instruction_data.to_vec(), @@ -1968,7 +1968,7 @@ mod tests { invoke_context .transaction_context - .configure_next_instruction_for_tests( + .configure_next_cpi_for_tests( 0, vec![ InstructionAccount::new(1, false, true), diff --git a/program-runtime/src/deploy.rs b/program-runtime/src/deploy.rs index c3781a90..0ada8eb1 100644 --- a/program-runtime/src/deploy.rs +++ b/program-runtime/src/deploy.rs @@ -45,51 +45,6 @@ fn morph_into_deployment_environment_v1<'a>( Ok(result) } -#[allow(clippy::too_many_arguments)] -pub fn load_program_from_bytes( - log_collector: Option>>, - #[cfg(feature = "metrics")] load_program_metrics: &mut LoadProgramMetrics, - programdata: &[u8], - loader_key: &Pubkey, - account_size: usize, - deployment_slot: Slot, - program_runtime_environment: Arc>>, - reloading: bool, -) -> Result { - let effective_slot = deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET); - let loaded_program = if reloading { - // Safety: this is safe because the program is being reloaded in the cache. - unsafe { - ProgramCacheEntry::reload( - loader_key, - program_runtime_environment, - deployment_slot, - effective_slot, - programdata, - account_size, - #[cfg(feature = "metrics")] - load_program_metrics, - ) - } - } else { - ProgramCacheEntry::new( - loader_key, - program_runtime_environment, - deployment_slot, - effective_slot, - programdata, - account_size, - #[cfg(feature = "metrics")] - load_program_metrics, - ) - } - .map_err(|err| { - ic_logger_msg!(log_collector, "{}", err); - InstructionError::InvalidAccountData - })?; - Ok(loaded_program) -} - /// Directly deploy a program using a provided invoke context. /// This function should only be invoked from the runtime, since it does not /// provide any account loads or checks. @@ -145,17 +100,23 @@ pub fn deploy_program( load_program_metrics.verify_code_us = verify_code_time.as_us(); } // Reload but with program_runtime_environment - let executor = load_program_from_bytes( - log_collector, - #[cfg(feature = "metrics")] - load_program_metrics, - programdata, - loader_key, - account_size, - deployment_slot, - program_runtime_environment, - true, - )?; + let executor = unsafe { + // SAFETY: The executable has been verified just above. + ProgramCacheEntry::reload( + loader_key, + program_runtime_environment, + deployment_slot, + deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), + programdata, + account_size, + #[cfg(feature = "metrics")] + load_program_metrics, + ) + } + .map_err(|err| { + ic_logger_msg!(log_collector, "{}", err); + InstructionError::InvalidAccountData + })?; if let Some(old_entry) = program_cache_for_tx_batch.find(program_id) { executor.tx_usage_counter.store( old_entry.tx_usage_counter.load(Ordering::Relaxed), diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index df559435..37b41d4e 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -32,8 +32,8 @@ use { solana_svm_transaction::{instruction::SVMInstruction, svm_message::SVMMessage}, solana_svm_type_overrides::sync::Arc, solana_transaction_context::{ - IndexOfAccount, MAX_ACCOUNTS_PER_TRANSACTION, TransactionContext, - instruction::InstructionContext, instruction_accounts::InstructionAccount, + IndexOfAccount, MAX_ACCOUNTS_PER_TRANSACTION, instruction::InstructionContext, + instruction_accounts::InstructionAccount, transaction::TransactionContext, transaction_accounts::KeyedAccountSharedData, }, std::{ @@ -203,6 +203,9 @@ pub struct InvokeContext<'a, 'ix_data> { pub syscall_context: Vec>, /// Pairs of index in TX instruction trace and VM register trace register_traces: Vec<(usize, Vec<[u64; 12]>)>, + /// Debug port to use for this executing transaction. + #[cfg(feature = "sbpf-debugger")] + pub debug_port: Option, } impl<'a, 'ix_data> InvokeContext<'a, 'ix_data> { @@ -227,6 +230,8 @@ impl<'a, 'ix_data> InvokeContext<'a, 'ix_data> { timings: ExecuteDetailsTimings::default(), syscall_context: Vec::new(), register_traces: Vec::new(), + #[cfg(feature = "sbpf-debugger")] + debug_port: None, } } @@ -283,7 +288,7 @@ impl<'a, 'ix_data> InvokeContext<'a, 'ix_data> { instruction: Instruction, signers: &[Pubkey], ) -> Result<(), InstructionError> { - self.prepare_next_instruction(instruction, signers)?; + self.prepare_next_cpi_instruction(instruction, signers)?; let mut compute_units_consumed = 0; self.process_instruction(&mut compute_units_consumed, &mut ExecuteTimings::default())?; Ok(()) @@ -291,7 +296,7 @@ impl<'a, 'ix_data> InvokeContext<'a, 'ix_data> { /// Helper to prepare for process_instruction() when the instruction is not a top level one, /// and depends on `AccountMeta`s - pub fn prepare_next_instruction( + pub fn prepare_next_cpi_instruction( &mut self, instruction: Instruction, signers: &[Pubkey], @@ -426,7 +431,8 @@ impl<'a, 'ix_data> InvokeContext<'a, 'ix_data> { // This ? operator should not error out because `fn get_current_instruction_index` is also called // in `get_current_instruction_context` let caller_index = self.transaction_context.get_current_instruction_index()?; - self.transaction_context.configure_next_instruction( + self.transaction_context.configure_instruction_at_index( + self.transaction_context.get_instruction_trace_length(), program_account_index, instruction_accounts, transaction_callee_map, @@ -469,7 +475,8 @@ impl<'a, 'ix_data> InvokeContext<'a, 'ix_data> { )); } - self.transaction_context.configure_next_instruction( + self.transaction_context.configure_instruction_at_index( + self.transaction_context.get_instruction_trace_length(), program_account_index, instruction_accounts, transaction_callee_map, @@ -773,6 +780,7 @@ macro_rules! with_mock_invoke_context_with_feature_set { $invoke_context:ident, $transaction_context:ident, $feature_set:ident, + $top_level_instructions:literal, $transaction_accounts:expr $(,)? ) => { use { @@ -798,7 +806,7 @@ macro_rules! with_mock_invoke_context_with_feature_set { Rent::default(), compute_budget.max_instruction_stack_depth, compute_budget.max_instruction_trace_length, - /* number_of_top_level_instructions */ 1, + $top_level_instructions, ); let mut sysvar_cache = SysvarCache::default(); sysvar_cache.fill_missing_entries(|pubkey, callback| { @@ -840,6 +848,20 @@ macro_rules! with_mock_invoke_context_with_feature_set { ), ); }; + ( + $invoke_context:ident, + $transaction_context:ident, + $feature_set:ident, + $transaction_accounts:expr $(,)? + ) => { + with_mock_invoke_context_with_feature_set!( + $invoke_context, + $transaction_context, + $feature_set, + 1, + $transaction_accounts + ); + }; } #[macro_export] @@ -847,17 +869,30 @@ macro_rules! with_mock_invoke_context { ( $invoke_context:ident, $transaction_context:ident, + $top_level_instructions:literal, $transaction_accounts:expr $(,)? ) => { - use $crate::with_mock_invoke_context_with_feature_set; let feature_set = &solana_svm_feature_set::SVMFeatureSet::default(); - with_mock_invoke_context_with_feature_set!( + $crate::with_mock_invoke_context_with_feature_set!( $invoke_context, $transaction_context, feature_set, + $top_level_instructions, $transaction_accounts ) }; + ( + $invoke_context:ident, + $transaction_context:ident, + $transaction_accounts:expr $(,)? + ) => { + with_mock_invoke_context!( + $invoke_context, + $transaction_context, + 1, + $transaction_accounts + ); + }; } #[allow(clippy::too_many_arguments)] @@ -932,7 +967,7 @@ pub fn mock_process_instruction_with_feature_set< pre_adjustments(&mut invoke_context); invoke_context .transaction_context - .configure_next_instruction_for_tests( + .configure_top_level_instruction_for_tests( program_index, instruction_accounts, instruction_data.to_vec(), @@ -1072,7 +1107,11 @@ mod tests { ); invoke_context .transaction_context - .configure_next_instruction_for_tests(3, instruction_accounts, vec![]) + .configure_top_level_instruction_for_tests( + 3, + instruction_accounts, + vec![], + ) .unwrap(); let result = invoke_context.push(); assert_eq!(result, Err(InstructionError::UnbalancedInstruction)); @@ -1144,7 +1183,7 @@ mod tests { for _ in 0..invoke_stack.len() { invoke_context .transaction_context - .configure_next_instruction_for_tests( + .configure_top_level_instruction_for_tests( one_more_than_max_depth.saturating_add(depth_reached) as IndexOfAccount, instruction_accounts.clone(), vec![], @@ -1160,7 +1199,7 @@ mod tests { } #[test] - fn test_max_instruction_trace_length() { + fn test_max_instruction_trace_length_top_level() { const MAX_INSTRUCTIONS: usize = 8; let mut transaction_context = TransactionContext::new( vec![( @@ -1175,7 +1214,7 @@ mod tests { for _ in 0..MAX_INSTRUCTIONS { transaction_context.push().unwrap(); transaction_context - .configure_next_instruction_for_tests( + .configure_top_level_instruction_for_tests( 0, vec![InstructionAccount::new(0, false, false)], vec![], @@ -1189,6 +1228,61 @@ mod tests { ); } + #[test] + fn test_max_instruction_trace_length_cpi() { + // Hitting the limit with CPIs + const MAX_INSTRUCTIONS: usize = 8; + let mut transaction_context = TransactionContext::new( + vec![( + Pubkey::new_unique(), + AccountSharedData::new(1, 1, &Pubkey::new_unique()), + )], + Rent::default(), + 256, + MAX_INSTRUCTIONS, + 2, + ); + + // To be uncommented when we reorder the trace + // transaction_context + // .configure_instruction_at_index( + // 0, + // 0, + // vec![InstructionAccount::new(0, false, false)], + // vec![u16::MAX; 256], + // Cow::Owned(Vec::new()), + // None, + // ) + // .unwrap(); + // + // transaction_context + // .configure_instruction_at_index( + // 1, + // 0, + // vec![InstructionAccount::new(0, false, false)], + // vec![u16::MAX; 256], + // Cow::Owned(Vec::new()), + // None, + // ) + // .unwrap(); + + for _ in 0..MAX_INSTRUCTIONS { + transaction_context.push().unwrap(); + transaction_context + .configure_next_cpi_for_tests( + 0, + vec![InstructionAccount::new(0, false, false)], + Vec::new(), + ) + .unwrap(); + } + + assert_eq!( + transaction_context.push(), + Err(InstructionError::MaxInstructionTraceLengthExceeded) + ); + } + #[test_case(MockInstruction::NoopSuccess, Ok(()); "NoopSuccess")] #[test_case(MockInstruction::NoopFail, Err(InstructionError::GenericError); "NoopFail")] #[test_case(MockInstruction::ModifyOwned, Ok(()); "ModifyOwned")] @@ -1239,11 +1333,11 @@ mod tests { // Account modification tests invoke_context .transaction_context - .configure_next_instruction_for_tests(4, instruction_accounts, vec![]) + .configure_top_level_instruction_for_tests(4, instruction_accounts, vec![]) .unwrap(); invoke_context.push().unwrap(); let inner_instruction = - Instruction::new_with_bincode(callee_program_id, &instruction, metas.clone()); + Instruction::new_with_bincode(callee_program_id, &instruction, metas); let result = invoke_context .native_invoke(inner_instruction, &[]) .and(invoke_context.pop()); @@ -1295,7 +1389,7 @@ mod tests { let compute_units_to_consume = 10; invoke_context .transaction_context - .configure_next_instruction_for_tests(4, instruction_accounts, vec![]) + .configure_top_level_instruction_for_tests(4, instruction_accounts, vec![]) .unwrap(); invoke_context.push().unwrap(); let inner_instruction = Instruction::new_with_bincode( @@ -1304,10 +1398,10 @@ mod tests { compute_units_to_consume, desired_result: expected_result.clone(), }, - metas.clone(), + metas, ); invoke_context - .prepare_next_instruction(inner_instruction, &[]) + .prepare_next_cpi_instruction(inner_instruction, &[]) .unwrap(); let mut compute_units_consumed = 0; @@ -1340,7 +1434,7 @@ mod tests { invoke_context .transaction_context - .configure_next_instruction_for_tests(0, vec![], vec![]) + .configure_top_level_instruction_for_tests(0, vec![], vec![]) .unwrap(); invoke_context.push().unwrap(); assert_eq!(*invoke_context.get_compute_budget(), execution_budget); @@ -1380,7 +1474,7 @@ mod tests { invoke_context .transaction_context - .configure_next_instruction_for_tests(2, instruction_accounts, instruction_data) + .configure_top_level_instruction_for_tests(2, instruction_accounts, instruction_data) .unwrap(); let result = invoke_context.process_instruction(&mut 0, &mut ExecuteTimings::default()); @@ -1428,7 +1522,7 @@ mod tests { } } - with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts); + with_mock_invoke_context!(invoke_context, transaction_context, 2, transaction_accounts); let instruction_1 = Instruction::new_with_bytes(program_id, &[20], account_metas.clone()); @@ -1535,13 +1629,13 @@ mod tests { invoke_context.transaction_context.push().unwrap(); invoke_context - .prepare_next_instruction(instruction_1, &[fee_payer.pubkey()]) + .prepare_next_cpi_instruction(instruction_1, &[fee_payer.pubkey()]) .unwrap(); test_case_1(&invoke_context); invoke_context.transaction_context.push().unwrap(); invoke_context - .prepare_next_instruction(instruction_2, &[fee_payer.pubkey()]) + .prepare_next_cpi_instruction(instruction_2, &[fee_payer.pubkey()]) .unwrap(); test_case_2(&invoke_context); } @@ -1626,7 +1720,7 @@ mod tests { ); invoke_context - .prepare_next_instruction(instruction, &[fee_payer.pubkey()]) + .prepare_next_cpi_instruction(instruction, &[fee_payer.pubkey()]) .unwrap(); let instruction_context = invoke_context .transaction_context diff --git a/program-runtime/src/lib.rs b/program-runtime/src/lib.rs index 1470e71a..3b66a171 100644 --- a/program-runtime/src/lib.rs +++ b/program-runtime/src/lib.rs @@ -24,6 +24,6 @@ pub mod __private { solana_hash::Hash, solana_instruction::error::InstructionError, solana_rent::Rent, - solana_transaction_context::TransactionContext, + solana_transaction_context::transaction::TransactionContext, }; } diff --git a/program-runtime/src/loaded_programs.rs b/program-runtime/src/loaded_programs.rs index df96af40..0d60f21d 100644 --- a/program-runtime/src/loaded_programs.rs +++ b/program-runtime/src/loaded_programs.rs @@ -849,7 +849,7 @@ impl ProgramCache { match &mut self.index { IndexImplementation::V1 { entries, .. } => { let slot_versions = &mut entries.entry(key).or_default(); - match slot_versions.binary_search_by(|at| { + let insertion_point = slot_versions.binary_search_by(|at| { at.effective_slot .cmp(&entry.effective_slot) .then(at.deployment_slot.cmp(&entry.deployment_slot)) @@ -866,7 +866,8 @@ impl ProgramCache { entry.program.get_environment(), )), ) - }) { + }); + match insertion_point { Ok(index) => { let existing = slot_versions.get_mut(index).unwrap(); match (&existing.program, &entry.program) { @@ -904,7 +905,8 @@ impl ProgramCache { slot_versions.insert(index, Arc::clone(&entry)); } } - // Remove existing entries in the same deployment slot unless they are for a different environment. + // Remove existing entries in the same deployment slot unless they are for a different + // environment. // This overwrites the current status of a program in program management instructions. slot_versions.retain(|existing| { existing.deployment_slot != entry.deployment_slot @@ -969,12 +971,13 @@ impl ProgramCache { first_ancestor_env = entry.program.get_environment(); return true; } - // Do not prune the entry if the runtime environment of the entry is different - // than the entry that was previously found (stored in first_ancestor_env). - // Different environment indicates that this entry might belong to an older - // epoch that had a different environment (e.g. different feature set). - // Once the root moves to the new/current epoch, the entry will get pruned. - // But, until then the entry might still be getting used by an older slot. + // Do not prune the entry if the runtime environment of the entry is + // different than the entry that was previously found (stored in + // first_ancestor_env). Different environment indicates that this entry + // might belong to an older epoch that had a different environment (e.g. + // different feature set). Once the root moves to the new/current epoch, + // the entry will get pruned. But, until then the entry might still be + // getting used by an older slot. if let Some(entry_env) = entry.program.get_environment() && let Some(env) = first_ancestor_env && !Arc::ptr_eq(entry_env, env) @@ -1058,28 +1061,36 @@ impl ProgramCache { if let Some(second_level) = entries.get(key) { let mut filter_by_deployment_slot = None; for entry in second_level.iter().rev() { - if filter_by_deployment_slot - .map(|slot| slot != entry.deployment_slot) - .unwrap_or(false) - { + let required_deployment_slot = + filter_by_deployment_slot.unwrap_or(entry.deployment_slot); + if required_deployment_slot != entry.deployment_slot { continue; } - if entry.deployment_slot <= self.latest_root_slot + let entry_in_same_branch = entry.deployment_slot + <= self.latest_root_slot || matches!( locked_fork_graph.relationship( entry.deployment_slot, loaded_programs_for_tx_batch.slot ), BlockRelation::Equal | BlockRelation::Ancestor - ) - { - let entry_to_return = if loaded_programs_for_tx_batch.slot - >= entry.effective_slot - { + ); + if entry_in_same_branch { + let entry_is_effective = + loaded_programs_for_tx_batch.slot >= entry.effective_slot; + let entry_to_return = if entry_is_effective { if !Self::matches_environment( entry, program_runtime_environments_for_execution, ) { + // We found an entry that would work, had its environment matched + // the one we're planning to use for this slot. + // + // At this point we know that whatever the "current version" of + // program is, it must have had a deployment slot equal to the + // program we're looking at in this iteration. We just have to find + // one with the correct environment and can skip entries for any + // other deployment slot while searching further. filter_by_deployment_slot = filter_by_deployment_slot .or(Some(entry.deployment_slot)); continue; diff --git a/program-runtime/src/serialization.rs b/program-runtime/src/serialization.rs index 36ad1f00..fbab76fd 100644 --- a/program-runtime/src/serialization.rs +++ b/program-runtime/src/serialization.rs @@ -262,7 +262,8 @@ pub fn serialize_parameters( .collect::>(); if is_loader_deprecated { - serialize_parameters_unaligned( + // Used by loader-v1 (bpf_loader_deprecated) + serialize_parameters_for_abiv0( accounts, instruction_context.get_instruction_data(), &program_id, @@ -270,7 +271,8 @@ pub fn serialize_parameters( account_data_direct_mapping, ) } else { - serialize_parameters_aligned( + // Used by loader-v2 (bpf_loader) and loader-v3 (bpf_loader_upgradeable) + serialize_parameters_for_abiv1( accounts, instruction_context.get_instruction_data(), &program_id, @@ -291,7 +293,8 @@ pub fn deserialize_parameters( instruction_context.get_program_owner()? == bpf_loader_deprecated::id(); let account_lengths = accounts_metadata.iter().map(|a| a.original_data_len); if is_loader_deprecated { - deserialize_parameters_unaligned( + // Used by loader-v1 (bpf_loader_deprecated) + deserialize_parameters_for_abiv0( instruction_context, stricter_abi_and_runtime_constraints, account_data_direct_mapping, @@ -299,7 +302,8 @@ pub fn deserialize_parameters( account_lengths, ) } else { - deserialize_parameters_aligned( + // Used by loader-v2 (bpf_loader) and loader-v3 (bpf_loader_upgradeable) + deserialize_parameters_for_abiv1( instruction_context, stricter_abi_and_runtime_constraints, account_data_direct_mapping, @@ -309,7 +313,7 @@ pub fn deserialize_parameters( } } -fn serialize_parameters_unaligned( +fn serialize_parameters_for_abiv0( accounts: Vec, instruction_data: &[u8], program_id: &Pubkey, @@ -401,7 +405,7 @@ fn serialize_parameters_unaligned( )) } -fn deserialize_parameters_unaligned>( +fn deserialize_parameters_for_abiv0>( instruction_context: &InstructionContext, stricter_abi_and_runtime_constraints: bool, account_data_direct_mapping: bool, @@ -463,7 +467,7 @@ fn deserialize_parameters_unaligned>( Ok(()) } -fn serialize_parameters_aligned( +fn serialize_parameters_for_abiv1( accounts: Vec, instruction_data: &[u8], program_id: &Pubkey, @@ -564,7 +568,7 @@ fn serialize_parameters_aligned( )) } -fn deserialize_parameters_aligned>( +fn deserialize_parameters_for_abiv1>( instruction_context: &InstructionContext, stricter_abi_and_runtime_constraints: bool, account_data_direct_mapping: bool, @@ -667,8 +671,8 @@ mod tests { solana_sdk_ids::bpf_loader, solana_system_interface::MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION, solana_transaction_context::{ - MAX_ACCOUNTS_PER_TRANSACTION, TransactionContext, - instruction_accounts::InstructionAccount, + MAX_ACCOUNTS_PER_TRANSACTION, instruction_accounts::InstructionAccount, + transaction::TransactionContext, }, std::{ borrow::Cow, @@ -776,18 +780,19 @@ mod tests { let dedup_map = vec![u16::MAX; MAX_ACCOUNTS_PER_TRANSACTION]; invoke_context .transaction_context - .configure_next_instruction( + .configure_instruction_at_index( + 0, 0, instruction_accounts, dedup_map, Cow::Owned(instruction_data.clone()), - None, + Some(0), ) .unwrap(); } else { invoke_context .transaction_context - .configure_next_instruction_for_tests( + .configure_top_level_instruction_for_tests( 0, instruction_accounts, instruction_data.clone(), @@ -947,7 +952,7 @@ mod tests { with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts); invoke_context .transaction_context - .configure_next_instruction_for_tests( + .configure_top_level_instruction_for_tests( 0, instruction_accounts.clone(), instruction_data.clone(), @@ -959,7 +964,7 @@ mod tests { .get_current_instruction_context() .unwrap(); - // check serialize_parameters_aligned + // check serialize_parameters_for_abiv1 let (mut serialized, regions, accounts_metadata, _instruction_data_offset) = serialize_parameters( &instruction_context, @@ -1043,10 +1048,10 @@ mod tests { assert_eq!(&*account, original_account); } - // check serialize_parameters_unaligned + // check serialize_parameters_for_abiv0 invoke_context .transaction_context - .configure_next_instruction_for_tests( + .configure_top_level_instruction_for_tests( 7, instruction_accounts, instruction_data.clone(), @@ -1068,7 +1073,7 @@ mod tests { let mut serialized_regions = concat_regions(®ions); let (de_program_id, de_accounts, de_instruction_data) = unsafe { - deserialize_unaligned( + deserialize_for_abiv0( if !stricter_abi_and_runtime_constraints { serialized.as_slice_mut() } else { @@ -1210,7 +1215,7 @@ mod tests { with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts); invoke_context .transaction_context - .configure_next_instruction_for_tests(0, instruction_accounts.clone(), vec![]) + .configure_top_level_instruction_for_tests(0, instruction_accounts.clone(), vec![]) .unwrap(); invoke_context.push().unwrap(); let instruction_context = invoke_context @@ -1218,7 +1223,7 @@ mod tests { .get_current_instruction_context() .unwrap(); - // check serialize_parameters_aligned + // check serialize_parameters_for_abiv1 let (_serialized, regions, _accounts_metadata, _instruction_data_offset) = serialize_parameters( &instruction_context, @@ -1240,10 +1245,10 @@ mod tests { } } - // check serialize_parameters_unaligned + // check serialize_parameters_for_abiv0 invoke_context .transaction_context - .configure_next_instruction_for_tests(7, instruction_accounts, vec![]) + .configure_top_level_instruction_for_tests(7, instruction_accounts, vec![]) .unwrap(); invoke_context.push().unwrap(); let instruction_context = invoke_context @@ -1261,7 +1266,7 @@ mod tests { let mut serialized_regions = concat_regions(®ions); let (_de_program_id, de_accounts, _de_instruction_data) = unsafe { - deserialize_unaligned(serialized_regions.as_slice_mut().first_mut().unwrap() as *mut u8) + deserialize_for_abiv0(serialized_regions.as_slice_mut().first_mut().unwrap() as *mut u8) }; for account_info in de_accounts { #[allow(deprecated)] @@ -1273,7 +1278,7 @@ mod tests { // the old bpf_loader in-program deserializer bpf_loader::id() #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn deserialize_unaligned<'a>( + unsafe fn deserialize_for_abiv0<'a>( input: *mut u8, ) -> (&'a Pubkey, Vec>, &'a [u8]) { // this boring boilerplate struct is needed until inline const... @@ -1451,7 +1456,7 @@ mod tests { let instruction_accounts = deduplicated_instruction_accounts(&transaction_accounts_indexes, |index| index > 0); transaction_context - .configure_next_instruction_for_tests(6, instruction_accounts, vec![]) + .configure_top_level_instruction_for_tests(6, instruction_accounts, vec![]) .unwrap(); transaction_context.push().unwrap(); let instruction_context = transaction_context @@ -1508,7 +1513,10 @@ mod tests { .store::(0, account_start_offsets[0]) .unwrap_err(); - // Writing to shared writable account makes it unique (CoW logic) + // Writing to shared writable account makes it unique (CoW logic.) + // It has been previously been made non-unique at the beginning of + // the test through a clone. + let _shared_account_ref = shared_account; assert!( transaction_context .accounts() diff --git a/program-runtime/src/vm.rs b/program-runtime/src/vm.rs index bc673cb0..8888bc80 100644 --- a/program-runtime/src/vm.rs +++ b/program-runtime/src/vm.rs @@ -22,7 +22,7 @@ use { solana_sdk_ids::bpf_loader_deprecated, solana_svm_log_collector::ic_logger_msg, solana_svm_measure::measure::Measure, - solana_transaction_context::{IndexOfAccount, TransactionContext}, + solana_transaction_context::{IndexOfAccount, transaction::TransactionContext}, std::{cell::RefCell, mem}, }; @@ -96,7 +96,7 @@ fn create_memory_mapping<'a, C: ContextObject>( MemoryRegion::new_writable_gapped( stack, ebpf::MM_STACK_START, - if !sbpf_version.manual_stack_frame_bump() && config.enable_stack_frame_gaps { + if sbpf_version.stack_frame_gaps() && config.enable_stack_frame_gaps { config.stack_frame_size as u64 } else { 0 @@ -178,6 +178,26 @@ pub fn execute<'a, 'b: 'a>( feature = "sbpf-debugger" ))] { let use_jit = false; + #[cfg(feature = "sbpf-debugger")] + let (debug_port, debug_metadata) = ( + invoke_context.debug_port, + format!( + "program_id={};cpi_level={};caller={}", + program_id, + instruction_context.get_stack_height().saturating_sub(1), + invoke_context + .get_stack_height() + .checked_sub(2) + .and_then(|nesting_level| { + transaction_context + .get_instruction_context_at_nesting_level(nesting_level) + .ok() + }) + .and_then(|ctx| ctx.get_program_key().ok()) + .map(|key| key.to_string()) + .unwrap_or_else(|| "none".into()) + ), + ); } else { let use_jit = executable.get_compiled_program().is_some(); } @@ -229,6 +249,11 @@ pub fn execute<'a, 'b: 'a>( }; create_vm_time.stop(); + #[cfg(feature = "sbpf-debugger")] + { + vm.debug_port = debug_port; + vm.debug_metadata = Some(debug_metadata); + } vm.context_object_pointer.execute_time = Some(Measure::start("execute")); vm.registers[1] = ebpf::MM_INPUT_START; diff --git a/programs/bpf_loader/benches/serialization.rs b/programs/bpf_loader/benches/serialization.rs index 92261608..f7b5f18e 100644 --- a/programs/bpf_loader/benches/serialization.rs +++ b/programs/bpf_loader/benches/serialization.rs @@ -5,7 +5,9 @@ use { solana_pubkey::Pubkey, solana_rent::Rent, solana_sdk_ids::{bpf_loader, bpf_loader_deprecated}, - solana_transaction_context::{TransactionContext, instruction_accounts::InstructionAccount}, + solana_transaction_context::{ + instruction_accounts::InstructionAccount, transaction::TransactionContext, + }, }; fn create_inputs(owner: Pubkey, num_instruction_accounts: usize) -> TransactionContext<'static> { @@ -100,7 +102,7 @@ fn create_inputs(owner: Pubkey, num_instruction_accounts: usize) -> TransactionC TransactionContext::new(transaction_accounts, Rent::default(), 1, 1, 1); let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; transaction_context - .configure_next_instruction_for_tests(0, instruction_accounts, instruction_data) + .configure_top_level_instruction_for_tests(0, instruction_accounts, instruction_data) .unwrap(); transaction_context.push().unwrap(); transaction_context diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 301164e6..c0bb90a9 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1149,15 +1149,13 @@ fn common_close_account( #[cfg_attr(feature = "svm-internal", qualifiers(pub))] mod test_utils { + #[cfg(all(feature = "svm-internal", feature = "metrics"))] + use solana_program_runtime::loaded_programs::LoadProgramMetrics; #[cfg(feature = "svm-internal")] use { - super::*, - agave_syscalls::create_program_runtime_environment_v1, - solana_account::ReadableAccount, - solana_loader_v4_interface::state::LoaderV4State, - solana_program_runtime::{ - deploy::load_program_from_bytes, loaded_programs::LoadProgramMetrics, - }, + super::*, agave_syscalls::create_program_runtime_environment_v1, + solana_account::ReadableAccount, solana_loader_v4_interface::state::LoaderV4State, + solana_program_runtime::loaded_programs::DELAY_VISIBILITY_SLOT_OFFSET, solana_sdk_ids::loader_v4, }; @@ -1172,7 +1170,6 @@ mod test_utils { #[cfg(feature = "svm-internal")] #[cfg_attr(feature = "svm-internal", qualifiers(pub))] fn load_all_invoked_programs(invoke_context: &mut InvokeContext) { - let mut load_program_metrics = LoadProgramMetrics::default(); let program_runtime_environment = create_program_runtime_environment_v1( invoke_context.get_feature_set(), invoke_context.get_compute_budget(), @@ -1200,19 +1197,24 @@ mod test_utils { .get_key_of_account_at_index(index) .expect("Failed to get account key"); - if let Ok(loaded_program) = load_program_from_bytes( - None, - &mut load_program_metrics, - account - .data() - .get(programdata_data_offset.min(account.data().len())..) - .unwrap(), + let programdata = account + .data() + .get(programdata_data_offset.min(account.data().len())..) + .unwrap(); + let program_runtime_environment = program_runtime_environment.clone(); + let effective_slot = DELAY_VISIBILITY_SLOT_OFFSET; + let loaded_program = ProgramCacheEntry::new( owner, - account.data().len(), + program_runtime_environment, 0, - program_runtime_environment.clone(), - false, - ) { + effective_slot, + programdata, + account.data().len(), + #[cfg(feature = "metrics")] + &mut LoadProgramMetrics::default(), + ) + .map_err(|_| InstructionError::InvalidAccountData); + if let Ok(loaded_program) = loaded_program { invoke_context .program_cache_for_tx_batch .store_modified_entry(*pubkey, Arc::new(loaded_program)); diff --git a/programs/sbf/benches/bpf_loader.rs b/programs/sbf/benches/bpf_loader.rs index 0ac789b9..2fcf8331 100644 --- a/programs/sbf/benches/bpf_loader.rs +++ b/programs/sbf/benches/bpf_loader.rs @@ -64,11 +64,12 @@ macro_rules! with_mock_invoke_context { solana_program_runtime::with_mock_invoke_context!( $invoke_context, transaction_context, + 1, transaction_accounts ); $invoke_context .transaction_context - .configure_next_instruction_for_tests(1, instruction_accounts, vec![]) + .configure_top_level_instruction_for_tests(1, instruction_accounts, vec![]) .unwrap(); $invoke_context.push().unwrap(); }; diff --git a/programs/sbf/rust/deprecated_loader/src/lib.rs b/programs/sbf/rust/deprecated_loader/src/lib.rs index 0c78c2e1..e6d8b6d3 100644 --- a/programs/sbf/rust/deprecated_loader/src/lib.rs +++ b/programs/sbf/rust/deprecated_loader/src/lib.rs @@ -167,7 +167,7 @@ fn process_instruction( ) .unwrap(); - // deserialize_parameters_unaligned predates realloc support, and + // deserialize_parameters_for_abiv0 predates realloc support, and // hardcodes the account data length to the original length. if !solana_program::bpf_loader_deprecated::check_id(realloc_program_owner) && stricter_abi_and_runtime_constraints == 0 diff --git a/programs/sbf/rust/invoke/src/lib.rs b/programs/sbf/rust/invoke/src/lib.rs index 63e580da..a472f461 100644 --- a/programs/sbf/rust/invoke/src/lib.rs +++ b/programs/sbf/rust/invoke/src/lib.rs @@ -1088,7 +1088,7 @@ fn process_instruction<'a>( ) .unwrap(); - // deserialize_parameters_unaligned predates realloc support, and + // deserialize_parameters_for_abiv0 predates realloc support, and // hardcodes the account data length to the original length. if !bpf_loader_deprecated::check_id(realloc_program_owner) && stricter_abi_and_runtime_constraints == 0 diff --git a/programs/system/benches/system.rs b/programs/system/benches/system.rs index 15fa00d8..3458ec3d 100644 --- a/programs/system/benches/system.rs +++ b/programs/system/benches/system.rs @@ -1,6 +1,6 @@ #[allow(deprecated)] use { - criterion::{criterion_group, criterion_main, Criterion}, + criterion::{Criterion, criterion_group, criterion_main}, solana_account::{self as account, AccountSharedData, WritableAccount}, solana_hash::Hash, solana_instruction::AccountMeta, @@ -16,7 +16,7 @@ use { sysvar::{recent_blockhashes, rent}, }, solana_system_interface::instruction::SystemInstruction, - solana_sysvar::recent_blockhashes::{IterItem, RecentBlockhashes, MAX_ENTRIES}, + solana_sysvar::recent_blockhashes::{IterItem, MAX_ENTRIES, RecentBlockhashes}, }; const SEED: &str = "bench test"; diff --git a/programs/system/src/lib.rs b/programs/system/src/lib.rs index a8d1a821..2949911b 100644 --- a/programs/system/src/lib.rs +++ b/programs/system/src/lib.rs @@ -5,6 +5,6 @@ pub mod system_processor; use solana_sdk_ids::system_program; pub use { - solana_nonce_account::{get_system_account_kind, SystemAccountKind}, + solana_nonce_account::{SystemAccountKind, get_system_account_kind}, system_program::id, }; diff --git a/programs/system/src/system_instruction.rs b/programs/system/src/system_instruction.rs index 41d7f0a6..19e9857f 100644 --- a/programs/system/src/system_instruction.rs +++ b/programs/system/src/system_instruction.rs @@ -11,8 +11,8 @@ use { solana_system_interface::error::SystemError, solana_sysvar::rent::Rent, solana_transaction_context::{ - instruction::InstructionContext, instruction_accounts::BorrowedInstructionAccount, - IndexOfAccount, + IndexOfAccount, instruction::InstructionContext, + instruction_accounts::BorrowedInstructionAccount, }, std::collections::HashSet, }; @@ -265,7 +265,7 @@ mod test { ($invoke_context:expr, $instruction_context:ident, $instruction_accounts:ident) => { $invoke_context .transaction_context - .configure_next_instruction_for_tests(2, $instruction_accounts, vec![]) + .configure_top_level_instruction_for_tests(2, $instruction_accounts, vec![]) .unwrap(); $invoke_context.push().unwrap(); let transaction_context = &$invoke_context.transaction_context; @@ -277,6 +277,7 @@ mod test { macro_rules! prepare_mockup { ($invoke_context:ident, $instruction_accounts:ident, $rent:ident, $transaction_context:ident) => { + #[allow(deprecated)] let $rent = Rent { lamports_per_byte_year: 42, ..Rent::default() diff --git a/programs/system/src/system_processor.rs b/programs/system/src/system_processor.rs index 34b31137..5b3490b0 100644 --- a/programs/system/src/system_processor.rs +++ b/programs/system/src/system_processor.rs @@ -15,11 +15,11 @@ use { solana_sdk_ids::system_program, solana_svm_log_collector::ic_msg, solana_system_interface::{ - error::SystemError, instruction::SystemInstruction, MAX_PERMITTED_DATA_LENGTH, + MAX_PERMITTED_DATA_LENGTH, error::SystemError, instruction::SystemInstruction, }, solana_transaction_context::{ - instruction::InstructionContext, instruction_accounts::BorrowedInstructionAccount, - IndexOfAccount, + IndexOfAccount, instruction::InstructionContext, + instruction_accounts::BorrowedInstructionAccount, }, std::collections::HashSet, }; @@ -188,7 +188,7 @@ fn create_account( fn create_account_allow_prefund( to_account_index: IndexOfAccount, to_address: &Address, - payer_and_lamports: Option<(IndexOfAccount, u64)>, + from_and_lamports: Option<(IndexOfAccount, u64)>, space: u64, owner: &Pubkey, signers: &HashSet, @@ -199,7 +199,7 @@ fn create_account_allow_prefund( let mut to = instruction_context.try_borrow_instruction_account(to_account_index)?; allocate_and_assign(&mut to, to_address, space, owner, signers, invoke_context)?; } - if let Some((from_account_index, lamports)) = payer_and_lamports { + if let Some((from_account_index, lamports)) = from_and_lamports { if lamports > 0 { transfer( from_account_index, @@ -538,7 +538,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| { return Err(InstructionError::InvalidInstructionData); } - let payer_and_lamports = if lamports > 0 { + let from_and_lamports = if lamports > 0 { instruction_context.check_number_of_instruction_accounts(2)?; Some((1, lamports)) } else { @@ -553,7 +553,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| create_account_allow_prefund( 0, &to_address, - payer_and_lamports, + from_and_lamports, space, &owner, &signers, @@ -569,7 +569,7 @@ mod tests { use { super::*, bincode::serialize, - solana_nonce_account::{get_system_account_kind, SystemAccountKind}, + solana_nonce_account::{SystemAccountKind, get_system_account_kind}, solana_program_runtime::{ invoke_context::mock_process_instruction, with_mock_invoke_context, }, @@ -578,12 +578,12 @@ mod tests { #[allow(deprecated)] use { solana_account::{ - self as account, create_account_shared_data_with_fields, to_account, Account, - AccountSharedData, ReadableAccount, DUMMY_INHERITABLE_ACCOUNT_FIELDS, + self as account, Account, AccountSharedData, DUMMY_INHERITABLE_ACCOUNT_FIELDS, + ReadableAccount, create_account_shared_data_with_fields, to_account, }, solana_fee_calculator::FeeCalculator, solana_hash::Hash, - solana_instruction::{error::InstructionError, AccountMeta, Instruction}, + solana_instruction::{AccountMeta, Instruction, error::InstructionError}, solana_nonce::{ self as nonce, state::{Data as NonceData, DurableNonce, State as NonceState}, @@ -594,7 +594,7 @@ mod tests { solana_system_interface::{instruction as system_instruction, program as system_program}, solana_sysvar::{ self as sysvar, - recent_blockhashes::{IntoIterSorted, IterItem, RecentBlockhashes, MAX_ENTRIES}, + recent_blockhashes::{IntoIterSorted, IterItem, MAX_ENTRIES, RecentBlockhashes}, rent::Rent, }, }; diff --git a/rustfmt.toml b/rustfmt.toml index 8651681b..95a43b75 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ imports_granularity = "One" format_strings = true group_imports = "One" +style_edition = "2024" diff --git a/svm-test-harness/fixture/src/feature_set.rs b/svm-test-harness/fixture/src/feature_set.rs index 1e873c47..fca4d6c3 100644 --- a/svm-test-harness/fixture/src/feature_set.rs +++ b/svm-test-harness/fixture/src/feature_set.rs @@ -4,7 +4,7 @@ use { crate::proto::FeatureSet as ProtoFeatureSet, - agave_feature_set::{FeatureSet, FEATURE_NAMES}, + agave_feature_set::{FEATURE_NAMES, FeatureSet}, solana_pubkey::Pubkey, std::{collections::HashMap, sync::LazyLock}, }; diff --git a/svm-test-harness/instr/Cargo.toml b/svm-test-harness/instr/Cargo.toml index 8122a6c9..240337ae 100644 --- a/svm-test-harness/instr/Cargo.toml +++ b/svm-test-harness/instr/Cargo.toml @@ -13,6 +13,7 @@ publish = false [features] agave-unstable-api = [] dummy-for-ci-check = ["fuzz"] +metrics = ["solana-program-runtime/metrics", "solana-svm/metrics"] fuzz = [ "dep:agave-feature-set", "dep:agave-precompiles", @@ -36,6 +37,7 @@ solana-epoch-schedule = { workspace = true, features = ["sysvar"] } solana-instruction = { workspace = true } solana-instruction-error = { workspace = true, features = ["serde"] } solana-last-restart-slot = { workspace = true, features = ["sysvar"] } +solana-loader-v4-interface = { workspace = true } solana-message = { workspace = true } solana-precompile-error = { workspace = true } solana-program-runtime = { workspace = true } diff --git a/svm-test-harness/instr/src/harness.rs b/svm-test-harness/instr/src/harness.rs index 403a140c..d5717dfb 100644 --- a/svm-test-harness/instr/src/harness.rs +++ b/svm-test-harness/instr/src/harness.rs @@ -18,7 +18,7 @@ use { solana_svm_log_collector::LogCollector, solana_svm_timings::ExecuteTimings, solana_svm_transaction::{instruction::SVMInstruction, svm_message::SVMStaticMessage}, - solana_transaction_context::TransactionContext, + solana_transaction_context::transaction::TransactionContext, std::{collections::HashSet, rc::Rc, sync::Arc}, }; diff --git a/svm-test-harness/instr/src/keyed_account.rs b/svm-test-harness/instr/src/keyed_account.rs index feaaa5a3..6b0dabc5 100644 --- a/svm-test-harness/instr/src/keyed_account.rs +++ b/svm-test-harness/instr/src/keyed_account.rs @@ -1,7 +1,11 @@ //! Keyed account helpers. use { - solana_account::Account, solana_builtins::BUILTINS, solana_pubkey::Pubkey, solana_rent::Rent, + solana_account::Account, + solana_builtins::BUILTINS, + solana_loader_v4_interface::state::{LoaderV4State, LoaderV4Status}, + solana_pubkey::Pubkey, + solana_rent::Rent, }; fn create_keyed_account_for_builtin_program(program_id: &Pubkey, name: &str) -> (Pubkey, Account) { @@ -20,3 +24,41 @@ fn create_keyed_account_for_builtin_program(program_id: &Pubkey, name: &str) -> pub fn keyed_account_for_system_program() -> (Pubkey, Account) { create_keyed_account_for_builtin_program(&BUILTINS[0].program_id, BUILTINS[0].name) } + +pub fn keyed_account_for_compute_budget_program() -> (Pubkey, Account) { + create_keyed_account_for_builtin_program(&BUILTINS[5].program_id, BUILTINS[5].name) +} + +pub fn keyed_account_for_loader_v4_program() -> (Pubkey, Account) { + create_keyed_account_for_builtin_program(&BUILTINS[7].program_id, BUILTINS[7].name) +} + +pub fn create_program_account_loader_v4( + slot: u64, + authority_address_or_next_version: Pubkey, + status: LoaderV4Status, + elf: &[u8], +) -> Account { + let data = unsafe { + let elf_offset = LoaderV4State::program_data_offset(); + let data_len = elf_offset.saturating_add(elf.len()); + let mut data = vec![0u8; data_len]; + *std::mem::transmute::<&mut [u8; LoaderV4State::program_data_offset()], &mut LoaderV4State>( + (&mut data[0..elf_offset]).try_into().unwrap(), + ) = LoaderV4State { + slot, + authority_address_or_next_version, + status, + }; + data[elf_offset..].copy_from_slice(elf); + data + }; + let lamports = Rent::default().minimum_balance(data.len()); + Account { + lamports, + data, + owner: solana_sdk_ids::loader_v4::id(), + executable: true, + ..Default::default() + } +} diff --git a/svm-test-harness/instr/src/program_cache.rs b/svm-test-harness/instr/src/program_cache.rs index 915b6cd4..49d77305 100644 --- a/svm-test-harness/instr/src/program_cache.rs +++ b/svm-test-harness/instr/src/program_cache.rs @@ -107,7 +107,6 @@ pub fn fill_from_accounts( &acc.0, slot, &mut ExecuteTimings::default(), - false, ) { program_cache.replenish(acc.0, loaded_program); diff --git a/svm/Cargo.toml b/svm/Cargo.toml index 0e8ef0d8..b3b9904c 100644 --- a/svm/Cargo.toml +++ b/svm/Cargo.toml @@ -17,7 +17,9 @@ crate-type = ["lib"] name = "solana_svm" [features] +default = ["metrics"] agave-unstable-api = [] +dummy-for-ci-check = ["metrics"] dev-context-only-utils = [ "dep:qualifier_attr", "solana-program-runtime/dev-context-only-utils", @@ -27,6 +29,11 @@ frozen-abi = [ "dep:solana-frozen-abi-macro", "solana-program-runtime/frozen-abi", ] +metrics = [ + "solana-bpf-loader-program/metrics", + "solana-loader-v4-program/metrics", + "solana-program-runtime/metrics", +] shuttle-test = [ "solana-bpf-loader-program/shuttle-test", "solana-loader-v4-program/shuttle-test", @@ -44,12 +51,8 @@ serde = { workspace = true, features = ["rc"] } solana-account = { workspace = true } solana-clock = { workspace = true } solana-fee-structure = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } +solana-frozen-abi = { workspace = true, optional = true, features = ["frozen-abi"] } +solana-frozen-abi-macro = { workspace = true, optional = true, features = ["frozen-abi"] } solana-hash = { workspace = true } solana-instruction = { workspace = true, features = ["std"] } solana-instructions-sysvar = { workspace = true } @@ -61,7 +64,7 @@ solana-nonce = { workspace = true } solana-nonce-account = { workspace = true } solana-program-entrypoint = { workspace = true } solana-program-pack = { workspace = true } -solana-program-runtime = { workspace = true, features = ["metrics"] } +solana-program-runtime = { workspace = true } solana-pubkey = { workspace = true } solana-rent = { workspace = true } solana-sdk-ids = { workspace = true } diff --git a/svm/src/account_loader.rs b/svm/src/account_loader.rs index 5dbb9665..a76c6746 100644 --- a/svm/src/account_loader.rs +++ b/svm/src/account_loader.rs @@ -680,7 +680,7 @@ mod tests { solana_system_transaction::transfer, solana_transaction::{Transaction, sanitized::SanitizedTransaction}, solana_transaction_context::{ - TransactionContext, transaction_accounts::KeyedAccountSharedData, + transaction::TransactionContext, transaction_accounts::KeyedAccountSharedData, }, solana_transaction_error::{TransactionError, TransactionResult as Result}, std::{ @@ -1204,6 +1204,7 @@ mod tests { #[test] fn test_validate_fee_payer() { + #[allow(deprecated)] let rent = Rent { lamports_per_byte_year: 1, ..Rent::default() @@ -1280,6 +1281,7 @@ mod tests { #[test] fn test_validate_nonce_fee_payer_with_checked_arithmetic() { + #[allow(deprecated)] let rent = Rent { lamports_per_byte_year: 1, ..Rent::default() @@ -1886,7 +1888,7 @@ mod tests { let mut error_metrics = TransactionErrorMetrics::default(); let load_result = load_transaction( &mut account_loader, - &sanitized_tx.clone(), + &sanitized_tx, Ok(ValidatedTransactionDetails::default()), &mut error_metrics, &Rent::default(), @@ -2048,7 +2050,7 @@ mod tests { let load_result = load_transaction( &mut account_loader, &sanitized_transaction, - validation_result.clone(), + validation_result, &mut TransactionErrorMetrics::default(), &rent, ); @@ -2189,7 +2191,7 @@ mod tests { .iter() .map(|(k, v)| (*k, v.clone())) .collect(); - actual_inspected_accounts.sort_unstable_by(|a, b| a.0.cmp(&b.0)); + actual_inspected_accounts.sort_unstable_by_key(|a| a.0); let mut expected_inspected_accounts = vec![ // *not* key0, since it is loaded during fee payer validation @@ -2197,7 +2199,7 @@ mod tests { (address2, vec![(None, true)]), (address3, vec![(Some(account3), false)]), ]; - expected_inspected_accounts.sort_unstable_by(|a, b| a.0.cmp(&b.0)); + expected_inspected_accounts.sort_unstable_by_key(|a| a.0); assert_eq!(actual_inspected_accounts, expected_inspected_accounts,); } diff --git a/svm/src/message_processor.rs b/svm/src/message_processor.rs index df9a76de..3d0be64e 100644 --- a/svm/src/message_processor.rs +++ b/svm/src/message_processor.rs @@ -114,7 +114,7 @@ mod tests { solana_secp256r1_program::{new_secp256r1_instruction_with_signature, sign_message}, solana_svm_callback::InvokeContextCallback, solana_svm_feature_set::SVMFeatureSet, - solana_transaction_context::TransactionContext, + solana_transaction_context::transaction::TransactionContext, std::{collections::HashSet, sync::Arc}, }; @@ -191,7 +191,8 @@ mod tests { create_loadable_account_for_test("mock_system_program"), ), ]; - let mut transaction_context = TransactionContext::new(accounts, Rent::default(), 1, 3, 2); + let mut transaction_context = + TransactionContext::new(accounts.clone(), Rent::default(), 1, 3, 1); let program_indices = vec![2]; let mut program_cache_for_tx_batch = ProgramCacheForTxBatch::default(); program_cache_for_tx_batch.replenish( @@ -293,6 +294,8 @@ mod tests { &program_runtime_environments, &sysvar_cache, ); + let mut transaction_context = + TransactionContext::new(accounts.clone(), Rent::default(), 1, 3, 1); let mut invoke_context = InvokeContext::new( &mut transaction_context, &mut program_cache_for_tx_batch, @@ -340,6 +343,7 @@ mod tests { &program_runtime_environments, &sysvar_cache, ); + let mut transaction_context = TransactionContext::new(accounts, Rent::default(), 1, 3, 1); let mut invoke_context = InvokeContext::new( &mut transaction_context, &mut program_cache_for_tx_batch, @@ -433,7 +437,8 @@ mod tests { create_loadable_account_for_test("mock_system_program"), ), ]; - let mut transaction_context = TransactionContext::new(accounts, Rent::default(), 1, 3, 2); + let mut transaction_context = + TransactionContext::new(accounts.clone(), Rent::default(), 1, 3, 1); let program_indices = vec![2]; let mut program_cache_for_tx_batch = ProgramCacheForTxBatch::default(); program_cache_for_tx_batch.replenish( @@ -518,6 +523,8 @@ mod tests { &program_runtime_environments, &sysvar_cache, ); + let mut transaction_context = + TransactionContext::new(accounts.clone(), Rent::default(), 1, 3, 1); let mut invoke_context = InvokeContext::new( &mut transaction_context, &mut program_cache_for_tx_batch, @@ -557,6 +564,7 @@ mod tests { &program_runtime_environments, &sysvar_cache, ); + let mut transaction_context = TransactionContext::new(accounts, Rent::default(), 1, 3, 1); let mut invoke_context = InvokeContext::new( &mut transaction_context, &mut program_cache_for_tx_batch, diff --git a/svm/src/program_loader.rs b/svm/src/program_loader.rs index cf9f1ec7..a79a6154 100644 --- a/svm/src/program_loader.rs +++ b/svm/src/program_loader.rs @@ -1,13 +1,13 @@ +#[cfg(feature = "metrics")] +use solana_program_runtime::loaded_programs::LoadProgramMetrics; use { solana_account::{AccountSharedData, ReadableAccount, state_traits::StateMut}, solana_clock::Slot, - solana_instruction::error::InstructionError, solana_loader_v3_interface::state::UpgradeableLoaderState, solana_loader_v4_interface::state::{LoaderV4State, LoaderV4Status}, solana_program_runtime::loaded_programs::{ - DELAY_VISIBILITY_SLOT_OFFSET, LoadProgramMetrics, ProgramCacheEntry, - ProgramCacheEntryOwner, ProgramCacheEntryType, ProgramRuntimeEnvironment, - ProgramRuntimeEnvironments, + DELAY_VISIBILITY_SLOT_OFFSET, ProgramCacheEntry, ProgramCacheEntryOwner, + ProgramCacheEntryType, ProgramRuntimeEnvironments, }, solana_pubkey::Pubkey, solana_sdk_ids::{bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, loader_v4}, @@ -26,41 +26,6 @@ pub(crate) enum ProgramAccountLoadResult { ProgramOfLoaderV4(AccountSharedData, Slot), } -pub(crate) fn load_program_from_bytes( - load_program_metrics: &mut LoadProgramMetrics, - programdata: &[u8], - loader_key: &Pubkey, - account_size: usize, - deployment_slot: Slot, - program_runtime_environment: ProgramRuntimeEnvironment, - reloading: bool, -) -> std::result::Result> { - if reloading { - // Safety: this is safe because the program is being reloaded in the cache. - unsafe { - ProgramCacheEntry::reload( - loader_key, - program_runtime_environment, - deployment_slot, - deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), - programdata, - account_size, - load_program_metrics, - ) - } - } else { - ProgramCacheEntry::new( - loader_key, - program_runtime_environment, - deployment_slot, - deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), - programdata, - account_size, - load_program_metrics, - ) - } -} - pub(crate) fn load_program_accounts( callbacks: &CB, pubkey: &Pubkey, @@ -126,12 +91,14 @@ pub fn load_program_with_pubkey( pubkey: &Pubkey, current_slot: Slot, execute_timings: &mut ExecuteTimings, - reload: bool, ) -> Option<(Arc, Slot)> { + #[cfg(feature = "metrics")] let mut load_program_metrics = LoadProgramMetrics { program_id: pubkey.to_string(), ..LoadProgramMetrics::default() }; + #[cfg(not(feature = "metrics"))] + let _ = execute_timings; let (load_result, last_modification_slot) = load_program_accounts(callbacks, pubkey)?; let loaded_program = match load_result { @@ -139,25 +106,27 @@ pub fn load_program_with_pubkey( ProgramCacheEntry::new_tombstone(current_slot, owner, ProgramCacheEntryType::Closed), ), - ProgramAccountLoadResult::ProgramOfLoaderV1(program_account) => load_program_from_bytes( - &mut load_program_metrics, - program_account.data(), + ProgramAccountLoadResult::ProgramOfLoaderV1(program_account) => ProgramCacheEntry::new( program_account.owner(), - program_account.data().len(), - 0, environments.program_runtime_v1.clone(), - reload, + 0, + DELAY_VISIBILITY_SLOT_OFFSET, + program_account.data(), + program_account.data().len(), + #[cfg(feature = "metrics")] + &mut load_program_metrics, ) .map_err(|_| (0, ProgramCacheEntryOwner::LoaderV1)), - ProgramAccountLoadResult::ProgramOfLoaderV2(program_account) => load_program_from_bytes( - &mut load_program_metrics, - program_account.data(), + ProgramAccountLoadResult::ProgramOfLoaderV2(program_account) => ProgramCacheEntry::new( program_account.owner(), - program_account.data().len(), - 0, environments.program_runtime_v1.clone(), - reload, + 0, + DELAY_VISIBILITY_SLOT_OFFSET, + program_account.data(), + program_account.data().len(), + #[cfg(feature = "metrics")] + &mut load_program_metrics, ) .map_err(|_| (0, ProgramCacheEntryOwner::LoaderV2)), @@ -168,20 +137,22 @@ pub fn load_program_with_pubkey( ) => programdata_account .data() .get(UpgradeableLoaderState::size_of_programdata_metadata()..) - .ok_or(Box::new(InstructionError::InvalidAccountData).into()) + .ok_or(()) .and_then(|programdata| { - load_program_from_bytes( - &mut load_program_metrics, - programdata, + ProgramCacheEntry::new( program_account.owner(), + environments.program_runtime_v1.clone(), + deployment_slot, + deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), + programdata, program_account .data() .len() .saturating_add(programdata_account.data().len()), - deployment_slot, - environments.program_runtime_v1.clone(), - reload, + #[cfg(feature = "metrics")] + &mut load_program_metrics, ) + .map_err(|_| ()) }) .map_err(|_| (deployment_slot, ProgramCacheEntryOwner::LoaderV3)), @@ -189,17 +160,19 @@ pub fn load_program_with_pubkey( program_account .data() .get(LoaderV4State::program_data_offset()..) - .ok_or(Box::new(InstructionError::InvalidAccountData).into()) + .ok_or(()) .and_then(|elf_bytes| { - load_program_from_bytes( - &mut load_program_metrics, - elf_bytes, + ProgramCacheEntry::new( &loader_v4::id(), - program_account.data().len(), - deployment_slot, environments.program_runtime_v1.clone(), - reload, + deployment_slot, + deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), + elf_bytes, + program_account.data().len(), + #[cfg(feature = "metrics")] + &mut load_program_metrics, ) + .map_err(|_| ()) }) .map_err(|_| (deployment_slot, ProgramCacheEntryOwner::LoaderV4)) } @@ -213,6 +186,7 @@ pub fn load_program_with_pubkey( ) }); + #[cfg(feature = "metrics")] load_program_metrics.submit_datapoint(&mut execute_timings.details); loaded_program.update_access_slot(current_slot); Some((Arc::new(loaded_program), last_modification_slot)) @@ -262,7 +236,9 @@ mod tests { crate::transaction_processor::TransactionBatchProcessor, solana_account::WritableAccount, solana_program_runtime::{ - loaded_programs::{BlockRelation, ForkGraph, ProgramRuntimeEnvironments}, + loaded_programs::{ + BlockRelation, ForkGraph, ProgramRuntimeEnvironment, ProgramRuntimeEnvironments, + }, solana_sbpf::program::BuiltinProgram, }, solana_sdk_ids::{bpf_loader, bpf_loader_upgradeable}, @@ -481,32 +457,22 @@ mod tests { fn test_load_program_from_bytes() { let buffer = load_test_program(); + #[cfg(feature = "metrics")] let mut metrics = LoadProgramMetrics::default(); let loader = bpf_loader_upgradeable::id(); let size = buffer.len(); - let slot = 2; + let slot: Slot = 2; let environment = ProgramRuntimeEnvironment::new(BuiltinProgram::new_mock()); - let result = load_program_from_bytes( - &mut metrics, - &buffer, + let result = ProgramCacheEntry::new( &loader, - size, - slot, environment.clone(), - false, - ); - - assert!(result.is_ok()); - - let result = load_program_from_bytes( - &mut metrics, + slot, + slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), &buffer, - &loader, size, - slot, - environment, - true, + #[cfg(feature = "metrics")] + &mut metrics, ); assert!(result.is_ok()); @@ -524,7 +490,6 @@ mod tests { &key, 500, &mut ExecuteTimings::default(), - false, ); assert!(result.is_none()); } @@ -547,7 +512,6 @@ mod tests { &key, 0, // Slot 0 &mut ExecuteTimings::default(), - false, ); let loaded_program = ProgramCacheEntry::new_tombstone( @@ -581,7 +545,6 @@ mod tests { &key, 200, &mut ExecuteTimings::default(), - false, ); let loaded_program = ProgramCacheEntry::new_tombstone( 0, @@ -608,18 +571,18 @@ mod tests { &key, 200, &mut ExecuteTimings::default(), - false, ); let environments = ProgramRuntimeEnvironments::default(); - let expected = load_program_from_bytes( - &mut LoadProgramMetrics::default(), - account_data.data(), + let expected = ProgramCacheEntry::new( account_data.owner(), - account_data.data().len(), - 0, environments.program_runtime_v1.clone(), - false, + 0, + DELAY_VISIBILITY_SLOT_OFFSET, + account_data.data(), + account_data.data().len(), + #[cfg(feature = "metrics")] + &mut LoadProgramMetrics::default(), ); assert_eq!(result.unwrap(), (Arc::new(expected.unwrap()), 0)); @@ -662,7 +625,6 @@ mod tests { &key1, 0, &mut ExecuteTimings::default(), - false, ); let loaded_program = ProgramCacheEntry::new_tombstone( 0, @@ -699,7 +661,6 @@ mod tests { &key1, 200, &mut ExecuteTimings::default(), - false, ); let data = account_data.data(); @@ -707,14 +668,15 @@ mod tests { .set_data(data[UpgradeableLoaderState::size_of_programdata_metadata()..].to_vec()); let environments = ProgramRuntimeEnvironments::default(); - let expected = load_program_from_bytes( - &mut LoadProgramMetrics::default(), - account_data.data(), + let expected = ProgramCacheEntry::new( account_data.owner(), - account_data.data().len(), - 0, environments.program_runtime_v1.clone(), - false, + 0, + DELAY_VISIBILITY_SLOT_OFFSET, + account_data.data(), + account_data.data().len(), + #[cfg(feature = "metrics")] + &mut LoadProgramMetrics::default(), ); assert_eq!(result.unwrap(), (Arc::new(expected.unwrap()), 0)); } @@ -749,7 +711,6 @@ mod tests { &key, 0, &mut ExecuteTimings::default(), - false, ); let loaded_program = ProgramCacheEntry::new_tombstone( 0, @@ -782,7 +743,6 @@ mod tests { &key, 200, &mut ExecuteTimings::default(), - false, ); let data = account_data.data()[LoaderV4State::program_data_offset()..].to_vec(); @@ -793,14 +753,15 @@ mod tests { .insert(key, (account_data.clone(), 0)); let environments = ProgramRuntimeEnvironments::default(); - let expected = load_program_from_bytes( - &mut LoadProgramMetrics::default(), - account_data.data(), + let expected = ProgramCacheEntry::new( account_data.owner(), - account_data.data().len(), - 0, environments.program_runtime_v1.clone(), - false, + 0, + DELAY_VISIBILITY_SLOT_OFFSET, + account_data.data(), + account_data.data().len(), + #[cfg(feature = "metrics")] + &mut LoadProgramMetrics::default(), ); assert_eq!(result.unwrap(), (Arc::new(expected.unwrap()), 0)); } @@ -832,7 +793,6 @@ mod tests { &key, 200, &mut ExecuteTimings::default(), - false, ) .unwrap(); assert_ne!( diff --git a/svm/src/rent_calculator.rs b/svm/src/rent_calculator.rs index 859ec6d4..2afd6c92 100644 --- a/svm/src/rent_calculator.rs +++ b/svm/src/rent_calculator.rs @@ -6,7 +6,7 @@ use { solana_clock::Epoch, solana_pubkey::Pubkey, solana_rent::Rent, - solana_transaction_context::{IndexOfAccount, TransactionContext}, + solana_transaction_context::{IndexOfAccount, transaction::TransactionContext}, solana_transaction_error::{TransactionError, TransactionResult}, }; diff --git a/svm/src/rollback_accounts.rs b/svm/src/rollback_accounts.rs index 7377e128..bdb90088 100644 --- a/svm/src/rollback_accounts.rs +++ b/svm/src/rollback_accounts.rs @@ -253,7 +253,7 @@ mod tests { let rollback_accounts = RollbackAccounts::new( Some(nonce), fee_payer_address, - rent_epoch_updated_fee_payer_account.clone(), + rent_epoch_updated_fee_payer_account, u64::MAX, // ignored ); diff --git a/svm/src/transaction_account_state_info.rs b/svm/src/transaction_account_state_info.rs index 2c9c6072..65341f43 100644 --- a/svm/src/transaction_account_state_info.rs +++ b/svm/src/transaction_account_state_info.rs @@ -3,7 +3,7 @@ use { solana_account::ReadableAccount, solana_rent::Rent, solana_svm_transaction::svm_message::SVMMessage, - solana_transaction_context::{IndexOfAccount, TransactionContext}, + solana_transaction_context::{IndexOfAccount, transaction::TransactionContext}, solana_transaction_error::TransactionResult as Result, }; @@ -78,7 +78,7 @@ mod test { }, solana_rent::Rent, solana_signer::Signer, - solana_transaction_context::TransactionContext, + solana_transaction_context::transaction::TransactionContext, solana_transaction_error::TransactionError, std::collections::HashSet, }; diff --git a/svm/src/transaction_commit_result.rs b/svm/src/transaction_commit_result.rs index 9116f4b9..7fdc51a3 100644 --- a/svm/src/transaction_commit_result.rs +++ b/svm/src/transaction_commit_result.rs @@ -1,7 +1,8 @@ use { crate::transaction_execution_result::TransactionLoadedAccountsStats, solana_fee_structure::FeeDetails, solana_message::inner_instruction::InnerInstructionsList, - solana_transaction_context::TransactionReturnData, solana_transaction_error::TransactionResult, + solana_transaction_context::transaction::TransactionReturnData, + solana_transaction_error::TransactionResult, }; pub type TransactionCommitResult = TransactionResult; diff --git a/svm/src/transaction_execution_result.rs b/svm/src/transaction_execution_result.rs index 6a066b49..c625cace 100644 --- a/svm/src/transaction_execution_result.rs +++ b/svm/src/transaction_execution_result.rs @@ -3,7 +3,7 @@ use { solana_message::inner_instruction::InnerInstructionsList, solana_program_runtime::loaded_programs::ProgramCacheEntry, solana_pubkey::Pubkey, - solana_transaction_context::TransactionReturnData, + solana_transaction_context::transaction::TransactionReturnData, solana_transaction_error::TransactionResult, std::{collections::HashMap, sync::Arc}, }; diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index 567ab76f..229537b3 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -52,7 +52,7 @@ use { solana_svm_timings::{ExecuteTimingType, ExecuteTimings}, solana_svm_transaction::{svm_message::SVMMessage, svm_transaction::SVMTransaction}, solana_svm_type_overrides::sync::{Arc, RwLock, RwLockReadGuard, atomic::Ordering}, - solana_transaction_context::{ExecutionRecord, TransactionContext}, + solana_transaction_context::transaction::{ExecutionRecord, TransactionContext}, solana_transaction_error::{TransactionError, TransactionResult}, std::{ collections::{HashMap, HashSet}, @@ -877,7 +877,6 @@ impl TransactionBatchProcessor { &key, self.slot, execute_timings, - false, ) .expect("called load_program_with_pubkey() with nonexistent account"); (key, program, last_modification_slot) @@ -905,8 +904,11 @@ impl TransactionBatchProcessor { } else if missing_programs.is_empty() { break; } else { - // Sleep until the next finish_cooperative_loading_task() call. - // Once a task completes we'll wake up and try to load the + // Remember: there are multiple transaction processor threads running concurrently + // and those other threads may be loading this or other programs. + // + // So, sleep until some other thread submits a program with their + // `finish_cooperative_loading_task` call. We'll then wake up and try to load the // missing programs inside the tx batch again. let _new_cookie = task_waiter.wait(task_cookie); } @@ -1212,7 +1214,7 @@ mod tests { solana_svm_callback::{AccountState, InvokeContextCallback}, solana_system_interface::instruction as system_instruction, solana_transaction::{Transaction, sanitized::SanitizedTransaction}, - solana_transaction_context::TransactionContext, + solana_transaction_context::transaction::TransactionContext, solana_transaction_error::TransactionError, std::collections::HashMap, test_case::test_case, @@ -1353,28 +1355,104 @@ mod tests { #[test] fn test_inner_instructions_list_from_instruction_trace() { - let instruction_trace = [1, 2, 1, 1, 2, 3, 2]; let mut transaction_context = TransactionContext::new( vec![( Pubkey::new_unique(), AccountSharedData::new(1, 1, &bpf_loader::ID), )], Rent::default(), - 3, - instruction_trace.len(), - instruction_trace.len(), + 4, + 11, + 4, ); - for (index_in_trace, stack_height) in instruction_trace.into_iter().enumerate() { - while stack_height <= transaction_context.get_instruction_stack_height() { - transaction_context.pop().unwrap(); - } - if stack_height > transaction_context.get_instruction_stack_height() { - transaction_context - .configure_next_instruction_for_tests(0, vec![], vec![index_in_trace as u8]) - .unwrap(); - transaction_context.push().unwrap(); - } - } + + // To be uncommented when we reorder the instruction trace + // Four top level instructions + // for i in 0..4 { + // transaction_context + // .configure_instruction_at_index( + // i, + // 0, + // vec![], + // vec![u16::MAX; 256], + // Cow::Owned(vec![i as u8]), + // None, + // ) + // .unwrap(); + // } + + // Execute ix #0 + transaction_context + .configure_top_level_instruction_for_tests(0, vec![], vec![0]) + .unwrap(); + transaction_context.push().unwrap(); + // ix #0 does a CPI + transaction_context + .configure_next_cpi_for_tests(0, vec![], vec![0, 0]) + .unwrap(); + transaction_context.push().unwrap(); + // Returning from everything + transaction_context.pop().unwrap(); + transaction_context.pop().unwrap(); + // Execute ix #1 + transaction_context + .configure_top_level_instruction_for_tests(0, vec![], vec![1]) + .unwrap(); + transaction_context.push().unwrap(); + transaction_context.pop().unwrap(); + // Execute ix #2 + transaction_context + .configure_top_level_instruction_for_tests(0, vec![], vec![2]) + .unwrap(); + transaction_context.push().unwrap(); + // ix #2 does a CPI + transaction_context + .configure_next_cpi_for_tests(0, vec![], vec![2, 0]) + .unwrap(); + transaction_context.push().unwrap(); + // A nested CPI + transaction_context + .configure_next_cpi_for_tests(0, vec![], vec![2, 1]) + .unwrap(); + transaction_context.push().unwrap(); + // Return from nested CPI + transaction_context.pop().unwrap(); + // Return from CPI + transaction_context.pop().unwrap(); + // ix #2 does another CPI + transaction_context + .configure_next_cpi_for_tests(0, vec![], vec![2, 2]) + .unwrap(); + transaction_context.push().unwrap(); + // Return from everything related to ix #2 + transaction_context.pop().unwrap(); + transaction_context.pop().unwrap(); + // Execute ix #3 + transaction_context + .configure_top_level_instruction_for_tests(0, vec![], vec![3]) + .unwrap(); + transaction_context.push().unwrap(); + // ix #3 does a CPI + transaction_context + .configure_next_cpi_for_tests(0, vec![], vec![3, 0]) + .unwrap(); + transaction_context.push().unwrap(); + // ix #3 does a nested CPI + transaction_context + .configure_next_cpi_for_tests(0, vec![], vec![3, 1]) + .unwrap(); + transaction_context.push().unwrap(); + // ix #3 does a second nested CPI + transaction_context + .configure_next_cpi_for_tests(0, vec![], vec![3, 2]) + .unwrap(); + transaction_context.push().unwrap(); + // Return from everything related to ix #3 + transaction_context.pop().unwrap(); + transaction_context.pop().unwrap(); + transaction_context.pop().unwrap(); + transaction_context.pop().unwrap(); + let inner_instructions = TransactionBatchProcessor::::deconstruct_transaction( transaction_context, @@ -1387,23 +1465,37 @@ mod tests { inner_instructions, vec![ vec![InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![1], vec![]), + instruction: CompiledInstruction::new_from_raw_parts(0, vec![0, 0], vec![]), stack_height: 2, }], vec![], vec![ InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![4], vec![]), + instruction: CompiledInstruction::new_from_raw_parts(0, vec![2, 0], vec![]), stack_height: 2, }, InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![5], vec![]), + instruction: CompiledInstruction::new_from_raw_parts(0, vec![2, 1], vec![]), stack_height: 3, }, InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![6], vec![]), + instruction: CompiledInstruction::new_from_raw_parts(0, vec![2, 2], vec![]), + stack_height: 2, + }, + ], + vec![ + InnerInstruction { + instruction: CompiledInstruction::new_from_raw_parts(0, vec![3, 0], vec![]), stack_height: 2, }, + InnerInstruction { + instruction: CompiledInstruction::new_from_raw_parts(0, vec![3, 1], vec![]), + stack_height: 3, + }, + InnerInstruction { + instruction: CompiledInstruction::new_from_raw_parts(0, vec![3, 2], vec![]), + stack_height: 4, + }, ] ] ); @@ -2127,7 +2219,7 @@ mod tests { let fee_payer_address = message.fee_payer(); let fee_payer_account = AccountSharedData::new(1, 0, &Pubkey::default()); let mut mock_accounts = HashMap::new(); - mock_accounts.insert(*fee_payer_address, fee_payer_account.clone()); + mock_accounts.insert(*fee_payer_address, fee_payer_account); let mock_bank = MockBankCallback { account_shared_data: Arc::new(RwLock::new(mock_accounts)), ..Default::default() @@ -2171,7 +2263,7 @@ mod tests { let starting_balance = min_balance + transaction_fee - 1; let fee_payer_account = AccountSharedData::new(starting_balance, 0, &Pubkey::default()); let mut mock_accounts = HashMap::new(); - mock_accounts.insert(*fee_payer_address, fee_payer_account.clone()); + mock_accounts.insert(*fee_payer_address, fee_payer_account); let mock_bank = MockBankCallback { account_shared_data: Arc::new(RwLock::new(mock_accounts)), ..Default::default() @@ -2213,7 +2305,7 @@ mod tests { let fee_payer_address = message.fee_payer(); let fee_payer_account = AccountSharedData::new(1_000_000, 0, &Pubkey::new_unique()); let mut mock_accounts = HashMap::new(); - mock_accounts.insert(*fee_payer_address, fee_payer_account.clone()); + mock_accounts.insert(*fee_payer_address, fee_payer_account); let mock_bank = MockBankCallback { account_shared_data: Arc::new(RwLock::new(mock_accounts)), ..Default::default() @@ -2465,7 +2557,7 @@ mod tests { .unwrap(); let mut mock_accounts = HashMap::new(); - mock_accounts.insert(*fee_payer_address, fee_payer_account.clone()); + mock_accounts.insert(*fee_payer_address, fee_payer_account); let mock_bank = MockBankCallback { account_shared_data: Arc::new(RwLock::new(mock_accounts)), ..Default::default() diff --git a/svm/tests/integration_test.rs b/svm/tests/integration_test.rs index 78d959b4..7cbe144c 100644 --- a/svm/tests/integration_test.rs +++ b/svm/tests/integration_test.rs @@ -52,7 +52,7 @@ use { solana_system_transaction as system_transaction, solana_sysvar::rent::Rent, solana_transaction::{Transaction, sanitized::SanitizedTransaction}, - solana_transaction_context::TransactionReturnData, + solana_transaction_context::transaction::TransactionReturnData, solana_transaction_error::TransactionError, std::{collections::HashMap, num::NonZeroU32, slice, sync::atomic::Ordering}, test_case::test_case, @@ -1528,9 +1528,7 @@ fn simd83_nonce_reuse(fee_paying_nonce: bool) -> Vec { nonce::state::Data::new(fee_payer, initial_durable, LAMPORTS_PER_SIGNATURE); let mut initial_nonce_account = AccountSharedData::new_data( LAMPORTS_PER_SOL, - &nonce::versions::Versions::new(nonce::state::State::Initialized( - initial_nonce_data.clone(), - )), + &nonce::versions::Versions::new(nonce::state::State::Initialized(initial_nonce_data)), &system_program::id(), ) .unwrap(); @@ -1538,7 +1536,7 @@ fn simd83_nonce_reuse(fee_paying_nonce: bool) -> Vec { let initial_nonce_info = NonceInfo::new(nonce_pubkey, initial_nonce_account.clone()); let advanced_durable = DurableNonce::from_blockhash(&LAST_BLOCKHASH); - let mut advanced_nonce_info = initial_nonce_info.clone(); + let mut advanced_nonce_info = initial_nonce_info; advanced_nonce_info .try_advance_nonce(advanced_durable, LAMPORTS_PER_SIGNATURE) .unwrap(); @@ -1695,10 +1693,7 @@ fn simd83_nonce_reuse(fee_paying_nonce: bool) -> Vec { let mut test_entry = common_test_entry.clone(); let first_transaction = Transaction::new_signed_with_payer( - &[ - successful_noop_instruction.clone(), - advance_instruction.clone(), - ], + &[successful_noop_instruction.clone(), advance_instruction], Some(&fee_payer), &[&fee_payer_keypair], Hash::default(), @@ -1921,7 +1916,7 @@ fn simd83_nonce_reuse(fee_paying_nonce: bool) -> Vec { test_entry.push_transaction(first_transaction); test_entry.push_nonce_transaction_with_status( - second_transaction.clone(), + second_transaction, nonce_pubkey, ExecutionStatus::Discarded, ); @@ -1944,7 +1939,7 @@ fn simd83_nonce_reuse(fee_paying_nonce: bool) -> Vec { // * a successful blockhash transaction that changes the nonce authority // * a nonce transaction that uses the nonce with the new authority; this transaction succeeds if !fee_paying_nonce { - let mut test_entry = common_test_entry.clone(); + let mut test_entry = common_test_entry; let new_authority_keypair = Keypair::new(); let new_authority = new_authority_keypair.pubkey(); @@ -1963,7 +1958,7 @@ fn simd83_nonce_reuse(fee_paying_nonce: bool) -> Vec { let second_transaction = Transaction::new_signed_with_payer( &[ system_instruction::advance_nonce_account(&nonce_pubkey, &new_authority), - successful_noop_instruction.clone(), + successful_noop_instruction, ], Some(&fee_payer), &[&fee_payer_keypair, &new_authority_keypair], @@ -1971,7 +1966,7 @@ fn simd83_nonce_reuse(fee_paying_nonce: bool) -> Vec { ); test_entry.push_transaction(first_transaction); - test_entry.push_nonce_transaction(second_transaction.clone(), nonce_pubkey); + test_entry.push_nonce_transaction(second_transaction, nonce_pubkey); test_entry.decrease_expected_lamports(&fee_payer, LAMPORTS_PER_SIGNATURE * 2); @@ -2132,6 +2127,7 @@ fn simd83_fee_payer_deallocate() -> Vec { test_entry.add_initial_program(program_name); // rent minimum needs to be adjusted so fee payer can be deallocated + #[allow(deprecated)] let rent = Rent { lamports_per_byte_year: LAMPORTS_PER_SIGNATURE / solana_rent::ACCOUNT_STORAGE_OVERHEAD, exemption_threshold: 1.0, @@ -2227,9 +2223,7 @@ fn simd83_fee_payer_deallocate() -> Vec { nonce::state::Data::new(dealloc_fee_payer, initial_durable, LAMPORTS_PER_SIGNATURE); let mut initial_nonce_account = AccountSharedData::new_data( LAMPORTS_PER_SOL, - &nonce::versions::Versions::new(nonce::state::State::Initialized( - initial_nonce_data.clone(), - )), + &nonce::versions::Versions::new(nonce::state::State::Initialized(initial_nonce_data)), &system_program::id(), ) .unwrap(); @@ -2237,7 +2231,7 @@ fn simd83_fee_payer_deallocate() -> Vec { let initial_nonce_info = NonceInfo::new(nonce_pubkey, initial_nonce_account.clone()); let advanced_durable = DurableNonce::from_blockhash(&LAST_BLOCKHASH); - let mut advanced_nonce_info = initial_nonce_info.clone(); + let mut advanced_nonce_info = initial_nonce_info; advanced_nonce_info .try_advance_nonce(advanced_durable, LAMPORTS_PER_SIGNATURE) .unwrap(); @@ -2363,7 +2357,7 @@ fn simd83_account_reallocate() -> Vec { // * successful large realloc up // * transaction is aborted based on the new transaction data size post-realloc { - let mut test_entry = common_test_entry.clone(); + let mut test_entry = common_test_entry; let new_target_size = target_start_size + MAX_PERMITTED_DATA_INCREASE; @@ -2371,10 +2365,8 @@ fn simd83_account_reallocate() -> Vec { .create_transaction(program_id, &fee_payer_keypair, target, None); test_entry.push_transaction(realloc_transaction); - test_entry.push_transaction_with_status( - print_transaction.clone(), - ExecutionStatus::ProcessedFailed, - ); + test_entry + .push_transaction_with_status(print_transaction, ExecutionStatus::ProcessedFailed); test_entry.update_expected_account_data(target, &mk_target(new_target_size)); @@ -2979,7 +2971,7 @@ fn program_cache_stats() { test_entry.push_transaction_with_status( make_transaction(&[ - failing_transfer_instruction.clone(), + failing_transfer_instruction, succesful_noop_instruction.clone(), succesful_transfer_instruction.clone(), ]), @@ -2992,7 +2984,7 @@ fn program_cache_stats() { test_entry.push_transaction_with_status( make_transaction(&[ succesful_noop_instruction.clone(), - fee_only_noop_instruction.clone(), + fee_only_noop_instruction, ]), ExecutionStatus::ProcessedFailed, ); @@ -3192,9 +3184,7 @@ fn svm_inspect_nonce_load_failure(fee_paying_nonce: bool) { nonce::state::Data::new(fee_payer, initial_durable, LAMPORTS_PER_SIGNATURE); let mut initial_nonce_account = AccountSharedData::new_data( LAMPORTS_PER_SOL, - &nonce::versions::Versions::new(nonce::state::State::Initialized( - initial_nonce_data.clone(), - )), + &nonce::versions::Versions::new(nonce::state::State::Initialized(initial_nonce_data)), &system_program::id(), ) .unwrap(); @@ -3203,7 +3193,7 @@ fn svm_inspect_nonce_load_failure(fee_paying_nonce: bool) { let initial_nonce_info = NonceInfo::new(nonce_pubkey, initial_nonce_account.clone()); let advanced_durable = DurableNonce::from_blockhash(&LAST_BLOCKHASH); - let mut advanced_nonce_info = initial_nonce_info.clone(); + let mut advanced_nonce_info = initial_nonce_info; advanced_nonce_info .try_advance_nonce(advanced_durable, LAMPORTS_PER_SIGNATURE) .unwrap(); @@ -3376,7 +3366,7 @@ fn svm_inspect_account() { let mut final_test_entry = SvmTestEntry { initial_accounts: initial_test_entry.final_accounts.clone(), - final_accounts: initial_test_entry.final_accounts.clone(), + final_accounts: initial_test_entry.final_accounts, ..SvmTestEntry::default() }; diff --git a/timings/src/lib.rs b/timings/src/lib.rs index 77e3bfde..5987519c 100644 --- a/timings/src/lib.rs +++ b/timings/src/lib.rs @@ -36,9 +36,8 @@ impl ProgramTiming { self.accumulated_us += other.accumulated_us; self.accumulated_units += other.accumulated_units; self.count += other.count; - // Clones the entire vector, maybe not great... self.errored_txs_compute_consumed - .extend(other.errored_txs_compute_consumed.clone()); + .extend(other.errored_txs_compute_consumed.iter().copied()); self.total_errored_units += other.total_errored_units; } } diff --git a/transaction-context/Cargo.toml b/transaction-context/Cargo.toml index dded1e6b..33616868 100644 --- a/transaction-context/Cargo.toml +++ b/transaction-context/Cargo.toml @@ -21,17 +21,17 @@ dev-context-only-utils = ["bincode", "solana-account/dev-context-only-utils", "d serde = ["serde/derive", "solana-pubkey/serde"] [dependencies] -qualifier_attr = { workspace = true, optional = true } -serde = { workspace = true, optional = true } solana-account = { workspace = true } solana-instruction = { workspace = true, features = ["std"] } solana-instructions-sysvar = { workspace = true } solana-pubkey = { workspace = true } -solana-sbpf = { workspace = true } -[target.'cfg(not(target_os = "solana"))'.dependencies] +[target.'cfg(not(any(target_arch = "sbf", target_arch = "bpf")))'.dependencies] bincode = { workspace = true, optional = true } +qualifier_attr = { workspace = true, optional = true } +serde = { workspace = true, optional = true } solana-rent = { workspace = true } +solana-sbpf = { workspace = true } solana-sdk-ids = { workspace = true } solana-signature = { workspace = true, optional = true } @@ -39,10 +39,7 @@ solana-signature = { workspace = true, optional = true } solana-account-info = { workspace = true } solana-program-entrypoint = { workspace = true } solana-system-interface = { workspace = true } -solana-transaction-context = { path = ".", features = [ - "agave-unstable-api", - "dev-context-only-utils", -] } +solana-transaction-context = { path = ".", features = ["agave-unstable-api", "dev-context-only-utils"] } static_assertions = { workspace = true } [lints] diff --git a/transaction-context/src/instruction.rs b/transaction-context/src/instruction.rs index 0a3614bf..c90ab5b0 100644 --- a/transaction-context/src/instruction.rs +++ b/transaction-context/src/instruction.rs @@ -1,7 +1,8 @@ use { crate::{ - IndexOfAccount, InstructionAccount, TransactionContext, - instruction_accounts::BorrowedInstructionAccount, + IndexOfAccount, + instruction_accounts::{BorrowedInstructionAccount, InstructionAccount}, + transaction::TransactionContext, vm_addresses::{ GUEST_INSTRUCTION_ACCOUNT_BASE_ADDRESS, GUEST_INSTRUCTION_DATA_BASE_ADDRESS, GUEST_REGION_SIZE, @@ -43,6 +44,7 @@ impl Default for InstructionFrame { } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl InstructionFrame { pub fn configure_vm_slices( &mut self, @@ -73,6 +75,7 @@ pub struct InstructionContext<'a, 'ix_data> { // The rest of the fields are redundant shortcuts pub(crate) index_in_trace: usize, pub(crate) nesting_level: usize, + pub(crate) index_of_caller_instruction: usize, pub(crate) program_account_index_in_tx: IndexOfAccount, pub(crate) instruction_accounts: &'a [InstructionAccount], pub(crate) dedup_map: &'a [u16], @@ -85,6 +88,11 @@ impl<'a> InstructionContext<'a, '_> { self.index_in_trace } + /// Returns the index of the instruction that called into this one. + pub fn get_index_of_caller(&self) -> usize { + self.index_of_caller_instruction + } + /// How many Instructions were on the stack after this one was pushed /// /// That is the number of nested parent Instructions plus one (itself). diff --git a/transaction-context/src/instruction_accounts.rs b/transaction-context/src/instruction_accounts.rs index f9ae48ca..dd2e769f 100644 --- a/transaction-context/src/instruction_accounts.rs +++ b/transaction-context/src/instruction_accounts.rs @@ -1,6 +1,6 @@ use { crate::{ - IndexOfAccount, MAX_ACCOUNT_DATA_GROWTH_PER_INSTRUCTION, TransactionContext, + IndexOfAccount, MAX_ACCOUNT_DATA_GROWTH_PER_INSTRUCTION, transaction::TransactionContext, transaction_accounts::AccountRefMut, }, solana_account::{ReadableAccount, WritableAccount}, @@ -56,6 +56,7 @@ impl InstructionAccount { } /// Shared account borrowed from the TransactionContext and an InstructionContext. +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] #[derive(Debug)] pub struct BorrowedInstructionAccount<'a, 'ix_data> { pub(crate) transaction_context: &'a TransactionContext<'ix_data>, @@ -64,6 +65,7 @@ pub struct BorrowedInstructionAccount<'a, 'ix_data> { pub(crate) index_in_transaction_of_instruction_program: IndexOfAccount, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl BorrowedInstructionAccount<'_, '_> { /// Returns the index of this account (transaction wide) #[inline] @@ -86,7 +88,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Assignes the owner of this account (transaction wide) - #[cfg(not(target_os = "solana"))] pub fn set_owner(&mut self, pubkey: &[u8]) -> Result<(), InstructionError> { // Only the owner can assign a new owner if !self.is_owned_by_current_program() { @@ -116,7 +117,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Overwrites the number of lamports of this account (transaction wide) - #[cfg(not(target_os = "solana"))] pub fn set_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> { // An account not owned by the program cannot have its balance decrease if !self.is_owned_by_current_program() && lamports < self.get_lamports() { @@ -143,7 +143,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Adds lamports to this account (transaction wide) - #[cfg(not(target_os = "solana"))] pub fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> { self.set_lamports( self.get_lamports() @@ -153,7 +152,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Subtracts lamports from this account (transaction wide) - #[cfg(not(target_os = "solana"))] pub fn checked_sub_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> { self.set_lamports( self.get_lamports() @@ -169,7 +167,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Returns a writable slice of the account data (transaction wide) - #[cfg(not(target_os = "solana"))] pub fn get_data_mut(&mut self) -> Result<&mut [u8], InstructionError> { self.can_data_be_changed()?; self.touch()?; @@ -181,7 +178,6 @@ impl BorrowedInstructionAccount<'_, '_> { /// /// Call this when you have a slice of data you do not own and want to /// replace the account data with it. - #[cfg(not(target_os = "solana"))] pub fn set_data_from_slice(&mut self, data: &[u8]) -> Result<(), InstructionError> { self.can_data_be_resized(data.len())?; self.touch()?; @@ -198,7 +194,6 @@ impl BorrowedInstructionAccount<'_, '_> { /// Resizes the account data (transaction wide) /// /// Fills it with zeros at the end if is extended or truncates at the end otherwise. - #[cfg(not(target_os = "solana"))] pub fn set_data_length(&mut self, new_length: usize) -> Result<(), InstructionError> { self.can_data_be_resized(new_length)?; // don't touch the account if the length does not change @@ -212,7 +207,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Appends all elements in a slice to the account - #[cfg(not(target_os = "solana"))] pub fn extend_from_slice(&mut self, data: &[u8]) -> Result<(), InstructionError> { let new_len = self.get_data().len().saturating_add(data.len()); self.can_data_be_resized(new_len)?; @@ -238,12 +232,10 @@ impl BorrowedInstructionAccount<'_, '_> { /// /// During account serialization, if an account is shared it'll get mapped as CoW, else it'll /// get mapped directly as writable. - #[cfg(not(target_os = "solana"))] pub fn is_shared(&self) -> bool { self.account.is_shared() } - #[cfg(not(target_os = "solana"))] fn make_data_mut(&mut self) { // if the account is still shared, it means this is the first time we're // about to write into it. Make the account mutable by copying it in a @@ -257,13 +249,13 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Deserializes the account data into a state - #[cfg(all(not(target_os = "solana"), feature = "bincode"))] + #[cfg(feature = "bincode")] pub fn get_state(&self) -> Result { bincode::deserialize(self.account.data()).map_err(|_| InstructionError::InvalidAccountData) } /// Serializes a state into the account data - #[cfg(all(not(target_os = "solana"), feature = "bincode"))] + #[cfg(feature = "bincode")] pub fn set_state(&mut self, state: &T) -> Result<(), InstructionError> { let data = self.get_data_mut()?; let serialized_size = @@ -277,7 +269,6 @@ impl BorrowedInstructionAccount<'_, '_> { // Returns whether or the lamports currently in the account is sufficient for rent exemption should the // data be resized to the given size - #[cfg(not(target_os = "solana"))] pub fn is_rent_exempt_at_data_length(&self, data_length: usize) -> bool { self.transaction_context .rent @@ -293,7 +284,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Configures whether this account is executable (transaction wide) - #[cfg(not(target_os = "solana"))] pub fn set_executable(&mut self, is_executable: bool) -> Result<(), InstructionError> { // To become executable an account must be rent exempt if !self @@ -322,7 +312,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Returns the rent epoch of this account (transaction wide) - #[cfg(not(target_os = "solana"))] #[inline] pub fn get_rent_epoch(&self) -> u64 { self.account.rent_epoch() @@ -347,7 +336,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Returns an error if the account data can not be mutated by the current program - #[cfg(not(target_os = "solana"))] pub fn can_data_be_changed(&self) -> Result<(), InstructionError> { // and only if the account is writable if !self.is_writable() { @@ -361,7 +349,6 @@ impl BorrowedInstructionAccount<'_, '_> { } /// Returns an error if the account data can not be resized to the given length - #[cfg(not(target_os = "solana"))] pub fn can_data_be_resized(&self, new_len: usize) -> Result<(), InstructionError> { let old_len = self.get_data().len(); // Only the owner can change the length of the data @@ -374,14 +361,12 @@ impl BorrowedInstructionAccount<'_, '_> { self.can_data_be_changed() } - #[cfg(not(target_os = "solana"))] fn touch(&self) -> Result<(), InstructionError> { self.transaction_context .accounts .touch(self.instruction_account.index_in_transaction) } - #[cfg(not(target_os = "solana"))] fn update_accounts_resize_delta(&mut self, new_len: usize) -> Result<(), InstructionError> { self.transaction_context .accounts @@ -389,7 +374,7 @@ impl BorrowedInstructionAccount<'_, '_> { } } -#[cfg(not(target_os = "solana"))] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] fn is_zeroed(buf: &[u8]) -> bool { const ZEROS_LEN: usize = 1024; const ZEROS: [u8; ZEROS_LEN] = [0; ZEROS_LEN]; diff --git a/transaction-context/src/lib.rs b/transaction-context/src/lib.rs index 3d5eab34..41fabcac 100644 --- a/transaction-context/src/lib.rs +++ b/transaction-context/src/lib.rs @@ -3,32 +3,14 @@ #![deny(clippy::indexing_slicing)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] -use { - crate::{ - instruction::{InstructionContext, InstructionFrame}, - instruction_accounts::InstructionAccount, - transaction_accounts::{KeyedAccountSharedData, TransactionAccounts}, - vm_addresses::{ - GUEST_INSTRUCTION_DATA_BASE_ADDRESS, GUEST_REGION_SIZE, RETURN_DATA_SCRATCHPAD, - }, - vm_slice::VmSlice, - }, - solana_account::{AccountSharedData, ReadableAccount}, - solana_instruction::error::InstructionError, - solana_instructions_sysvar as instructions, - solana_pubkey::Pubkey, - solana_sbpf::memory_region::{AccessType, AccessViolationHandler, MemoryRegion}, - std::{borrow::Cow, cell::Cell, rc::Rc}, -}; -#[cfg(not(target_os = "solana"))] -use {solana_account::WritableAccount, solana_rent::Rent}; - pub mod instruction; pub mod instruction_accounts; pub mod transaction_accounts; mod vm_addresses; pub mod vm_slice; +pub mod transaction; + pub const MAX_ACCOUNTS_PER_TRANSACTION: usize = 256; // This is one less than MAX_ACCOUNTS_PER_TRANSACTION because // one index is used as NON_DUP_MARKER in ABI v0 and v1. @@ -66,897 +48,3 @@ static_assertions::const_assert_eq!( /// Index of an account inside of the transaction or an instruction. pub type IndexOfAccount = u16; - -/// Used only in fn `take_instruction_trace` for deconstructing TransactionContext -pub type InstructionTrace<'ix_data> = ( - Vec, - Vec>, - Vec>, -); - -/// This data structure is shared with programs in ABIv2, providing information about the -/// transaction metadata. -/// -/// Modifications without a feature gate and proper versioning might break programs. -#[repr(C)] -#[derive(Debug)] -struct TransactionFrame { - /// Pubkey of the last program to write to the return data scratchpad - return_data_pubkey: Pubkey, - return_data_scratchpad: VmSlice, - /// Scratchpad for programs to write CPI instruction data - cpi_scratchpad: VmSlice, - /// Index of current executing instruction - current_executing_instruction: u16, - /// Number of instructions in transaction - number_of_instructions: u16, - /// Number of executed CPIs - number_of_executed_cpis: u16, - /// Number of transaction accounts - number_of_transaction_accounts: u16, -} - -/// Loaded transaction shared between runtime and programs. -/// -/// This context is valid for the entire duration of a transaction being processed. -#[derive(Debug)] -pub struct TransactionContext<'ix_data> { - accounts: Rc, - instruction_stack_capacity: usize, - instruction_trace_capacity: usize, - instruction_stack: Vec, - instruction_trace: Vec, - transaction_frame: TransactionFrame, - return_data_bytes: Vec, - top_level_instruction_index: usize, - #[cfg(not(target_os = "solana"))] - rent: Rent, - /// This is an account deduplication map that maps index_in_transaction to index_in_instruction - /// Usage: dedup_map[index_in_transaction] = index_in_instruction - /// Each entry in `deduplication_maps` represents the deduplication map for each instruction. - deduplication_maps: Vec>, - /// Each entry in `instruction_accounts` represents the array of accounts for each instruction. - instruction_accounts: Vec>, - /// Each entry in `instruction_data` represents the data for instruction at the corresponding - /// index. - instruction_data: Vec>, -} - -impl<'ix_data> TransactionContext<'ix_data> { - /// Constructs a new TransactionContext - #[cfg(not(target_os = "solana"))] - pub fn new( - transaction_accounts: Vec, - rent: Rent, - instruction_stack_capacity: usize, - instruction_trace_capacity: usize, - number_of_top_level_instructions: usize, - ) -> Self { - let transaction_frame = TransactionFrame { - return_data_pubkey: Pubkey::default(), - return_data_scratchpad: VmSlice::new(RETURN_DATA_SCRATCHPAD, 0), - cpi_scratchpad: VmSlice::new( - GUEST_INSTRUCTION_DATA_BASE_ADDRESS.saturating_add( - GUEST_REGION_SIZE.saturating_mul(number_of_top_level_instructions as u64), - ), - 0, - ), - current_executing_instruction: 0, - number_of_instructions: number_of_top_level_instructions as u16, - number_of_executed_cpis: 0, - number_of_transaction_accounts: transaction_accounts.len() as u16, - }; - - Self { - accounts: Rc::new(TransactionAccounts::new(transaction_accounts)), - instruction_stack_capacity, - instruction_trace_capacity, - instruction_stack: Vec::with_capacity(instruction_stack_capacity), - instruction_trace: vec![InstructionFrame::default()], - return_data_bytes: Vec::new(), - transaction_frame, - top_level_instruction_index: 0, - rent, - instruction_accounts: Vec::with_capacity(instruction_trace_capacity), - deduplication_maps: Vec::with_capacity(instruction_trace_capacity), - instruction_data: Vec::with_capacity(instruction_trace_capacity), - } - } - - #[cfg(feature = "dev-context-only-utils")] - pub fn set_top_level_instruction_index(&mut self, top_level_instruction_index: usize) { - self.top_level_instruction_index = top_level_instruction_index; - } - - /// Used in mock_process_instruction - #[cfg(not(target_os = "solana"))] - pub fn deconstruct_without_keys(self) -> Result, InstructionError> { - if !self.instruction_stack.is_empty() { - return Err(InstructionError::CallDepth); - } - - let accounts = Rc::try_unwrap(self.accounts) - .expect("transaction_context.accounts has unexpected outstanding refs") - .deconstruct_into_account_shared_data(); - - Ok(accounts) - } - - #[cfg(not(target_os = "solana"))] - pub fn accounts(&self) -> &Rc { - &self.accounts - } - - /// Returns the total number of accounts loaded in this Transaction - pub fn get_number_of_accounts(&self) -> IndexOfAccount { - self.accounts.len() as IndexOfAccount - } - - /// Searches for an account by its key - pub fn get_key_of_account_at_index( - &self, - index_in_transaction: IndexOfAccount, - ) -> Result<&Pubkey, InstructionError> { - self.accounts - .account_key(index_in_transaction) - .ok_or(InstructionError::MissingAccount) - } - - /// Searches for an account by its key - pub fn find_index_of_account(&self, pubkey: &Pubkey) -> Option { - self.accounts - .account_keys_iter() - .position(|key| key == pubkey) - .map(|index| index as IndexOfAccount) - } - - /// Gets the max length of the instruction trace - pub fn get_instruction_trace_capacity(&self) -> usize { - self.instruction_trace_capacity - } - - /// Returns the instruction trace length. - /// - /// Not counting the last empty instruction which is always pre-reserved for the next instruction. - /// See also `get_next_instruction_context()`. - pub fn get_instruction_trace_length(&self) -> usize { - self.instruction_trace.len().saturating_sub(1) - } - - /// Gets a view on an instruction by its index in the trace - pub fn get_instruction_context_at_index_in_trace( - &self, - index_in_trace: usize, - ) -> Result, InstructionError> { - let instruction = self - .instruction_trace - .get(index_in_trace) - .ok_or(InstructionError::CallDepth)?; - - // These commands will return a default empty slice if we are retrieving an instruction - // that hasn't been configured yet. - let instruction_accounts = self - .instruction_accounts - .get(index_in_trace) - .map(|item| item.as_ref()) - .unwrap_or_default(); - let dedup_map = self - .deduplication_maps - .get(index_in_trace) - .map(|item| item.as_ref()) - .unwrap_or_default(); - let instruction_data = self - .instruction_data - .get(index_in_trace) - .map(|item| item.as_ref()) - .unwrap_or_default(); - Ok(InstructionContext { - transaction_context: self, - index_in_trace, - nesting_level: instruction.nesting_level as usize, - program_account_index_in_tx: instruction.program_account_index_in_tx as IndexOfAccount, - instruction_accounts, - dedup_map, - instruction_data, - }) - } - - /// Gets a view on the instruction by its nesting level in the stack - pub fn get_instruction_context_at_nesting_level( - &self, - nesting_level: usize, - ) -> Result, InstructionError> { - let index_in_trace = *self - .instruction_stack - .get(nesting_level) - .ok_or(InstructionError::CallDepth)?; - let instruction_context = self.get_instruction_context_at_index_in_trace(index_in_trace)?; - debug_assert_eq!(instruction_context.nesting_level, nesting_level); - Ok(instruction_context) - } - - /// Gets the max height of the instruction stack - pub fn get_instruction_stack_capacity(&self) -> usize { - self.instruction_stack_capacity - } - - /// Gets instruction stack height, top-level instructions are height - /// `solana_instruction::TRANSACTION_LEVEL_STACK_HEIGHT` - pub fn get_instruction_stack_height(&self) -> usize { - self.instruction_stack.len() - } - - /// Returns the index in the instruction trace of the current executing instruction - pub fn get_current_instruction_index(&self) -> Result { - self.get_instruction_stack_height() - .checked_sub(1) - .ok_or(InstructionError::CallDepth) - } - - /// Returns a view on the current instruction - pub fn get_current_instruction_context( - &self, - ) -> Result, InstructionError> { - let level = self.get_current_instruction_index()?; - self.get_instruction_context_at_nesting_level(level) - } - - /// Returns a view on the next instruction. This function assumes it has already been - /// configured with the correct values in `prepare_next_instruction` or - /// `prepare_next_top_level_instruction` - pub fn get_next_instruction_context( - &self, - ) -> Result, InstructionError> { - let index_in_trace = self - .instruction_trace - .len() - .checked_sub(1) - .ok_or(InstructionError::CallDepth)?; - self.get_instruction_context_at_index_in_trace(index_in_trace) - } - - /// Configures the next instruction. - /// - /// The last InstructionContext is always empty and pre-reserved for the next instruction. - pub fn configure_next_instruction( - &mut self, - program_index: IndexOfAccount, - instruction_accounts: Vec, - deduplication_map: Vec, - instruction_data: Cow<'ix_data, [u8]>, - caller_index: Option, - ) -> Result<(), InstructionError> { - debug_assert_eq!(deduplication_map.len(), MAX_ACCOUNTS_PER_TRANSACTION); - let trace_len = self.instruction_trace.len(); - let instruction_index = trace_len.saturating_sub(1); - - let instruction = self - .instruction_trace - .last_mut() - .ok_or(InstructionError::CallDepth)?; - - // If we have a parent index, then we are dealing with a CPI. - if let Some(caller_index) = caller_index { - self.transaction_frame.number_of_instructions = self - .transaction_frame - .number_of_instructions - .saturating_add(1); - instruction.index_of_caller_instruction = caller_index; - } - - self.transaction_frame.cpi_scratchpad = VmSlice::new( - GUEST_INSTRUCTION_DATA_BASE_ADDRESS.saturating_add( - GUEST_REGION_SIZE - .saturating_mul(self.transaction_frame.number_of_instructions as u64), - ), - 0, - ); - - instruction.program_account_index_in_tx = program_index; - instruction.configure_vm_slices( - instruction_index as u64, - instruction_accounts.len(), - instruction_data.len() as u64, - ); - self.deduplication_maps - .push(deduplication_map.into_boxed_slice()); - self.instruction_accounts - .push(instruction_accounts.into_boxed_slice()); - self.instruction_data.push(instruction_data); - Ok(()) - } - - /// A version of `configure_next_instruction` to help creating the deduplication map in tests - pub fn configure_next_instruction_for_tests( - &mut self, - program_index: IndexOfAccount, - instruction_accounts: Vec, - instruction_data: Vec, - ) -> Result<(), InstructionError> { - debug_assert!(instruction_accounts.len() <= u16::MAX as usize); - let mut dedup_map = vec![u16::MAX; MAX_ACCOUNTS_PER_TRANSACTION]; - for (idx, account) in instruction_accounts.iter().enumerate() { - let index_in_instruction = dedup_map - .get_mut(account.index_in_transaction as usize) - .unwrap(); - if *index_in_instruction == u16::MAX { - *index_in_instruction = idx as u16; - } - } - self.configure_next_instruction( - program_index, - instruction_accounts, - dedup_map, - Cow::Owned(instruction_data), - None, - ) - } - - /// Pushes the next instruction - #[cfg(not(target_os = "solana"))] - pub fn push(&mut self) -> Result<(), InstructionError> { - let nesting_level = self.get_instruction_stack_height(); - if !self.instruction_stack.is_empty() && self.accounts.get_lamports_delta() != 0 { - return Err(InstructionError::UnbalancedInstruction); - } - { - let instruction = self - .instruction_trace - .last_mut() - .ok_or(InstructionError::CallDepth)?; - instruction.nesting_level = nesting_level as u16; - } - let index_in_trace = self.get_instruction_trace_length(); - if index_in_trace >= self.instruction_trace_capacity { - return Err(InstructionError::MaxInstructionTraceLengthExceeded); - } - self.instruction_trace.push(InstructionFrame::default()); - if nesting_level >= self.instruction_stack_capacity { - return Err(InstructionError::CallDepth); - } - self.transaction_frame.current_executing_instruction = index_in_trace as u16; - self.instruction_stack.push(index_in_trace); - if let Some(index_in_transaction) = self.find_index_of_account(&instructions::id()) { - let mut mut_account_ref = self.accounts.try_borrow_mut(index_in_transaction)?; - if mut_account_ref.owner() != &solana_sdk_ids::sysvar::id() { - return Err(InstructionError::InvalidAccountOwner); - } - instructions::store_current_index_checked( - mut_account_ref.data_as_mut_slice(), - self.top_level_instruction_index as u16, - )?; - } - Ok(()) - } - - /// Pops the current instruction - #[cfg(not(target_os = "solana"))] - pub fn pop(&mut self) -> Result<(), InstructionError> { - if self.instruction_stack.is_empty() { - return Err(InstructionError::CallDepth); - } - // Verify (before we pop) that the total sum of all lamports in this instruction did not change - let detected_an_unbalanced_instruction = - self.get_current_instruction_context() - .and_then(|instruction_context| { - // Verify all executable accounts have no outstanding refs - self.accounts - .try_borrow_mut( - instruction_context.get_index_of_program_account_in_transaction()?, - ) - .map_err(|err| { - if err == InstructionError::AccountBorrowFailed { - InstructionError::AccountBorrowOutstanding - } else { - err - } - })?; - Ok(self.accounts.get_lamports_delta() != 0) - }); - // Always pop, even if we `detected_an_unbalanced_instruction` - self.instruction_stack.pop(); - if let Some(instr_idx) = self.instruction_stack.last() { - self.transaction_frame.number_of_executed_cpis = self - .transaction_frame - .number_of_executed_cpis - .saturating_add(1); - self.transaction_frame.current_executing_instruction = *instr_idx as u16; - } else { - self.top_level_instruction_index = self.top_level_instruction_index.saturating_add(1); - } - if detected_an_unbalanced_instruction? { - Err(InstructionError::UnbalancedInstruction) - } else { - Ok(()) - } - } - - /// Gets the return data of the current instruction or any above - pub fn get_return_data(&self) -> (&Pubkey, &[u8]) { - ( - &self.transaction_frame.return_data_pubkey, - &self.return_data_bytes, - ) - } - - /// Set the return data of the current instruction - pub fn set_return_data( - &mut self, - program_id: Pubkey, - data: Vec, - ) -> Result<(), InstructionError> { - self.transaction_frame.return_data_pubkey = program_id; - // SAFETY: `return_data_scratchpad` is backed by `self.return_data_bytes` - // and `return_data_bytes` is being reset to `data` - // in the next statement. - unsafe { - self.transaction_frame - .return_data_scratchpad - .set_len(data.len() as u64); - } - self.return_data_bytes = data; - Ok(()) - } - - /// Returns a new account data write access handler - pub fn access_violation_handler( - &self, - stricter_abi_and_runtime_constraints: bool, - account_data_direct_mapping: bool, - ) -> AccessViolationHandler { - let accounts = Rc::clone(&self.accounts); - Box::new( - move |region: &mut MemoryRegion, - address_space_reserved_for_account: u64, - access_type: AccessType, - vm_addr: u64, - len: u64| { - if access_type == AccessType::Load { - return; - } - let Some(index_in_transaction) = region.access_violation_handler_payload else { - // This region is not a writable account. - return; - }; - let requested_length = - vm_addr.saturating_add(len).saturating_sub(region.vm_addr) as usize; - if requested_length > address_space_reserved_for_account as usize { - // Requested access goes further than the account region. - return; - } - - // The four calls below can't really fail. If they fail because of a bug, - // whatever is writing will trigger an EbpfError::AccessViolation like - // if the region was readonly, and the transaction will fail gracefully. - let Ok(mut account) = accounts.try_borrow_mut(index_in_transaction) else { - debug_assert!(false); - return; - }; - if accounts.touch(index_in_transaction).is_err() { - debug_assert!(false); - return; - } - - let remaining_allowed_growth = MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION - .saturating_sub(accounts.resize_delta()) - .max(0) as usize; - - if requested_length > region.len as usize { - // Realloc immediately here to fit the requested access, - // then later in CPI or deserialization realloc again to the - // account length the program stored in AccountInfo. - let old_len = account.data().len(); - let new_len = (address_space_reserved_for_account as usize) - .min(MAX_ACCOUNT_DATA_LEN as usize) - .min(old_len.saturating_add(remaining_allowed_growth)); - // The last two min operations ensure the following: - debug_assert!(accounts.can_data_be_resized(old_len, new_len).is_ok()); - if accounts - .update_accounts_resize_delta(old_len, new_len) - .is_err() - { - return; - } - account.resize(new_len, 0); - region.len = new_len as u64; - } - - // Potentially unshare / make the account shared data unique (CoW logic). - if stricter_abi_and_runtime_constraints && account_data_direct_mapping { - region.host_addr = account.data_as_mut_slice().as_mut_ptr() as u64; - region.writable = true; - } - }, - ) - } - - /// Take ownership of the instruction trace - pub fn take_instruction_trace(&mut self) -> InstructionTrace<'_> { - // The last frame is a placeholder for the next instruction to be executed, so it - // is empty. - self.instruction_trace.pop(); - ( - std::mem::take(&mut self.instruction_trace), - std::mem::take(&mut self.instruction_accounts), - std::mem::take(&mut self.instruction_data), - ) - } -} - -/// Return data at the end of a transaction -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct TransactionReturnData { - pub program_id: Pubkey, - pub data: Vec, -} - -/// Everything that needs to be recorded from a TransactionContext after execution -#[cfg(not(target_os = "solana"))] -pub struct ExecutionRecord { - pub accounts: Vec, - pub return_data: TransactionReturnData, - pub touched_account_count: u64, - pub accounts_resize_delta: i64, -} - -/// Used by the bank in the runtime to write back the processed accounts and recorded instructions -#[cfg(not(target_os = "solana"))] -impl From> for ExecutionRecord { - fn from(context: TransactionContext) -> Self { - let (accounts, touched_flags, resize_delta) = Rc::try_unwrap(context.accounts) - .expect("transaction_context.accounts has unexpected outstanding refs") - .take(); - let touched_account_count = touched_flags - .iter() - .fold(0usize, |accumulator, was_touched| { - accumulator.saturating_add(was_touched.get() as usize) - }) as u64; - - let return_data = TransactionReturnData { - program_id: context.transaction_frame.return_data_pubkey, - data: context.return_data_bytes, - }; - - Self { - accounts, - return_data, - touched_account_count, - accounts_resize_delta: Cell::into_inner(resize_delta), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_instructions_sysvar_store_index_checked() { - let build_transaction_context = |account: AccountSharedData| { - TransactionContext::new( - vec![ - (Pubkey::new_unique(), AccountSharedData::default()), - (instructions::id(), account), - ], - Rent::default(), - /* max_instruction_stack_depth */ 2, - /* max_instruction_trace_length */ 2, - /* number_of_top_level_instructions */ 1, - ) - }; - - let correct_space = 2; - let rent_exempt_lamports = Rent::default().minimum_balance(correct_space); - - // First try it with the wrong owner. - let account = - AccountSharedData::new(rent_exempt_lamports, correct_space, &Pubkey::new_unique()); - assert_eq!( - build_transaction_context(account).push(), - Err(InstructionError::InvalidAccountOwner), - ); - - // Now with the wrong data length. - let account = - AccountSharedData::new(rent_exempt_lamports, 0, &solana_sdk_ids::sysvar::id()); - assert_eq!( - build_transaction_context(account).push(), - Err(InstructionError::AccountDataTooSmall), - ); - - // Finally provide the correct account setup. - let account = AccountSharedData::new( - rent_exempt_lamports, - correct_space, - &solana_sdk_ids::sysvar::id(), - ); - assert_eq!(build_transaction_context(account).push(), Ok(()),); - } - - #[test] - fn test_invalid_native_loader_index() { - let mut transaction_context = TransactionContext::new( - vec![( - Pubkey::new_unique(), - AccountSharedData::new(1, 1, &Pubkey::new_unique()), - )], - Rent::default(), - 20, - 20, - 1, - ); - - transaction_context - .configure_next_instruction_for_tests( - u16::MAX, - vec![InstructionAccount::new(0, false, false)], - vec![], - ) - .unwrap(); - let instruction_context = transaction_context.get_next_instruction_context().unwrap(); - - let result = instruction_context.get_index_of_program_account_in_transaction(); - assert_eq!(result, Err(InstructionError::MissingAccount)); - - let result = instruction_context.get_program_key(); - assert_eq!(result, Err(InstructionError::MissingAccount)); - - let result = instruction_context.get_program_owner(); - assert_eq!(result.err(), Some(InstructionError::MissingAccount)); - } - - #[test] - fn test_instruction_shared_items() { - let transaction_accounts = vec![(Pubkey::new_unique(), AccountSharedData::default()); 10]; - let mut transaction_context = - TransactionContext::new(transaction_accounts, Rent::default(), 20, 20, 3); - - let instruction_accounts_1 = vec![ - InstructionAccount::new(0, false, true), - InstructionAccount::new(3, true, false), - ]; - transaction_context - .configure_next_instruction_for_tests( - 1, - instruction_accounts_1.clone(), - vec![1, 2, 3, 4], - ) - .unwrap(); - transaction_context.push().unwrap(); - - let instruction_accounts_2 = vec![ - InstructionAccount::new(0, false, true), - InstructionAccount::new(3, true, false), - InstructionAccount::new(5, false, false), - ]; - transaction_context - .configure_next_instruction_for_tests( - 1, - instruction_accounts_2.clone(), - vec![5, 6, 7, 8, 9], - ) - .unwrap(); - transaction_context.push().unwrap(); - - let instruction_accounts_3 = vec![ - InstructionAccount::new(0, false, true), - InstructionAccount::new(3, true, false), - InstructionAccount::new(5, false, false), - InstructionAccount::new(3, false, false), - InstructionAccount::new(10, false, false), - ]; - transaction_context - .configure_next_instruction_for_tests(1, instruction_accounts_3.clone(), vec![10, 11]) - .unwrap(); - transaction_context.push().unwrap(); - - let first_ix_context = transaction_context - .get_instruction_context_at_index_in_trace(0) - .unwrap(); - assert_eq!( - instruction_accounts_1.as_slice(), - first_ix_context.instruction_accounts - ); - assert_eq!( - *first_ix_context.instruction_data, - **transaction_context.instruction_data.first().unwrap() - ); - for (idx_in_ix, acc) in instruction_accounts_1.iter().enumerate() { - assert_eq!( - *first_ix_context - .dedup_map - .get(acc.index_in_transaction as usize) - .unwrap(), - idx_in_ix as u16 - ); - } - - let second_ix_context = transaction_context - .get_instruction_context_at_index_in_trace(1) - .unwrap(); - assert_eq!( - instruction_accounts_2.as_slice(), - second_ix_context.instruction_accounts - ); - assert_eq!( - *second_ix_context.instruction_data, - **transaction_context.instruction_data.get(1).unwrap() - ); - for (idx_in_ix, acc) in instruction_accounts_2.iter().enumerate() { - assert_eq!( - *second_ix_context - .dedup_map - .get(acc.index_in_transaction as usize) - .unwrap(), - idx_in_ix as u16 - ); - } - - let third_ix_context = transaction_context - .get_instruction_context_at_index_in_trace(2) - .unwrap(); - assert_eq!( - instruction_accounts_3.as_slice(), - third_ix_context.instruction_accounts - ); - assert_eq!( - *third_ix_context.instruction_data, - **transaction_context.instruction_data.get(2).unwrap() - ); - for (idx_in_ix, acc) in instruction_accounts_3.iter().enumerate() { - if idx_in_ix == 3 { - assert_eq!( - *third_ix_context - .dedup_map - .get(acc.index_in_transaction as usize) - .unwrap(), - 1 - ); - } else { - assert_eq!( - *third_ix_context - .dedup_map - .get(acc.index_in_transaction as usize) - .unwrap(), - idx_in_ix as u16 - ); - } - } - } - - #[test] - fn test_number_of_instructions() { - let transaction_accounts = vec![(Pubkey::new_unique(), AccountSharedData::default()); 3]; - let mut transaction_context = - TransactionContext::new(transaction_accounts, Rent::default(), 20, 20, 3); - assert_eq!( - transaction_context.transaction_frame.number_of_instructions, - 3 - ); - assert_eq!( - transaction_context - .transaction_frame - .number_of_executed_cpis, - 0 - ); - - transaction_context - .configure_next_instruction( - 0, - vec![InstructionAccount::new(1, false, false)], - vec![0; MAX_ACCOUNTS_PER_TRANSACTION], - Vec::new().into(), - None, - ) - .unwrap(); - transaction_context.push().unwrap(); - assert_eq!( - transaction_context - .transaction_frame - .current_executing_instruction, - 0 - ); - transaction_context.pop().unwrap(); - assert_eq!( - transaction_context.transaction_frame.number_of_instructions, - 3 - ); - assert_eq!( - transaction_context - .transaction_frame - .number_of_executed_cpis, - 0 - ); - - transaction_context - .configure_next_instruction( - 0, - vec![InstructionAccount::new(1, false, false)], - vec![0; MAX_ACCOUNTS_PER_TRANSACTION], - Vec::new().into(), - None, - ) - .unwrap(); - transaction_context.push().unwrap(); - assert_eq!( - transaction_context - .transaction_frame - .current_executing_instruction, - 1 - ); - assert_eq!( - transaction_context.transaction_frame.cpi_scratchpad.ptr(), - GUEST_INSTRUCTION_DATA_BASE_ADDRESS.saturating_add(GUEST_REGION_SIZE.saturating_mul(3)) - ); - assert_eq!( - transaction_context.transaction_frame.cpi_scratchpad.len(), - 0, - ); - - transaction_context - .configure_next_instruction( - 0, - vec![InstructionAccount::new(2, false, true)], - vec![0; 256], - Vec::new().into(), - Some(2), - ) - .unwrap(); - assert_eq!( - transaction_context.transaction_frame.number_of_instructions, - 4 - ); - assert_eq!( - transaction_context - .transaction_frame - .number_of_executed_cpis, - 0 - ); - transaction_context.push().unwrap(); - assert_eq!( - transaction_context - .transaction_frame - .current_executing_instruction, - 2 - ); - assert_eq!( - transaction_context.transaction_frame.cpi_scratchpad.ptr(), - GUEST_INSTRUCTION_DATA_BASE_ADDRESS.saturating_add(GUEST_REGION_SIZE.saturating_mul(4)) - ); - assert_eq!( - transaction_context.transaction_frame.cpi_scratchpad.len(), - 0, - ); - - transaction_context.pop().unwrap(); - assert_eq!( - transaction_context.transaction_frame.number_of_instructions, - 4 - ); - assert_eq!( - transaction_context - .transaction_frame - .number_of_executed_cpis, - 1 - ); - assert_eq!( - transaction_context - .transaction_frame - .current_executing_instruction, - 1 - ); - transaction_context.pop().unwrap(); - - assert_eq!( - transaction_context.transaction_frame.number_of_instructions, - 4 - ); - assert_eq!( - transaction_context - .transaction_frame - .number_of_executed_cpis, - 1 - ); - } -} diff --git a/transaction-context/src/transaction.rs b/transaction-context/src/transaction.rs new file mode 100644 index 00000000..6bfef6d0 --- /dev/null +++ b/transaction-context/src/transaction.rs @@ -0,0 +1,1062 @@ +use { + crate::{ + IndexOfAccount, MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION, MAX_ACCOUNT_DATA_LEN, + MAX_ACCOUNTS_PER_TRANSACTION, + instruction::{InstructionContext, InstructionFrame}, + instruction_accounts::InstructionAccount, + transaction_accounts::{KeyedAccountSharedData, TransactionAccounts}, + vm_addresses::{ + GUEST_INSTRUCTION_DATA_BASE_ADDRESS, GUEST_REGION_SIZE, RETURN_DATA_SCRATCHPAD, + }, + vm_slice::VmSlice, + }, + solana_account::{AccountSharedData, ReadableAccount, WritableAccount}, + solana_instruction::error::InstructionError, + solana_instructions_sysvar as instructions, + solana_pubkey::Pubkey, + solana_rent::Rent, + solana_sbpf::memory_region::{AccessType, AccessViolationHandler, MemoryRegion}, + std::{borrow::Cow, cell::Cell, rc::Rc}, +}; + +/// Used only in fn `take_instruction_trace` for deconstructing TransactionContext +pub type InstructionTrace<'ix_data> = ( + Vec, + Vec>, + Vec>, +); + +/// This data structure is shared with programs in ABIv2, providing information about the +/// transaction metadata. +/// +/// Modifications without a feature gate and proper versioning might break programs. +#[repr(C)] +#[derive(Debug)] +struct TransactionFrame { + /// Pubkey of the last program to write to the return data scratchpad + return_data_pubkey: Pubkey, + return_data_scratchpad: VmSlice, + /// Scratchpad for programs to write CPI instruction data + cpi_scratchpad: VmSlice, + /// Index of current executing instruction + current_executing_instruction: u16, + /// Number of instructions in the instruction trace (including top level and CPIs) + total_number_of_instructions_in_trace: u16, + /// Number of CPIs in the instruction trace + number_of_cpis_in_trace: u16, + /// Number of transaction accounts + number_of_transaction_accounts: u16, +} + +/// Loaded transaction shared between runtime and programs. +/// +/// This context is valid for the entire duration of a transaction being processed. +#[derive(Debug)] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] +pub struct TransactionContext<'ix_data> { + pub(crate) accounts: Rc, + instruction_stack_capacity: usize, + instruction_trace_capacity: usize, + instruction_stack: Vec, + instruction_trace: Vec, + transaction_frame: TransactionFrame, + return_data_bytes: Vec, + next_top_level_instruction_index: usize, + #[cfg(not(target_os = "solana"))] + pub(crate) rent: Rent, + /// This is an account deduplication map that maps index_in_transaction to index_in_instruction + /// Usage: dedup_map[index_in_transaction] = index_in_instruction + /// Each entry in `deduplication_maps` represents the deduplication map for each instruction. + deduplication_maps: Vec>, + /// Each entry in `instruction_accounts` represents the array of accounts for each instruction. + instruction_accounts: Vec>, + /// Each entry in `instruction_data` represents the data for instruction at the corresponding + /// index. + instruction_data: Vec>, +} + +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] +impl<'ix_data> TransactionContext<'ix_data> { + /// Constructs a new TransactionContext + pub fn new( + transaction_accounts: Vec, + rent: Rent, + instruction_stack_capacity: usize, + instruction_trace_capacity: usize, + number_of_top_level_instructions: usize, + ) -> Self { + let transaction_frame = TransactionFrame { + return_data_pubkey: Pubkey::default(), + return_data_scratchpad: VmSlice::new(RETURN_DATA_SCRATCHPAD, 0), + cpi_scratchpad: VmSlice::new(0, 0), + current_executing_instruction: 0, + total_number_of_instructions_in_trace: number_of_top_level_instructions as u16, + number_of_cpis_in_trace: 0, + number_of_transaction_accounts: transaction_accounts.len() as u16, + }; + + Self { + accounts: Rc::new(TransactionAccounts::new(transaction_accounts)), + instruction_stack_capacity, + instruction_trace_capacity, + instruction_stack: Vec::with_capacity(instruction_stack_capacity), + instruction_trace: vec![InstructionFrame::default()], + return_data_bytes: Vec::new(), + transaction_frame, + next_top_level_instruction_index: 0, + rent, + instruction_accounts: Vec::with_capacity(instruction_trace_capacity), + deduplication_maps: Vec::with_capacity(instruction_trace_capacity), + instruction_data: Vec::with_capacity(instruction_trace_capacity), + } + } + + /// Used in mock_process_instruction + pub fn deconstruct_without_keys(self) -> Result, InstructionError> { + if !self.instruction_stack.is_empty() { + return Err(InstructionError::CallDepth); + } + + let accounts = Rc::try_unwrap(self.accounts) + .expect("transaction_context.accounts has unexpected outstanding refs") + .deconstruct_into_account_shared_data(); + + Ok(accounts) + } + + pub fn accounts(&self) -> &Rc { + &self.accounts + } + + /// Returns the total number of accounts loaded in this Transaction + pub fn get_number_of_accounts(&self) -> IndexOfAccount { + self.accounts.len() as IndexOfAccount + } + + /// Searches for an account by its key + pub fn get_key_of_account_at_index( + &self, + index_in_transaction: IndexOfAccount, + ) -> Result<&Pubkey, InstructionError> { + self.accounts + .account_key(index_in_transaction) + .ok_or(InstructionError::MissingAccount) + } + + /// Searches for an account by its key + pub fn find_index_of_account(&self, pubkey: &Pubkey) -> Option { + self.accounts + .account_keys_iter() + .position(|key| key == pubkey) + .map(|index| index as IndexOfAccount) + } + + /// Gets the max length of the instruction trace + pub fn get_instruction_trace_capacity(&self) -> usize { + self.instruction_trace_capacity + } + + /// Returns the instruction trace length. + /// + /// Not counting the last empty instruction which is always pre-reserved for the next instruction. + pub fn get_instruction_trace_length(&self) -> usize { + self.instruction_trace.len().saturating_sub(1) + } + + /// Gets a view on an instruction by its index in the trace + pub fn get_instruction_context_at_index_in_trace( + &self, + index_in_trace: usize, + ) -> Result, InstructionError> { + let instruction = self + .instruction_trace + .get(index_in_trace) + .ok_or(InstructionError::CallDepth)?; + + // These commands will return a default empty slice if we are retrieving an instruction + // that hasn't been configured yet. + let instruction_accounts = self + .instruction_accounts + .get(index_in_trace) + .map(|item| item.as_ref()) + .unwrap_or_default(); + let dedup_map = self + .deduplication_maps + .get(index_in_trace) + .map(|item| item.as_ref()) + .unwrap_or_default(); + let instruction_data = self + .instruction_data + .get(index_in_trace) + .map(|item| item.as_ref()) + .unwrap_or_default(); + Ok(InstructionContext { + transaction_context: self, + index_in_trace, + nesting_level: instruction.nesting_level as usize, + program_account_index_in_tx: instruction.program_account_index_in_tx as IndexOfAccount, + instruction_accounts, + dedup_map, + instruction_data, + index_of_caller_instruction: instruction.index_of_caller_instruction as usize, + }) + } + + /// Gets a view on the instruction by its nesting level in the stack + pub fn get_instruction_context_at_nesting_level( + &self, + nesting_level: usize, + ) -> Result, InstructionError> { + let index_in_trace = *self + .instruction_stack + .get(nesting_level) + .ok_or(InstructionError::CallDepth)?; + let instruction_context = self.get_instruction_context_at_index_in_trace(index_in_trace)?; + debug_assert_eq!(instruction_context.nesting_level, nesting_level); + Ok(instruction_context) + } + + /// Gets the max height of the instruction stack + pub fn get_instruction_stack_capacity(&self) -> usize { + self.instruction_stack_capacity + } + + /// Gets instruction stack height, top-level instructions are height + /// `solana_instruction::TRANSACTION_LEVEL_STACK_HEIGHT` + pub fn get_instruction_stack_height(&self) -> usize { + self.instruction_stack.len() + } + + /// Returns the index in the instruction trace of the current executing instruction + pub fn get_current_instruction_index(&self) -> Result { + self.instruction_stack + .last() + .copied() + .ok_or(InstructionError::CallDepth) + } + + /// Returns a view on the current instruction + pub fn get_current_instruction_context( + &self, + ) -> Result, InstructionError> { + let index_in_trace = self.get_current_instruction_index()?; + self.get_instruction_context_at_index_in_trace(index_in_trace) + } + + /// Returns a view on the next instruction. This function assumes it has already been + /// configured with the correct values in `prepare_next_instruction` or + /// `prepare_next_top_level_instruction` + pub fn get_next_instruction_context( + &self, + ) -> Result, InstructionError> { + let index_in_trace = self + .instruction_trace + .len() + .checked_sub(1) + .ok_or(InstructionError::CallDepth)?; + self.get_instruction_context_at_index_in_trace(index_in_trace) + } + + /// Configures an instruction at a specific index in trace. + pub fn configure_instruction_at_index( + &mut self, + instruction_index: usize, + program_index: IndexOfAccount, + instruction_accounts: Vec, + deduplication_map: Vec, + instruction_data: Cow<'ix_data, [u8]>, + caller_index: Option, + ) -> Result<(), InstructionError> { + debug_assert_eq!(deduplication_map.len(), MAX_ACCOUNTS_PER_TRANSACTION); + + let instruction = self + .instruction_trace + .get_mut(instruction_index) + .ok_or(InstructionError::MaxInstructionTraceLengthExceeded)?; + + // If we have a parent index, then we are dealing with a CPI. + if let Some(caller_index) = caller_index { + self.transaction_frame.total_number_of_instructions_in_trace = self + .transaction_frame + .total_number_of_instructions_in_trace + .saturating_add(1); + instruction.index_of_caller_instruction = caller_index; + } + + self.transaction_frame.cpi_scratchpad = VmSlice::new( + GUEST_INSTRUCTION_DATA_BASE_ADDRESS.saturating_add(GUEST_REGION_SIZE.saturating_mul( + self.transaction_frame.total_number_of_instructions_in_trace as u64, + )), + 0, + ); + + instruction.program_account_index_in_tx = program_index; + instruction.configure_vm_slices( + instruction_index as u64, + instruction_accounts.len(), + instruction_data.len() as u64, + ); + self.deduplication_maps + .push(deduplication_map.into_boxed_slice()); + self.instruction_accounts + .push(instruction_accounts.into_boxed_slice()); + self.instruction_data.push(instruction_data); + Ok(()) + } + + /// For tests only + fn deduplicate_accounts_for_tests(instruction_accounts: &[InstructionAccount]) -> Vec { + let mut dedup_map = vec![u16::MAX; MAX_ACCOUNTS_PER_TRANSACTION]; + for (idx, account) in instruction_accounts.iter().enumerate() { + let index_in_instruction = dedup_map + .get_mut(account.index_in_transaction as usize) + .unwrap(); + if *index_in_instruction == u16::MAX { + *index_in_instruction = idx as u16; + } + } + dedup_map + } + + /// A version of `configure_top_level_instruction` to help creating the deduplication map in tests + pub fn configure_top_level_instruction_for_tests( + &mut self, + program_index: IndexOfAccount, + instruction_accounts: Vec, + instruction_data: Vec, + ) -> Result<(), InstructionError> { + debug_assert!(instruction_accounts.len() <= u16::MAX as usize); + let dedup_map = Self::deduplicate_accounts_for_tests(&instruction_accounts); + + self.configure_instruction_at_index( + self.get_instruction_trace_length(), + program_index, + instruction_accounts, + dedup_map, + Cow::Owned(instruction_data), + None, + )?; + Ok(()) + } + + /// A helper function to facilitate creating a CPI in tests + pub fn configure_next_cpi_for_tests( + &mut self, + program_index: IndexOfAccount, + instruction_accounts: Vec, + instruction_data: Vec, + ) -> Result<(), InstructionError> { + debug_assert!(instruction_accounts.len() <= u16::MAX as usize); + let dedup_map = Self::deduplicate_accounts_for_tests(&instruction_accounts); + let caller_index = self.get_current_instruction_index()?; + let cpi_index = self.get_instruction_trace_length(); + self.configure_instruction_at_index( + cpi_index, + program_index, + instruction_accounts, + dedup_map, + Cow::Owned(instruction_data), + Some(caller_index as u16), + )?; + Ok(()) + } + + /// Pushes the next instruction + pub fn push(&mut self) -> Result<(), InstructionError> { + let nesting_level = self.get_instruction_stack_height(); + if !self.instruction_stack.is_empty() && self.accounts.get_lamports_delta() != 0 { + return Err(InstructionError::UnbalancedInstruction); + } + { + let instruction = self + .instruction_trace + .last_mut() + .ok_or(InstructionError::CallDepth)?; + instruction.nesting_level = nesting_level as u16; + } + let index_in_trace = self.get_instruction_trace_length(); + if index_in_trace >= self.instruction_trace_capacity { + return Err(InstructionError::MaxInstructionTraceLengthExceeded); + } + + let current_top_level_instruction = if self.instruction_stack.is_empty() { + let index = self.next_top_level_instruction_index; + self.next_top_level_instruction_index = + self.next_top_level_instruction_index.saturating_add(1); + index + } else { + self.transaction_frame.number_of_cpis_in_trace = self + .transaction_frame + .number_of_cpis_in_trace + .saturating_add(1); + self.next_top_level_instruction_index.saturating_sub(1) + }; + + self.instruction_trace.push(InstructionFrame::default()); + if nesting_level >= self.instruction_stack_capacity { + return Err(InstructionError::CallDepth); + } + self.transaction_frame.current_executing_instruction = index_in_trace as u16; + self.instruction_stack.push(index_in_trace); + if let Some(index_in_transaction) = self.find_index_of_account(&instructions::id()) { + let mut mut_account_ref = self.accounts.try_borrow_mut(index_in_transaction)?; + if mut_account_ref.owner() != &solana_sdk_ids::sysvar::id() { + return Err(InstructionError::InvalidAccountOwner); + } + instructions::store_current_index_checked( + mut_account_ref.data_as_mut_slice(), + current_top_level_instruction as u16, + )?; + } + Ok(()) + } + + /// Pops the current instruction + pub fn pop(&mut self) -> Result<(), InstructionError> { + if self.instruction_stack.is_empty() { + return Err(InstructionError::CallDepth); + } + // Verify (before we pop) that the total sum of all lamports in this instruction did not change + let detected_an_unbalanced_instruction = + self.get_current_instruction_context() + .and_then(|instruction_context| { + // Verify all executable accounts have no outstanding refs + self.accounts + .try_borrow_mut( + instruction_context.get_index_of_program_account_in_transaction()?, + ) + .map_err(|err| { + if err == InstructionError::AccountBorrowFailed { + InstructionError::AccountBorrowOutstanding + } else { + err + } + })?; + Ok(self.accounts.get_lamports_delta() != 0) + }); + // Always pop, even if we `detected_an_unbalanced_instruction` + self.instruction_stack.pop(); + if let Some(instr_idx) = self.instruction_stack.last() { + self.transaction_frame.current_executing_instruction = *instr_idx as u16; + } + if detected_an_unbalanced_instruction? { + Err(InstructionError::UnbalancedInstruction) + } else { + Ok(()) + } + } + + /// Gets the return data of the current instruction or any above + pub fn get_return_data(&self) -> (&Pubkey, &[u8]) { + ( + &self.transaction_frame.return_data_pubkey, + &self.return_data_bytes, + ) + } + + /// Set the return data of the current instruction + pub fn set_return_data( + &mut self, + program_id: Pubkey, + data: Vec, + ) -> Result<(), InstructionError> { + self.transaction_frame.return_data_pubkey = program_id; + // SAFETY: `return_data_scratchpad` is backed by `self.return_data_bytes` + // and `return_data_bytes` is being reset to `data` + // in the next statement. + unsafe { + self.transaction_frame + .return_data_scratchpad + .set_len(data.len() as u64); + } + self.return_data_bytes = data; + Ok(()) + } + + /// Returns a new account data write access handler + pub fn access_violation_handler( + &self, + stricter_abi_and_runtime_constraints: bool, + account_data_direct_mapping: bool, + ) -> AccessViolationHandler { + let accounts = Rc::clone(&self.accounts); + Box::new( + move |region: &mut MemoryRegion, + address_space_reserved_for_account: u64, + access_type: AccessType, + vm_addr: u64, + len: u64| { + if access_type == AccessType::Load { + return; + } + let Some(index_in_transaction) = region.access_violation_handler_payload else { + // This region is not a writable account. + return; + }; + let requested_length = + vm_addr.saturating_add(len).saturating_sub(region.vm_addr) as usize; + if requested_length > address_space_reserved_for_account as usize { + // Requested access goes further than the account region. + return; + } + + // The four calls below can't really fail. If they fail because of a bug, + // whatever is writing will trigger an EbpfError::AccessViolation like + // if the region was readonly, and the transaction will fail gracefully. + let Ok(mut account) = accounts.try_borrow_mut(index_in_transaction) else { + debug_assert!(false); + return; + }; + if accounts.touch(index_in_transaction).is_err() { + debug_assert!(false); + return; + } + + let remaining_allowed_growth = MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION + .saturating_sub(accounts.resize_delta()) + .max(0) as usize; + + if requested_length > region.len as usize { + // Realloc immediately here to fit the requested access, + // then later in CPI or deserialization realloc again to the + // account length the program stored in AccountInfo. + let old_len = account.data().len(); + let new_len = (address_space_reserved_for_account as usize) + .min(MAX_ACCOUNT_DATA_LEN as usize) + .min(old_len.saturating_add(remaining_allowed_growth)); + // The last two min operations ensure the following: + debug_assert!(accounts.can_data_be_resized(old_len, new_len).is_ok()); + if accounts + .update_accounts_resize_delta(old_len, new_len) + .is_err() + { + return; + } + account.resize(new_len, 0); + region.len = new_len as u64; + } + + // Potentially unshare / make the account shared data unique (CoW logic). + if stricter_abi_and_runtime_constraints && account_data_direct_mapping { + region.host_addr = account.data_as_mut_slice().as_mut_ptr() as u64; + region.writable = true; + } + }, + ) + } + + /// Take ownership of the instruction trace + pub fn take_instruction_trace(&mut self) -> InstructionTrace<'_> { + // The last frame is a placeholder for the next instruction to be executed, so it + // is empty. + self.instruction_trace.pop(); + ( + std::mem::take(&mut self.instruction_trace), + std::mem::take(&mut self.instruction_accounts), + std::mem::take(&mut self.instruction_data), + ) + } + + /// An active instruction is either one that has already finished execution or that is + /// under execution (e.g. all nested CPIs are active). + /// For ABIv2 only. + pub fn number_of_active_instructions_in_trace(&self) -> usize { + self.next_top_level_instruction_index + .saturating_add(self.transaction_frame.number_of_cpis_in_trace as usize) + } + + /// Return next top level instruction to execute + pub fn next_top_level_instruction_index(&self) -> usize { + self.next_top_level_instruction_index + } + + /// Return number of CPIs in instruction trace + pub fn number_of_cpis_in_trace(&self) -> usize { + self.transaction_frame.number_of_cpis_in_trace as usize + } +} + +/// Return data at the end of a transaction +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct TransactionReturnData { + pub program_id: Pubkey, + pub data: Vec, +} + +/// Everything that needs to be recorded from a TransactionContext after execution +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] +pub struct ExecutionRecord { + pub accounts: Vec, + pub return_data: TransactionReturnData, + pub touched_account_count: u64, + pub accounts_resize_delta: i64, +} + +/// Used by the bank in the runtime to write back the processed accounts and recorded instructions +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] +impl From> for ExecutionRecord { + fn from(context: TransactionContext) -> Self { + let (accounts, touched_flags, resize_delta) = Rc::try_unwrap(context.accounts) + .expect("transaction_context.accounts has unexpected outstanding refs") + .take(); + let touched_account_count = touched_flags + .iter() + .fold(0usize, |accumulator, was_touched| { + accumulator.saturating_add(was_touched.get() as usize) + }) as u64; + + let return_data = TransactionReturnData { + program_id: context.transaction_frame.return_data_pubkey, + data: context.return_data_bytes, + }; + + Self { + accounts, + return_data, + touched_account_count, + accounts_resize_delta: Cell::into_inner(resize_delta), + } + } +} + +#[cfg(all(test, not(target_arch = "sbf"), not(target_arch = "bpf")))] +mod tests { + use super::*; + + #[test] + fn test_instructions_sysvar_store_index_checked() { + let build_transaction_context = |account: AccountSharedData| { + TransactionContext::new( + vec![ + (Pubkey::new_unique(), AccountSharedData::default()), + (instructions::id(), account), + ], + Rent::default(), + /* max_instruction_stack_depth */ 2, + /* max_instruction_trace_length */ 2, + /* number_of_top_level_instructions */ 1, + ) + }; + + let correct_space = 2; + let rent_exempt_lamports = Rent::default().minimum_balance(correct_space); + + // First try it with the wrong owner. + let account = + AccountSharedData::new(rent_exempt_lamports, correct_space, &Pubkey::new_unique()); + assert_eq!( + build_transaction_context(account).push(), + Err(InstructionError::InvalidAccountOwner), + ); + + // Now with the wrong data length. + let account = + AccountSharedData::new(rent_exempt_lamports, 0, &solana_sdk_ids::sysvar::id()); + assert_eq!( + build_transaction_context(account).push(), + Err(InstructionError::AccountDataTooSmall), + ); + + // Finally provide the correct account setup. + let account = AccountSharedData::new( + rent_exempt_lamports, + correct_space, + &solana_sdk_ids::sysvar::id(), + ); + assert_eq!(build_transaction_context(account).push(), Ok(()),); + } + + #[test] + fn test_invalid_native_loader_index() { + let mut transaction_context = TransactionContext::new( + vec![( + Pubkey::new_unique(), + AccountSharedData::new(1, 1, &Pubkey::new_unique()), + )], + Rent::default(), + 20, + 20, + 1, + ); + + transaction_context + .configure_top_level_instruction_for_tests( + u16::MAX, + vec![InstructionAccount::new(0, false, false)], + vec![], + ) + .unwrap(); + let instruction_context = transaction_context.get_next_instruction_context().unwrap(); + + let result = instruction_context.get_index_of_program_account_in_transaction(); + assert_eq!(result, Err(InstructionError::MissingAccount)); + + let result = instruction_context.get_program_key(); + assert_eq!(result, Err(InstructionError::MissingAccount)); + + let result = instruction_context.get_program_owner(); + assert_eq!(result.err(), Some(InstructionError::MissingAccount)); + } + + #[test] + fn test_instruction_shared_items() { + let transaction_accounts = vec![(Pubkey::new_unique(), AccountSharedData::default()); 10]; + let mut transaction_context = + TransactionContext::new(transaction_accounts, Rent::default(), 20, 20, 3); + + let instruction_accounts_1 = vec![ + InstructionAccount::new(0, false, true), + InstructionAccount::new(3, true, false), + ]; + transaction_context + .configure_top_level_instruction_for_tests( + 1, + instruction_accounts_1.clone(), + vec![1, 2, 3, 4], + ) + .unwrap(); + transaction_context.push().unwrap(); + + let instruction_accounts_2 = vec![ + InstructionAccount::new(0, false, true), + InstructionAccount::new(3, true, false), + InstructionAccount::new(5, false, false), + ]; + transaction_context + .configure_top_level_instruction_for_tests( + 1, + instruction_accounts_2.clone(), + vec![5, 6, 7, 8, 9], + ) + .unwrap(); + transaction_context.push().unwrap(); + + let instruction_accounts_3 = vec![ + InstructionAccount::new(0, false, true), + InstructionAccount::new(3, true, false), + InstructionAccount::new(5, false, false), + InstructionAccount::new(3, false, false), + InstructionAccount::new(10, false, false), + ]; + transaction_context + .configure_top_level_instruction_for_tests( + 1, + instruction_accounts_3.clone(), + vec![10, 11], + ) + .unwrap(); + transaction_context.push().unwrap(); + + let first_ix_context = transaction_context + .get_instruction_context_at_index_in_trace(0) + .unwrap(); + assert_eq!( + instruction_accounts_1.as_slice(), + first_ix_context.instruction_accounts + ); + assert_eq!( + *first_ix_context.instruction_data, + **transaction_context.instruction_data.first().unwrap() + ); + for (idx_in_ix, acc) in instruction_accounts_1.iter().enumerate() { + assert_eq!( + *first_ix_context + .dedup_map + .get(acc.index_in_transaction as usize) + .unwrap(), + idx_in_ix as u16 + ); + } + + let second_ix_context = transaction_context + .get_instruction_context_at_index_in_trace(1) + .unwrap(); + assert_eq!( + instruction_accounts_2.as_slice(), + second_ix_context.instruction_accounts + ); + assert_eq!( + *second_ix_context.instruction_data, + **transaction_context.instruction_data.get(1).unwrap() + ); + for (idx_in_ix, acc) in instruction_accounts_2.iter().enumerate() { + assert_eq!( + *second_ix_context + .dedup_map + .get(acc.index_in_transaction as usize) + .unwrap(), + idx_in_ix as u16 + ); + } + + let third_ix_context = transaction_context + .get_instruction_context_at_index_in_trace(2) + .unwrap(); + assert_eq!( + instruction_accounts_3.as_slice(), + third_ix_context.instruction_accounts + ); + assert_eq!( + *third_ix_context.instruction_data, + **transaction_context.instruction_data.get(2).unwrap() + ); + for (idx_in_ix, acc) in instruction_accounts_3.iter().enumerate() { + if idx_in_ix == 3 { + assert_eq!( + *third_ix_context + .dedup_map + .get(acc.index_in_transaction as usize) + .unwrap(), + 1 + ); + } else { + assert_eq!( + *third_ix_context + .dedup_map + .get(acc.index_in_transaction as usize) + .unwrap(), + idx_in_ix as u16 + ); + } + } + } + + #[test] + fn test_number_of_instructions() { + let transaction_accounts = vec![(Pubkey::new_unique(), AccountSharedData::default()); 3]; + let mut transaction_context = + TransactionContext::new(transaction_accounts, Rent::default(), 20, 20, 3); + assert_eq!( + transaction_context + .transaction_frame + .total_number_of_instructions_in_trace, + 3 + ); + assert_eq!( + transaction_context + .transaction_frame + .number_of_cpis_in_trace, + 0 + ); + + transaction_context + .configure_instruction_at_index( + 0, + 0, + vec![InstructionAccount::new(1, false, false)], + vec![0; MAX_ACCOUNTS_PER_TRANSACTION], + Vec::new().into(), + None, + ) + .unwrap(); + transaction_context.push().unwrap(); + assert_eq!( + transaction_context + .transaction_frame + .current_executing_instruction, + 0 + ); + transaction_context.pop().unwrap(); + assert_eq!( + transaction_context + .transaction_frame + .total_number_of_instructions_in_trace, + 3 + ); + assert_eq!( + transaction_context + .transaction_frame + .number_of_cpis_in_trace, + 0 + ); + + transaction_context + .configure_instruction_at_index( + 1, + 0, + vec![InstructionAccount::new(1, false, false)], + vec![0; MAX_ACCOUNTS_PER_TRANSACTION], + Vec::new().into(), + None, + ) + .unwrap(); + transaction_context.push().unwrap(); + assert_eq!( + transaction_context + .transaction_frame + .current_executing_instruction, + 1 + ); + assert_eq!( + transaction_context.transaction_frame.cpi_scratchpad.ptr(), + GUEST_INSTRUCTION_DATA_BASE_ADDRESS.saturating_add(GUEST_REGION_SIZE.saturating_mul(3)) + ); + assert_eq!( + transaction_context.transaction_frame.cpi_scratchpad.len(), + 0, + ); + + transaction_context + .configure_next_cpi_for_tests(0, vec![InstructionAccount::new(2, false, true)], vec![]) + .unwrap(); + assert_eq!( + transaction_context + .transaction_frame + .total_number_of_instructions_in_trace, + 4 + ); + assert_eq!( + transaction_context + .transaction_frame + .number_of_cpis_in_trace, + 0 + ); + transaction_context.push().unwrap(); + assert_eq!( + transaction_context + .transaction_frame + .current_executing_instruction, + 2 + ); + assert_eq!( + transaction_context.transaction_frame.cpi_scratchpad.ptr(), + GUEST_INSTRUCTION_DATA_BASE_ADDRESS.saturating_add(GUEST_REGION_SIZE.saturating_mul(4)) + ); + assert_eq!( + transaction_context.transaction_frame.cpi_scratchpad.len(), + 0, + ); + + transaction_context.pop().unwrap(); + assert_eq!( + transaction_context + .transaction_frame + .total_number_of_instructions_in_trace, + 4 + ); + assert_eq!( + transaction_context + .transaction_frame + .number_of_cpis_in_trace, + 1 + ); + assert_eq!( + transaction_context + .transaction_frame + .current_executing_instruction, + 1 + ); + transaction_context.pop().unwrap(); + + assert_eq!( + transaction_context + .transaction_frame + .total_number_of_instructions_in_trace, + 4 + ); + assert_eq!( + transaction_context + .transaction_frame + .number_of_cpis_in_trace, + 1 + ); + } + + #[test] + fn test_get_current_instruction_index() { + let transaction_accounts = vec![(Pubkey::new_unique(), AccountSharedData::default()); 3]; + let mut transaction_context = + TransactionContext::new(transaction_accounts, Rent::default(), 20, 20, 3); + + // First top level instruction + transaction_context + .configure_instruction_at_index( + 0, + 1, + vec![ + InstructionAccount::new(0, false, false), + InstructionAccount::new(1, false, false), + ], + vec![u16::MAX; 256], + Cow::Owned(Vec::new()), + None, + ) + .unwrap(); + transaction_context.push().unwrap(); + assert_eq!( + transaction_context.get_current_instruction_index().unwrap(), + 0 + ); + transaction_context.pop().unwrap(); + + // Second top-level instruction + transaction_context + .configure_instruction_at_index( + 1, + 1, + vec![ + InstructionAccount::new(0, false, false), + InstructionAccount::new(1, false, true), + ], + vec![u16::MAX; 256], + Cow::Owned(Vec::new()), + None, + ) + .unwrap(); + transaction_context.push().unwrap(); + assert_eq!( + transaction_context.get_current_instruction_index().unwrap(), + 1 + ); + + // Simulating a CPI + transaction_context + .configure_next_cpi_for_tests( + 1, + vec![ + InstructionAccount::new(0, false, true), + InstructionAccount::new(1, false, false), + ], + Vec::new(), + ) + .unwrap(); + transaction_context.push().unwrap(); + assert_eq!( + transaction_context.get_current_instruction_index().unwrap(), + 2 + ); + + // Yet another CPI + transaction_context + .configure_next_cpi_for_tests( + 1, + vec![ + InstructionAccount::new(0, false, true), + InstructionAccount::new(1, false, false), + ], + Vec::new(), + ) + .unwrap(); + transaction_context.push().unwrap(); + assert_eq!( + transaction_context.get_current_instruction_index().unwrap(), + 3 + ); + + // CPI return + transaction_context.pop().unwrap(); + assert_eq!( + transaction_context.get_current_instruction_index().unwrap(), + 2 + ); + + // CPI return 2 + transaction_context.pop().unwrap(); + assert_eq!( + transaction_context.get_current_instruction_index().unwrap(), + 1 + ); + } +} diff --git a/transaction-context/src/transaction_accounts.rs b/transaction-context/src/transaction_accounts.rs index fa92945e..d5c8a201 100644 --- a/transaction-context/src/transaction_accounts.rs +++ b/transaction-context/src/transaction_accounts.rs @@ -30,12 +30,14 @@ struct AccountSharedFields { } #[derive(Debug, PartialEq)] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] struct AccountPrivateFields { rent_epoch: u64, executable: bool, payload: Arc>, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl AccountPrivateFields { fn payload_len(&self) -> usize { self.payload.len() @@ -43,11 +45,13 @@ impl AccountPrivateFields { } #[derive(Debug, PartialEq)] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] pub struct TransactionAccountView<'a> { abi_account: &'a AccountSharedFields, private_fields: &'a AccountPrivateFields, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl ReadableAccount for TransactionAccountView<'_> { fn lamports(&self) -> u64 { self.abi_account.lamports @@ -70,6 +74,7 @@ impl ReadableAccount for TransactionAccountView<'_> { } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl PartialEq for TransactionAccountView<'_> { fn eq(&self, other: &AccountSharedData) -> bool { other.lamports() == self.lamports() @@ -81,11 +86,13 @@ impl PartialEq for TransactionAccountView<'_> { } #[derive(Debug)] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] pub struct TransactionAccountViewMut<'a> { abi_account: &'a mut AccountSharedFields, private_fields: &'a mut AccountPrivateFields, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl TransactionAccountViewMut<'_> { fn data_mut(&mut self) -> &mut Vec { Arc::make_mut(&mut self.private_fields.payload) @@ -172,6 +179,7 @@ impl TransactionAccountViewMut<'_> { } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl ReadableAccount for TransactionAccountViewMut<'_> { fn lamports(&self) -> u64 { self.abi_account.lamports @@ -194,6 +202,7 @@ impl ReadableAccount for TransactionAccountViewMut<'_> { } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl WritableAccount for TransactionAccountViewMut<'_> { fn set_lamports(&mut self, lamports: u64) { self.abi_account.lamports = lamports; @@ -231,22 +240,25 @@ impl WritableAccount for TransactionAccountViewMut<'_> { } /// An account key and the matching account +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] pub type KeyedAccountSharedData = (Pubkey, AccountSharedData); +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] pub(crate) type DeconstructedTransactionAccounts = (Vec, Box<[Cell]>, Cell); #[derive(Debug)] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] pub struct TransactionAccounts { - shared_account_fields: UnsafeCell>, - private_account_fields: UnsafeCell>, + shared_account_fields: Box<[UnsafeCell]>, + private_account_fields: Box<[UnsafeCell]>, borrow_counters: Box<[BorrowCounter]>, touched_flags: Box<[Cell]>, resize_delta: Cell, lamports_delta: Cell, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl TransactionAccounts { - #[cfg(not(target_os = "solana"))] pub(crate) fn new(accounts: Vec) -> TransactionAccounts { let touched_flags = vec![Cell::new(false); accounts.len()].into_boxed_slice(); let borrow_counters = vec![BorrowCounter::default(); accounts.len()].into_boxed_slice(); @@ -255,7 +267,7 @@ impl TransactionAccounts { .enumerate() .map(|(idx, item)| { ( - AccountSharedFields { + UnsafeCell::new(AccountSharedFields { key: item.0, owner: *item.1.owner(), lamports: item.1.lamports(), @@ -264,19 +276,22 @@ impl TransactionAccounts { .saturating_add(GUEST_REGION_SIZE.saturating_mul(idx as u64)), item.1.data().len() as u64, ), - }, - AccountPrivateFields { + }), + UnsafeCell::new(AccountPrivateFields { rent_epoch: item.1.rent_epoch(), executable: item.1.executable(), payload: item.1.data_clone(), - }, + }), ) }) - .collect::<(Vec, Vec)>(); + .collect::<( + Vec>, + Vec>, + )>(); TransactionAccounts { - shared_account_fields: UnsafeCell::new(shared_accounts.into_boxed_slice()), - private_account_fields: UnsafeCell::new(private_fields.into_boxed_slice()), + shared_account_fields: shared_accounts.into_boxed_slice(), + private_account_fields: private_fields.into_boxed_slice(), borrow_counters, touched_flags, resize_delta: Cell::new(0), @@ -285,24 +300,9 @@ impl TransactionAccounts { } pub(crate) fn len(&self) -> usize { - // RUST UPGRADE NOTE - // - // Rust 1.87.0 reports a `needless_borrow` warning - // Rust 1.88.0 reports a `dangerous_implicit_autorefs` warning if the - // recommendation given from Rust 1.87.0 is applied - // - // In order to facilitate upgrading to Rust >= 1.88.0, use the 1.88.0 - // suggestion and ignore the warning given by 1.87.0. This comment and - // the `#[allow(clippy::needless_borrow)]` will be removed after the - // Rust version has advanced - #[allow(clippy::needless_borrow)] - // SAFETY: The borrow is local to this function and is only reading length. - unsafe { - (&(*self.shared_account_fields.get())).len() - } + self.shared_account_fields.len() } - #[cfg(not(target_os = "solana"))] pub fn touch(&self, index: IndexOfAccount) -> Result<(), InstructionError> { self.touched_flags .get(index as usize) @@ -353,22 +353,23 @@ impl TransactionAccounts { .ok_or(InstructionError::MissingAccount)?; borrow_counter.try_borrow_mut()?; - // See previous RUST UPGRADE NOTE in this file - #[allow(clippy::needless_borrow)] // SAFETY: The borrow counter guarantees this is the only mutable borrow of this account. // The unwrap is safe because accounts.len() == borrow_counters.len(), so the missing // account error should have been returned above. let svm_account = unsafe { - (&mut (*self.shared_account_fields.get())) - .get_mut(index as usize) + &mut *self + .shared_account_fields + .get(index as usize) .unwrap() + .get() }; - // See previous RUST UPGRADE NOTE in this file - #[allow(clippy::needless_borrow)] + let private_fields = unsafe { - (&mut (*self.private_account_fields.get())) - .get_mut(index as usize) + &mut *self + .private_account_fields + .get(index as usize) .unwrap() + .get() }; let account = TransactionAccountViewMut { @@ -389,22 +390,23 @@ impl TransactionAccounts { .ok_or(InstructionError::MissingAccount)?; borrow_counter.try_borrow()?; - // See previous RUST UPGRADE NOTE in this file - #[allow(clippy::needless_borrow)] // SAFETY: The borrow counter guarantees there are no mutable borrow of this account. // The unwrap is safe because accounts.len() == borrow_counters.len(), so the missing // account error should have been returned above. let svm_account = unsafe { - (&(*self.shared_account_fields.get())) + &*self + .shared_account_fields .get(index as usize) .unwrap() + .get() }; - // See previous RUST UPGRADE NOTE in this file - #[allow(clippy::needless_borrow)] + let private_fields = unsafe { - (&(*self.private_account_fields.get())) + &*self + .private_account_fields .get(index as usize) .unwrap() + .get() }; let account = TransactionAccountView { @@ -433,11 +435,14 @@ impl TransactionAccounts { } fn deconstruct_into_keyed_account_shared_data(&mut self) -> Vec { - self.shared_account_fields - .get_mut() + let shared_account_fields = std::mem::take(&mut self.shared_account_fields); + let private_account_fields = std::mem::take(&mut self.private_account_fields); + shared_account_fields .into_iter() - .zip(&mut *self.private_account_fields.get_mut()) - .map(|(shared_fields, private_fields)| { + .zip(private_account_fields) + .map(|(shared_fields_cell, private_fields_cell)| { + let shared_fields = shared_fields_cell.into_inner(); + let private_fields = private_fields_cell.into_inner(); ( shared_fields.key, AccountSharedData::create_from_existing_shared_data( @@ -453,11 +458,14 @@ impl TransactionAccounts { } pub(crate) fn deconstruct_into_account_shared_data(&mut self) -> Vec { - self.shared_account_fields - .get_mut() + let shared_account_fields = std::mem::take(&mut self.shared_account_fields); + let private_account_fields = std::mem::take(&mut self.private_account_fields); + shared_account_fields .into_iter() - .zip(&mut *self.private_account_fields.get_mut()) - .map(|(shared_fields, private_fields)| { + .zip(private_account_fields) + .map(|(shared_fields_cell, private_fields_cell)| { + let shared_fields = shared_fields_cell.into_inner(); + let private_fields = private_fields_cell.into_inner(); AccountSharedData::create_from_existing_shared_data( shared_fields.lamports, private_fields.payload.clone(), @@ -479,31 +487,31 @@ impl TransactionAccounts { } pub(crate) fn account_key(&self, index: IndexOfAccount) -> Option<&Pubkey> { - // See previous RUST UPGRADE NOTE in this file - #[allow(clippy::needless_borrow)] // SAFETY: We never modify an account key, so returning a reference to it is safe. unsafe { - (&(*self.shared_account_fields.get())) + self.shared_account_fields .get(index as usize) - .map(|acc| &acc.key) + .map(|acc| &(*acc.get()).key) } } pub(crate) fn account_keys_iter(&self) -> impl Iterator { // SAFETY: We never modify account keys, so returning an immutable reference to them is safe. unsafe { - (*self.shared_account_fields.get()) + self.shared_account_fields .iter() - .map(|item| &item.key) + .map(|item| &(*item.get()).key) } } } #[derive(Default, Debug, Clone)] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] struct BorrowCounter { counter: Cell, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl BorrowCounter { #[inline] fn is_writing(&self) -> bool { @@ -551,17 +559,20 @@ impl BorrowCounter { } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] pub struct AccountRef<'a> { account: TransactionAccountView<'a>, borrow_counter: &'a BorrowCounter, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl Drop for AccountRef<'_> { fn drop(&mut self) { self.borrow_counter.release_borrow(); } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl<'a> Deref for AccountRef<'a> { type Target = TransactionAccountView<'a>; fn deref(&self) -> &Self::Target { @@ -570,11 +581,13 @@ impl<'a> Deref for AccountRef<'a> { } #[derive(Debug)] +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] pub struct AccountRefMut<'a> { account: TransactionAccountViewMut<'a>, borrow_counter: &'a BorrowCounter, } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl Drop for AccountRefMut<'_> { fn drop(&mut self) { // SAFETY: We are synchronizing the lengths. @@ -588,6 +601,7 @@ impl Drop for AccountRefMut<'_> { } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl<'a> Deref for AccountRefMut<'a> { type Target = TransactionAccountViewMut<'a>; fn deref(&self) -> &Self::Target { @@ -595,13 +609,14 @@ impl<'a> Deref for AccountRefMut<'a> { } } +#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))] impl DerefMut for AccountRefMut<'_> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.account } } -#[cfg(test)] +#[cfg(all(test, not(target_arch = "sbf"), not(target_arch = "bpf")))] mod tests { use { crate::transaction_accounts::TransactionAccounts, solana_account::AccountSharedData, diff --git a/type-overrides/src/lib.rs b/type-overrides/src/lib.rs index 893cf5ea..d4d472f4 100644 --- a/type-overrides/src/lib.rs +++ b/type-overrides/src/lib.rs @@ -25,7 +25,7 @@ pub mod hint { pub mod rand { pub use rand::*; #[cfg(feature = "shuttle-test")] - pub use shuttle::rand::{thread_rng as rng, Rng, RngCore}; + pub use shuttle::rand::{Rng, RngCore, thread_rng as rng}; } pub mod sync {