diff --git a/Cargo.lock b/Cargo.lock index ee042b0..4337b89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,9 +25,9 @@ checksum = "2733340e0429d146d4b77d265ae80b22e253507b30a2257ff68eccb78eab210b" dependencies = [ "ahash", "solana-epoch-schedule", - "solana-hash", + "solana-hash 2.3.0", "solana-pubkey", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", "solana-svm-feature-set", ] @@ -1152,6 +1152,15 @@ dependencies = [ "five8_core", ] +[[package]] +name = "five8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" +dependencies = [ + "five8_core", +] + [[package]] name = "five8_const" version = "0.1.4" @@ -1161,6 +1170,15 @@ dependencies = [ "five8_core", ] +[[package]] +name = "five8_const" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core", +] + [[package]] name = "five8_core" version = "0.1.2" @@ -2096,14 +2114,14 @@ dependencies = [ "solana-compute-budget", "solana-epoch-rewards", "solana-epoch-schedule", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-loader-v3-interface 3.0.0", "solana-loader-v4-interface", "solana-log-collector", "solana-logger", "solana-precompile-error", - "solana-program-error", + "solana-program-error 2.2.1", "solana-program-runtime", "solana-pubkey", "solana-rent", @@ -2149,7 +2167,7 @@ checksum = "ed0bb72e20d0f2429eeb8a4bbc85d95a0ac7e042c415b56494069cef26a70cca" dependencies = [ "solana-account", "solana-instruction", - "solana-program-error", + "solana-program-error 2.2.1", "solana-pubkey", "solana-rent", ] @@ -2495,28 +2513,25 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinocchio" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "530596fa307103e53257f2cf064815919ee7fbc4c7ab999f6f13cc7067c3aff1" - -[[package]] -name = "pinocchio-pubkey" -version = "0.2.4" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b20fcebc172c3cd3f54114b0241b48fa8e30893ced2eb4927aaba5e3a0ba5" +checksum = "d707cea2843c1a2fd8ec49e4116ce3fdaedcd552a3ee168b03ce60e627fc0f62" dependencies = [ - "five8_const", - "pinocchio", + "solana-account-view", + "solana-address", + "solana-define-syscall 5.1.0", + "solana-instruction-view", + "solana-program-error 3.0.1", ] [[package]] name = "pinocchio-system" -version = "0.2.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f75423420ae70aa748cf611cab14cfd00af08d0d2d3d258cb0cf5e2880ec19c" +checksum = "f3ae2ee67b42e2ac797dd88312da473c895660e270d8093e0ba2749b885b5778" dependencies = [ "pinocchio", - "pinocchio-pubkey", + "solana-address", ] [[package]] @@ -3256,6 +3271,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" @@ -3377,11 +3398,35 @@ checksum = "c8f5152a288ef1912300fc6efa6c2d1f9bb55d9398eb6c72326360b8063987da" dependencies = [ "bincode", "serde", - "solana-program-error", + "solana-program-error 2.2.1", "solana-program-memory", "solana-pubkey", ] +[[package]] +name = "solana-account-view" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc141b940560430425ebaadb7645496c45f6a10fad9911d719bd03eab7f4d422" +dependencies = [ + "solana-address", + "solana-program-error 3.0.1", +] + +[[package]] +name = "solana-address" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1384b52c435a750cc9c538760fc7bb472fd78e65a9900a2d07312c5bb335b72" +dependencies = [ + "five8 1.0.0", + "five8_const 1.0.0", + "sha2-const-stable", + "solana-define-syscall 5.1.0", + "solana-program-error 3.0.1", + "solana-sha256-hasher 3.1.0", +] + [[package]] name = "solana-address-lookup-table-interface" version = "2.2.2" @@ -3416,7 +3461,7 @@ checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" dependencies = [ "num-bigint 0.4.6", "num-traits", - "solana-define-syscall", + "solana-define-syscall 2.3.0", ] [[package]] @@ -3437,8 +3482,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" dependencies = [ "blake3", - "solana-define-syscall", - "solana-hash", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", "solana-sanitize", ] @@ -3453,7 +3498,7 @@ dependencies = [ "ark-ff", "ark-serialize", "bytemuck", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "thiserror 2.0.12", ] @@ -3487,7 +3532,7 @@ dependencies = [ "solana-clock", "solana-cpi", "solana-curve25519", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-keccak-hasher", "solana-loader-v3-interface 5.0.0", @@ -3502,7 +3547,7 @@ dependencies = [ "solana-sbpf", "solana-sdk-ids", "solana-secp256k1-recover", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", "solana-stable-layout", "solana-svm-feature-set", "solana-system-interface", @@ -3535,7 +3580,7 @@ dependencies = [ "solana-commitment-config", "solana-connection-cache", "solana-epoch-info", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-keypair", "solana-measure", @@ -3569,7 +3614,7 @@ dependencies = [ "solana-account", "solana-commitment-config", "solana-epoch-info", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-keypair", "solana-message", @@ -3602,7 +3647,7 @@ checksum = "7ace9fea2daa28354d107ea879cff107181d85cd4e0f78a2bedb10e1a428c97e" dependencies = [ "serde", "serde_derive", - "solana-hash", + "solana-hash 2.3.0", ] [[package]] @@ -3668,9 +3713,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" dependencies = [ "solana-account-info", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "solana-instruction", - "solana-program-error", + "solana-program-error 2.2.1", "solana-pubkey", "solana-stable-layout", ] @@ -3684,7 +3729,7 @@ dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "subtle", "thiserror 2.0.12", ] @@ -3704,6 +3749,18 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" +[[package]] +name = "solana-define-syscall" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" + +[[package]] +name = "solana-define-syscall" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e14a4f604117f379840956a8fc8695e4c84f5b0ebed192f31f60d9b85d581d" + [[package]] name = "solana-derivation-path" version = "2.2.1" @@ -3748,7 +3805,7 @@ checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" dependencies = [ "serde", "serde_derive", - "solana-hash", + "solana-hash 2.3.0", "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", @@ -3761,7 +3818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c5fd2662ae7574810904585fd443545ed2b568dbd304b25a31e79ccc76e81b" dependencies = [ "siphasher 0.3.11", - "solana-hash", + "solana-hash 2.3.0", "solana-pubkey", ] @@ -3788,7 +3845,7 @@ dependencies = [ "serde_derive", "solana-address-lookup-table-interface", "solana-clock", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-keccak-hasher", "solana-message", @@ -3811,7 +3868,7 @@ dependencies = [ "solana-account", "solana-account-info", "solana-instruction", - "solana-program-error", + "solana-program-error 2.2.1", "solana-pubkey", "solana-rent", "solana-sdk-ids", @@ -3827,9 +3884,9 @@ dependencies = [ "ahash", "lazy_static", "solana-epoch-schedule", - "solana-hash", + "solana-hash 2.3.0", "solana-pubkey", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", ] [[package]] @@ -3871,7 +3928,7 @@ dependencies = [ "solana-cluster-type", "solana-epoch-schedule", "solana-fee-calculator", - "solana-hash", + "solana-hash 2.3.0", "solana-inflation", "solana-keypair", "solana-logger", @@ -3880,7 +3937,7 @@ dependencies = [ "solana-pubkey", "solana-rent", "solana-sdk-ids", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", "solana-shred-version", "solana-signer", "solana-time-utils", @@ -3905,7 +3962,7 @@ dependencies = [ "borsh 1.5.7", "bytemuck", "bytemuck_derive", - "five8", + "five8 0.2.1", "js-sys", "serde", "serde_derive", @@ -3914,6 +3971,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "solana-hash" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b113239362cee7093bfb250467138f079a2a03673181dc15bff6ccd677912d" + [[package]] name = "solana-inflation" version = "2.2.1" @@ -3937,11 +4000,23 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "solana-pubkey", "wasm-bindgen", ] +[[package]] +name = "solana-instruction-view" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab7a27d0c4214b9f7389c3dd00b68c93093a67f1dcc5b7893aebe299bbcbb47" +dependencies = [ + "solana-account-view", + "solana-address", + "solana-define-syscall 5.1.0", + "solana-program-error 3.0.1", +] + [[package]] name = "solana-instructions-sysvar" version = "2.2.2" @@ -3951,7 +4026,7 @@ dependencies = [ "bitflags", "solana-account-info", "solana-instruction", - "solana-program-error", + "solana-program-error 2.2.1", "solana-pubkey", "solana-sanitize", "solana-sdk-ids", @@ -3966,8 +4041,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" dependencies = [ "sha3", - "solana-define-syscall", - "solana-hash", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", "solana-sanitize", ] @@ -4101,7 +4176,7 @@ dependencies = [ "serde", "serde_derive", "solana-bincode", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-pubkey", "solana-sanitize", @@ -4123,7 +4198,7 @@ dependencies = [ "log", "reqwest", "solana-cluster-type", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", "solana-time-utils", "thiserror 2.0.12", ] @@ -4134,7 +4209,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" dependencies = [ - "solana-define-syscall", + "solana-define-syscall 2.3.0", ] [[package]] @@ -4173,9 +4248,9 @@ dependencies = [ "serde", "serde_derive", "solana-fee-calculator", - "solana-hash", + "solana-hash 2.3.0", "solana-pubkey", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", ] [[package]] @@ -4185,7 +4260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde971a20b8dbf60144d6a84439dda86b5466e00e2843091fe731083cda614da" dependencies = [ "solana-account", - "solana-hash", + "solana-hash 2.3.0", "solana-nonce", "solana-sdk-ids", ] @@ -4197,11 +4272,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b526398ade5dea37f1f147ce55dae49aa017a5d7326606359b0445ca8d946581" dependencies = [ "num_enum", - "solana-hash", + "solana-hash 2.3.0", "solana-packet", "solana-pubkey", "solana-sanitize", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", "solana-signature", "solana-signer", ] @@ -4240,7 +4315,7 @@ dependencies = [ "rand 0.8.5", "rayon", "serde", - "solana-hash", + "solana-hash 2.3.0", "solana-message", "solana-metrics", "solana-packet", @@ -4270,7 +4345,7 @@ checksum = "65143c77c1d4864c05e238f25b7d41b5a14b4d56352afab38fe89d97a78fff7f" dependencies = [ "ark-bn254", "light-poseidon", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "thiserror 2.0.12", ] @@ -4347,13 +4422,13 @@ dependencies = [ "solana-clock", "solana-cpi", "solana-decode-error", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "solana-epoch-rewards", "solana-epoch-schedule", "solana-example-mocks", "solana-feature-gate-interface", "solana-fee-calculator", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-instructions-sysvar", "solana-keccak-hasher", @@ -4366,7 +4441,7 @@ dependencies = [ "solana-native-token", "solana-nonce", "solana-program-entrypoint", - "solana-program-error", + "solana-program-error 2.2.1", "solana-program-memory", "solana-program-option", "solana-program-pack", @@ -4378,7 +4453,7 @@ dependencies = [ "solana-secp256k1-recover", "solana-serde-varint", "solana-serialize-utils", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", "solana-short-vec", "solana-slot-hashes", "solana-slot-history", @@ -4400,7 +4475,7 @@ checksum = "473ffe73c68d93e9f2aa726ad2985fe52760052709aaab188100a42c618060ec" dependencies = [ "solana-account-info", "solana-msg", - "solana-program-error", + "solana-program-error 2.2.1", "solana-pubkey", ] @@ -4420,6 +4495,21 @@ dependencies = [ "solana-pubkey", ] +[[package]] +name = "solana-program-error" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f04fa578707b3612b095f0c8e19b66a1233f7c42ca8082fcb3b745afcc0add6" + +[[package]] +name = "solana-program-log" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26115ff9ec592bb4407379c82e7f00b9d0ae4e3fac80c3fd28c932aec852dc6" +dependencies = [ + "solana-define-syscall 4.0.1", +] + [[package]] name = "solana-program-memory" version = "2.2.1" @@ -4427,7 +4517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b0268f6c89825fb634a34bd0c3b8fdaeaecfc3728be1d622a8ee6dd577b60d4" dependencies = [ "num-traits", - "solana-define-syscall", + "solana-define-syscall 2.3.0", ] [[package]] @@ -4442,7 +4532,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" dependencies = [ - "solana-program-error", + "solana-program-error 2.2.1", ] [[package]] @@ -4464,7 +4554,7 @@ dependencies = [ "solana-epoch-rewards", "solana-epoch-schedule", "solana-fee-structure", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-last-restart-slot", "solana-log-collector", @@ -4499,8 +4589,8 @@ dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", - "five8", - "five8_const", + "five8 0.2.1", + "five8_const 0.1.4", "getrandom 0.2.15", "js-sys", "num-traits", @@ -4509,9 +4599,9 @@ dependencies = [ "serde_derive", "solana-atomic-u64", "solana-decode-error", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "solana-sanitize", - "solana-sha256-hasher", + "solana-sha256-hasher 2.2.1", "wasm-bindgen", ] @@ -4678,7 +4768,7 @@ dependencies = [ "solana-epoch-info", "solana-epoch-schedule", "solana-feature-gate-interface", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-message", "solana-pubkey", @@ -4722,7 +4812,7 @@ checksum = "582f8b6b0404d6dca8064ebfefd310c1d183d33a018a89844e82ef0c28824671" dependencies = [ "solana-account", "solana-commitment-config", - "solana-hash", + "solana-hash 2.3.0", "solana-message", "solana-nonce", "solana-pubkey", @@ -4898,7 +4988,7 @@ checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" dependencies = [ "borsh 1.5.7", "libsecp256k1", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "thiserror 2.0.12", ] @@ -4978,8 +5068,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" dependencies = [ "sha2 0.10.8", - "solana-define-syscall", - "solana-hash", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", +] + +[[package]] +name = "solana-sha256-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall 4.0.1", + "solana-hash 4.3.0", ] [[package]] @@ -4998,8 +5099,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afd3db0461089d1ad1a78d9ba3f15b563899ca2386351d38428faa5350c60a98" dependencies = [ "solana-hard-forks", - "solana-hash", - "solana-sha256-hasher", + "solana-hash 2.3.0", + "solana-sha256-hasher 2.2.1", ] [[package]] @@ -5009,7 +5110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64c8ec8e657aecfc187522fc67495142c12f35e55ddeca8698edbb738b8dbd8c" dependencies = [ "ed25519-dalek", - "five8", + "five8 0.2.1", "rand 0.8.5", "serde", "serde-big-array", @@ -5036,7 +5137,7 @@ checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" dependencies = [ "serde", "serde_derive", - "solana-hash", + "solana-hash 2.3.0", "solana-sdk-ids", "solana-sysvar-id", ] @@ -5079,7 +5180,7 @@ dependencies = [ "solana-cpi", "solana-decode-error", "solana-instruction", - "solana-program-error", + "solana-program-error 2.2.1", "solana-pubkey", "solana-system-interface", "solana-sysvar-id", @@ -5198,7 +5299,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd98a25e5bcba8b6be8bcbb7b84b24c2a6a8178d7fb0e3077a916855ceba91a" dependencies = [ - "solana-hash", + "solana-hash 2.3.0", "solana-keypair", "solana-message", "solana-pubkey", @@ -5222,16 +5323,16 @@ dependencies = [ "serde_derive", "solana-account-info", "solana-clock", - "solana-define-syscall", + "solana-define-syscall 2.3.0", "solana-epoch-rewards", "solana-epoch-schedule", "solana-fee-calculator", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-instructions-sysvar", "solana-last-restart-slot", "solana-program-entrypoint", - "solana-program-error", + "solana-program-error 2.2.1", "solana-program-memory", "solana-pubkey", "solana-rent", @@ -5269,7 +5370,7 @@ dependencies = [ "solana-commitment-config", "solana-connection-cache", "solana-epoch-info", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-keypair", "solana-message", @@ -5358,7 +5459,7 @@ dependencies = [ "serde_derive", "solana-bincode", "solana-feature-set", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-keypair", "solana-message", @@ -5501,7 +5602,7 @@ dependencies = [ "serde_derive", "solana-clock", "solana-decode-error", - "solana-hash", + "solana-hash 2.3.0", "solana-instruction", "solana-pubkey", "solana-rent", @@ -5537,11 +5638,11 @@ version = "1.0.1" dependencies = [ "mollusk-svm", "pinocchio", - "pinocchio-pubkey", "pinocchio-system", "solana-account", "solana-instruction", - "solana-program-error", + "solana-program-error 2.2.1", + "solana-program-log", "solana-pubkey", "solana-rent", "solana-sdk-ids", @@ -5564,7 +5665,7 @@ dependencies = [ "solana-cpi", "solana-decode-error", "solana-instruction", - "solana-program-error", + "solana-program-error 2.2.1", "solana-pubkey", "solana-sdk", "thiserror 1.0.69", diff --git a/Cargo.toml b/Cargo.toml index f090367..662a7dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,11 +3,11 @@ resolver = "2" members = ["program", "clients/rust"] [workspace.metadata.cli] -solana = "2.3.4" +solana = "3.1.14" [workspace.metadata.toolchains] -format = "nightly-2025-02-16" -lint = "nightly-2025-02-16" +format = "nightly-2026-01-22" +lint = "nightly-2026-01-22" [workspace.metadata.spellcheck] config = "scripts/spellcheck.toml" diff --git a/clients/rust/src/lib.rs b/clients/rust/src/lib.rs index fb44352..84b00df 100644 --- a/clients/rust/src/lib.rs +++ b/clients/rust/src/lib.rs @@ -1,3 +1,8 @@ +// Disable warnings for generated code since these need to be fixed +// in the codama generator. +#![allow(dead_code)] +#![allow(clippy::io_other_error)] + mod generated; mod hooked; diff --git a/codama.mjs b/codama.mjs index dd07203..4007475 100644 --- a/codama.mjs +++ b/codama.mjs @@ -80,7 +80,7 @@ export default { { formatCode: true, crateFolder: 'clients/rust', - toolchain: '+nightly-2025-02-16', + toolchain: '+nightly-2026-01-22', anchorTraits: false, linkOverrides: { definedTypes: { diff --git a/program/Cargo.toml b/program/Cargo.toml index ff9d1a4..1085c6b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,9 +21,9 @@ name = "spl_program_metadata" crate-type = ["cdylib", "lib"] [dependencies] -pinocchio = "0.8" -pinocchio-pubkey = "0.2" -pinocchio-system = "0.2" +pinocchio = { version = "0.11.1", features = ["account-resize"] } +pinocchio-system = "0.6.1" +solana-program-log = { version = "1.0", default-features = false } solana-security-txt = "1.1.1" [dev-dependencies] diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs index 93908cb..6e980fa 100644 --- a/program/src/entrypoint.rs +++ b/program/src/entrypoint.rs @@ -1,7 +1,9 @@ use pinocchio::{ - account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, - program_error::ProgramError, pubkey::Pubkey, ProgramResult, + default_panic_handler, error::ProgramError, no_allocator, program_entrypoint, AccountView, + Address, ProgramResult, }; +#[cfg(feature = "logging")] +use solana_program_log::log; use crate::{ instruction::ProgramMetadataInstruction, @@ -19,8 +21,8 @@ default_panic_handler!(); no_allocator!(); fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], + _program_id: &Address, + accounts: &mut [AccountView], instruction_data: &[u8], ) -> ProgramResult { let [instruction, data @ ..] = instruction_data else { @@ -31,63 +33,63 @@ fn process_instruction( // 0 - Write ProgramMetadataInstruction::Write => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Write"); + log("Instruction: Write"); write(accounts, data) } // 1 - Initialize ProgramMetadataInstruction::Initialize => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Initialize"); + log("Instruction: Initialize"); initialize(accounts, data) } // 2 - SetAuthority ProgramMetadataInstruction::SetAuthority => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: SetAuthority"); + log("Instruction: SetAuthority"); set_authority(accounts, data) } // 3 - SetData ProgramMetadataInstruction::SetData => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: SetData"); + log("Instruction: SetData"); set_data(accounts, data) } // 4 - SetImmutable ProgramMetadataInstruction::SetImmutable => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: SetImmutable"); + log("Instruction: SetImmutable"); set_immutable(accounts) } // 5 - Trim ProgramMetadataInstruction::Trim => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Trim"); + log("Instruction: Trim"); trim(accounts) } // 6 - Close ProgramMetadataInstruction::Close => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Close"); + log("Instruction: Close"); close(accounts) } // 7 - Allocate ProgramMetadataInstruction::Allocate => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Allocate"); + log("Instruction: Allocate"); allocate(accounts, data) } // 8 - Extend ProgramMetadataInstruction::Extend => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Extend"); + log("Instruction: Extend"); extend(accounts, data) } diff --git a/program/src/error.rs b/program/src/error.rs index 363daef..92e1156 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -1,4 +1,4 @@ -use pinocchio::program_error::ProgramError; +use pinocchio::error::ProgramError; #[derive(Clone, Debug, Eq, PartialEq)] pub enum ProgramMetadataError { diff --git a/program/src/instruction.rs b/program/src/instruction.rs index daa96be..5b0ac90 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1,4 +1,4 @@ -use pinocchio::program_error::ProgramError; +use pinocchio::error::ProgramError; /// Instructions supported by the program metadata program. #[derive(Clone, Copy, Debug)] diff --git a/program/src/lib.rs b/program/src/lib.rs index cb9ef67..37bc9a3 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -6,7 +6,7 @@ pub mod instruction; pub mod processor; pub mod state; -pinocchio_pubkey::declare_id!("ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S"); +pinocchio::address::declare_id!("ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S"); solana_security_txt::security_txt! { // Required fields diff --git a/program/src/processor/allocate.rs b/program/src/processor/allocate.rs index 67c5b0d..88ba766 100644 --- a/program/src/processor/allocate.rs +++ b/program/src/processor/allocate.rs @@ -1,15 +1,14 @@ use pinocchio::{ - account_info::AccountInfo, - instruction::{Seed, Signer}, - program_error::ProgramError, - pubkey::find_program_address, + cpi::{Seed, Signer}, + error::ProgramError, sysvars::{rent::Rent, Sysvar}, - ProgramResult, + AccountView, ProgramResult, }; use pinocchio_system::instructions::{Allocate, Assign}; use crate::{ error::ProgramMetadataError, + processor::derive_program_address, state::{buffer::Buffer, AccountDiscriminator, SEED_LEN}, ID, }; @@ -18,7 +17,7 @@ use super::is_program_authority; /// Processor for the [`Allocate`](`crate::instruction::ProgramMetadataInstruction::Allocate`) /// instruction. -pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { +pub fn allocate(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramResult { // Access accounts. let [buffer, authority, program, program_data, _system_program, _remaining @ ..] = accounts @@ -43,7 +42,7 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes // a signer (match the authority) // - must be rent exempt (pre-funded account) - let (is_pda, bump, canonical) = if buffer.key() == authority.key() { + let (is_pda, bump, canonical) = if buffer.address() == authority.address() { // A keypair buffer does not require a `seed` value. if !instruction_data.is_empty() { return Err(ProgramError::InvalidInstructionData); @@ -60,17 +59,22 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes return Err(ProgramMetadataError::NotExecutableAccount.into()); } - let canonical = is_program_authority(program, program_data, authority.key())?; + let canonical = is_program_authority(program, program_data, authority.address())?; - let seeds: &[&[u8]] = if canonical { - &[program.key(), instruction_data] + let (derived_metadata, bump) = if canonical { + derive_program_address(&[program.address().as_array(), instruction_data], &ID) } else { - &[program.key(), authority.key(), instruction_data] + derive_program_address( + &[ + program.address().as_array(), + authority.address().as_array(), + instruction_data, + ], + &ID, + ) }; - let (derived_metadata, bump) = find_program_address(seeds, &ID); - - if buffer.key() != &derived_metadata { + if buffer.address() != &derived_metadata { return Err(ProgramError::InvalidSeeds); } @@ -90,7 +94,7 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes buffer, space, &[ - Seed::from(program.key()), + Seed::from(program.address().as_array()), Seed::from(instruction_data), Seed::from(&[bump]), ], @@ -100,8 +104,8 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes buffer, space, &[ - Seed::from(program.key()), - Seed::from(authority.key()), + Seed::from(program.address().as_array()), + Seed::from(authority.address().as_array()), Seed::from(instruction_data), Seed::from(&[bump]), ], @@ -115,7 +119,7 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes // buffer account to the program (the runtime only allows assigning // zeroed accounts, so there is no need to check the contents of the // account). - if !buffer.is_owned_by(&crate::ID) { + if !buffer.owned_by(&crate::ID) { Assign { account: buffer, owner: &crate::ID, @@ -125,7 +129,7 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes // Checks whether the buffer account is already initialized or not. // // SAFETY: scoped borrow of the `buffer` account data. - let data = unsafe { buffer.borrow_data_unchecked() }; + let data = unsafe { buffer.borrow_unchecked() }; if data[0] != AccountDiscriminator::Empty as u8 { return Err(ProgramError::AccountAlreadyInitialized); @@ -135,7 +139,8 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes _ => return Err(ProgramError::InvalidAccountData), } - let minimum_balance = Rent::get()?.minimum_balance(buffer.data_len()); + // `buffer` length is within the permitted limit. + let minimum_balance = Rent::get()?.minimum_balance_unchecked(buffer.data_len()); if buffer.lamports() < minimum_balance { return Err(ProgramError::AccountNotRentExempt); @@ -145,13 +150,12 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes // SAFETY: single mutable borrow of the `buffer` account data. The legth of the buffer account // data has been checked to be at least `Buffer::LEN` and uninitialized. - let buffer_header = - unsafe { Buffer::from_bytes_mut_unchecked(buffer.borrow_mut_data_unchecked()) }; + let buffer_header = unsafe { Buffer::from_bytes_mut_unchecked(buffer.borrow_unchecked_mut()) }; buffer_header.discriminator = AccountDiscriminator::Buffer as u8; - buffer_header.authority = (*authority.key()).into(); + buffer_header.authority = (*authority.address()).into(); if is_pda { - buffer_header.program = (*program.key()).into(); + buffer_header.program = (*program.address()).into(); buffer_header.canonical = canonical as u8; buffer_header .seed @@ -165,7 +169,7 @@ pub fn allocate(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes /// /// When the `account` is a PDA, the `seeds` are used to create the signer. #[inline(always)] -fn allocate_and_assign(account: &AccountInfo, space: u64, seeds: &[Seed]) -> ProgramResult { +fn allocate_and_assign(account: &AccountView, space: u64, seeds: &[Seed]) -> ProgramResult { let signer: &[Signer] = if seeds.is_empty() { &[] } else { diff --git a/program/src/processor/close.rs b/program/src/processor/close.rs index ebc3678..8a07dec 100644 --- a/program/src/processor/close.rs +++ b/program/src/processor/close.rs @@ -1,4 +1,4 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; +use pinocchio::{account::AccountView, error::ProgramError, ProgramResult}; use crate::state::{buffer::Buffer, AccountDiscriminator}; @@ -6,7 +6,7 @@ use super::{validate_authority, validate_metadata}; /// Processor for the [`Close`](`crate::instruction::ProgramMetadataInstruction::Close`) /// instruction. -pub fn close(accounts: &[AccountInfo]) -> ProgramResult { +pub fn close(accounts: &mut [AccountView]) -> ProgramResult { // Access accounts. let [account, authority, program, program_data, destination] = accounts else { @@ -29,15 +29,15 @@ pub fn close(accounts: &[AccountInfo]) -> ProgramResult { // - must have data // - authority must match (if not a keypair buffer) - let account_data = if account.data_is_empty() { + let account_data = if account.is_data_empty() { return Err(ProgramError::UninitializedAccount); } else { - unsafe { account.borrow_data_unchecked() } + unsafe { account.borrow_unchecked() } }; // We only need to validate the authority if it is not a keypair buffer, // since we already validated that the authority is a signer. - if account.key() != authority.key() { + if account.address() != authority.address() { match AccountDiscriminator::try_from(account_data[0])? { AccountDiscriminator::Buffer => { let buffer = unsafe { Buffer::from_bytes_unchecked(account_data) }; @@ -53,16 +53,15 @@ pub fn close(accounts: &[AccountInfo]) -> ProgramResult { // Move the lamports to the destination account and close the account. - // SAFETY: There are no active borrows to accounts' lamports. - unsafe { - let account_lamports = account.borrow_mut_lamports_unchecked(); - let destination_lamports = destination.borrow_mut_lamports_unchecked(); + let account_lamports = account.lamports(); + let destination_lamports = destination.lamports(); - *destination_lamports = destination_lamports - .checked_add(*account_lamports) - .ok_or(ProgramError::ArithmeticOverflow)?; - *account_lamports = 0; - } + destination.set_lamports( + destination_lamports + .checked_add(account_lamports) + .ok_or(ProgramError::ArithmeticOverflow)?, + ); + account.set_lamports(0); account.close() } diff --git a/program/src/processor/extend.rs b/program/src/processor/extend.rs index 29b1530..1c4193a 100644 --- a/program/src/processor/extend.rs +++ b/program/src/processor/extend.rs @@ -1,9 +1,9 @@ use core::mem::size_of; use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, + account::AccountView, + error::ProgramError, sysvars::{rent::Rent, Sysvar}, - ProgramResult, + ProgramResult, Resize, }; use crate::state::{buffer::Buffer, AccountDiscriminator}; @@ -13,7 +13,7 @@ use super::{validate_authority, validate_metadata}; /// Processor for the [`Extend`](`crate::instruction::ProgramMetadataInstruction::Extend`) /// instruction. #[allow(clippy::arithmetic_side_effects)] -pub fn extend(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { +pub fn extend(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramResult { // Validates the instruction data. let extend_length = if instruction_data.len() != size_of::() { @@ -30,6 +30,9 @@ pub fn extend(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResul }; // Account validation. + // + // Note that program owned and writable checks are done implicitly by writing + // to the account. // account // - authority must be a signer (validated by `validate_authority`) @@ -38,11 +41,11 @@ pub fn extend(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResul // - must be rent exempt (pre-funded account) since we are reallocating the buffer // account - if account.data_is_empty() { + if account.is_data_empty() { return Err(ProgramError::InvalidAccountData); } else { // SAFETY: single immutable borrow of `account` account data. - let data = unsafe { account.borrow_data_unchecked() }; + let data = unsafe { account.borrow_unchecked() }; // SAFETY: `account` is guaranteed to not be empty. let discriminator = unsafe { data.get_unchecked(0) }; @@ -63,7 +66,7 @@ pub fn extend(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResul // will never overflow the `usize` limit. let length = account.data_len() + extend_length as usize; - let minimum_balance = Rent::get()?.minimum_balance(length); + let minimum_balance = Rent::get()?.try_minimum_balance(length)?; if account.lamports() < minimum_balance { return Err(ProgramError::AccountNotRentExempt); @@ -71,5 +74,6 @@ pub fn extend(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResul // Reallocates the account size. - account.realloc(length, false) + // SAFETY: `account` is not borrowed at this point. + unsafe { account.resize_unchecked(length) } } diff --git a/program/src/processor/initialize.rs b/program/src/processor/initialize.rs index 6481f55..e657b74 100644 --- a/program/src/processor/initialize.rs +++ b/program/src/processor/initialize.rs @@ -1,16 +1,14 @@ use pinocchio::{ - account_info::AccountInfo, - instruction::{Seed, Signer}, - memory::sol_memcpy, - program_error::ProgramError, - pubkey::{find_program_address, Pubkey}, - seeds, + cpi::{Seed, Signer}, + error::ProgramError, + instruction::seeds, sysvars::{rent::Rent, Sysvar}, - ProgramResult, + AccountView, Address, ProgramResult, }; use pinocchio_system::instructions::{Allocate, Assign}; use crate::{ + processor::derive_program_address, state::{ header::Header, AccountDiscriminator, Compression, DataSource, Encoding, Format, Zeroable, }, @@ -22,7 +20,7 @@ use super::is_program_authority; /// Processor for the [`Initialize`](`crate::instruction::ProgramMetadataInstruction::Initialize`) /// instruction. #[allow(clippy::arithmetic_side_effects)] -pub fn initialize(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { +pub fn initialize(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramResult { // Validates the instruction data. let (args, remaining_data) = if instruction_data.len() < Initialize::LEN { @@ -55,7 +53,7 @@ pub fn initialize(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramR return Err(ProgramError::MissingRequiredSignature); } - let canonical: bool = is_program_authority(program, program_data, authority.key())?; + let canonical: bool = is_program_authority(program, program_data, authority.address())?; // metadata // - must be a PDA derived from the program ID and the seed @@ -64,21 +62,26 @@ pub fn initialize(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramR // pre-allocated buffer (i.e. `discriminator = 1`), in which case, no remaining // instruction data is allowed as the data must already be written to the account - let seeds: &[&[u8]] = if canonical { - &[program.key(), args.seed.as_ref()] + let (derived_metadata, bump) = if canonical { + derive_program_address(&[program.address().as_array(), args.seed.as_ref()], &ID) } else { - &[program.key(), authority.key(), args.seed.as_ref()] + derive_program_address( + &[ + program.address().as_array(), + authority.address().as_array(), + args.seed.as_ref(), + ], + &ID, + ) }; - let (derived_metadata, bump) = find_program_address(seeds, &ID); - - if metadata.key() != &derived_metadata { + if metadata.address() != &derived_metadata { return Err(ProgramError::InvalidSeeds); } let discriminator = { // SAFETY: scoped immutable borrow of `metadata` account data. - AccountDiscriminator::try_from_bytes(unsafe { metadata.borrow_data_unchecked() })? + AccountDiscriminator::try_from_bytes(unsafe { metadata.borrow_unchecked() })? }; let data_length = match discriminator { @@ -112,12 +115,16 @@ pub fn initialize(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramR let signer_bump = &[bump]; let signer_seeds: &[Seed] = if canonical { // canonical - &seeds!(program.key(), args.seed.as_ref(), signer_bump) + &seeds!( + program.address().as_array(), + args.seed.as_ref(), + signer_bump + ) } else { // non-canonical &seeds!( - program.key(), - authority.key(), + program.address().as_array(), + authority.address().as_array(), args.seed.as_ref(), signer_bump ) @@ -138,7 +145,8 @@ pub fn initialize(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramR } .invoke_signed(signer)?; - let minimum_balance = Rent::get()?.minimum_balance(space); + // `space` is guranteed to be within the permitted limits. + let minimum_balance = Rent::get()?.minimum_balance_unchecked(space); if metadata.lamports() < minimum_balance { return Err(ProgramError::AccountNotRentExempt); @@ -146,16 +154,18 @@ pub fn initialize(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramR // SAFETY: scoped mutable borrow of `metadata` account data. The data is // guaranteed to be allocated and assigned to the program. - let metadata_account_data = unsafe { metadata.borrow_mut_data_unchecked() }; + let metadata_account_data = unsafe { metadata.borrow_unchecked_mut() }; // Copy the instruction remaining data to the metadata account. // // SAFETY: `metadata` account has been allocated and assigned to the program // and the length of the remaining data was checked. unsafe { - sol_memcpy( - metadata_account_data.get_unchecked_mut(Header::LEN..), - remaining_data, + core::ptr::copy_nonoverlapping( + remaining_data.as_ptr(), + metadata_account_data + .get_unchecked_mut(Header::LEN..) + .as_mut_ptr(), remaining_data.len(), ); } @@ -168,13 +178,13 @@ pub fn initialize(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramR // SAFETY: there are no other active borrows to `metadata` account data and // the account discriminator has been validated. - let header = unsafe { Header::from_bytes_mut_unchecked(metadata.borrow_mut_data_unchecked()) }; + let header = unsafe { Header::from_bytes_mut_unchecked(metadata.borrow_unchecked_mut()) }; header.discriminator = AccountDiscriminator::Metadata as u8; - header.program = *program.key(); + header.program = *program.address(); header.authority = match canonical { - true => Pubkey::ZERO.into(), - false => (*authority.key()).into(), + true => Address::ZERO.into(), + false => (*authority.address()).into(), }; header.mutable = true as u8; header.canonical = canonical as u8; diff --git a/program/src/processor/mod.rs b/program/src/processor/mod.rs index 24b59cd..dd711d3 100644 --- a/program/src/processor/mod.rs +++ b/program/src/processor/mod.rs @@ -1,8 +1,4 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::{Pubkey, PUBKEY_BYTES}, -}; +use pinocchio::{address::ADDRESS_BYTES, error::ProgramError, AccountView, Address}; use crate::state::{header::Header, Account, AccountDiscriminator}; @@ -17,10 +13,10 @@ pub mod trim; pub mod write; /// The program ID of the SVM Loader `v3`. -const BPF_LOADER_UPGRABABLE_ID: Pubkey = [ +const BPF_LOADER_UPGRABABLE_ID: Address = Address::new_from_array([ 2, 168, 246, 145, 78, 136, 161, 176, 226, 16, 21, 62, 247, 99, 174, 43, 0, 194, 185, 61, 22, 193, 36, 210, 192, 83, 122, 16, 4, 128, 0, 0, -]; +]); /// Checks if the provided `authority` is the authority allowed to update the `program`. /// Fails when providing unexpected input. @@ -47,45 +43,45 @@ const BPF_LOADER_UPGRABABLE_ID: Pubkey = [ #[allow(clippy::arithmetic_side_effects)] #[inline(always)] fn is_program_authority( - program: &AccountInfo, - program_data: &AccountInfo, - authority: &Pubkey, + program: &AccountView, + program_data: &AccountView, + authority: &Address, ) -> Result { // For BPFv1 and BPF Loader v2 programs, there is no program data associated. In this case, // the keypair used to deploy the program must be the authority and sign the transaction. - if !program.is_owned_by(&BPF_LOADER_UPGRABABLE_ID) { - return Ok(program.executable() && program.key() == authority); + if !program.owned_by(&BPF_LOADER_UPGRABABLE_ID) { + return Ok(program.executable() && program.address() == authority); } // For BPFv3 programs, we need the program data account to check the auhtority. - if program_data.key() == &crate::ID { + if program_data.address() == &crate::ID { return Ok(false); } let expected_program_data = { - let data = unsafe { program.borrow_data_unchecked() }; + let data = unsafe { program.borrow_unchecked() }; match (data.first(), program.executable()) { (Some(2 /* program discriminator */), true) => { let offset: usize = 4 /* discriminator */; - Pubkey::try_from(&data[offset..offset + PUBKEY_BYTES]) + Address::try_from(&data[offset..offset + ADDRESS_BYTES]) .map_err(|_| ProgramError::InvalidAccountData)? } _ => { - // TODO: use custom error (invalid program state) + // custom error (invalid program state) return Err(ProgramError::InvalidAccountData); } } }; // Program <-> Program Data check. - if expected_program_data != *program_data.key() { - // TODO: use custom error (invalid program data account) + if expected_program_data != *program_data.address() { + // use custom error (invalid program data account) return Err(ProgramError::InvalidAccountData); } // Program Data checks. let is_program_authority = { - let data = unsafe { program_data.borrow_data_unchecked() }; + let data = unsafe { program_data.borrow_unchecked() }; match (data.first(), program_data.executable()) { (Some(3 /* program data discriminator */), false) => { let option_offset: usize = 4 /* discriminator */ + 8 /* slot */; @@ -93,7 +89,7 @@ fn is_program_authority( let pubkey_offset: usize = option_offset + 1 /* option */; // The `authority_key` is a `Pubkey`. let authority_key = - Pubkey::try_from(&data[pubkey_offset..pubkey_offset + PUBKEY_BYTES]) + Address::try_from(&data[pubkey_offset..pubkey_offset + ADDRESS_BYTES]) .map_err(|_| ProgramError::InvalidAccountData)?; authority == &authority_key } else { @@ -101,7 +97,7 @@ fn is_program_authority( } } _ => { - // TODO: use custom error (invalid program state) + // custom error (invalid program state) return Err(ProgramError::InvalidAccountData); } } @@ -118,13 +114,13 @@ fn is_program_authority( /// be [`AccountDiscriminator::Metadata`]. /// - The `metadata` account must be mutable (`mutable = true`). #[inline(always)] -fn validate_metadata(metadata: &AccountInfo) -> Result<&Header, ProgramError> { - let header = unsafe { Header::from_bytes_unchecked(metadata.borrow_data_unchecked()) }; +fn validate_metadata(metadata: &AccountView) -> Result<&Header, ProgramError> { + let header = unsafe { Header::from_bytes_unchecked(metadata.borrow_unchecked()) }; if header.discriminator != AccountDiscriminator::Metadata as u8 { return Err(ProgramError::UninitializedAccount); } if !header.mutable() { - // TODO: use custom error (immutable metadata account) + // custom error (immutable metadata account) return Err(ProgramError::InvalidAccountData); } Ok(header) @@ -141,9 +137,9 @@ fn validate_metadata(metadata: &AccountInfo) -> Result<&Header, ProgramError> { #[inline(always)] fn validate_authority( account: &T, - authority: &AccountInfo, - program: &AccountInfo, - program_data: &AccountInfo, + authority: &AccountView, + program: &AccountView, + program_data: &AccountView, ) -> Result<(), ProgramError> { // Authority checks. if !authority.is_signer() { @@ -152,14 +148,14 @@ fn validate_authority( // The authority is the set authority. let explicitly_authorized = match account.get_authority() { - Some(metadata_authority) => metadata_authority == authority.key(), + Some(metadata_authority) => metadata_authority == authority.address(), None => false, }; // The authority is the program upgrade authority for canonical metadata accounts. let authorized = explicitly_authorized - || (account.is_canonical(program.key()) - && is_program_authority(program, program_data, authority.key())?); + || (account.is_canonical(program.address()) + && is_program_authority(program, program_data, authority.address())?); if !authorized { Err(ProgramError::IncorrectAuthority) @@ -167,3 +163,12 @@ fn validate_authority( Ok(()) } } + +#[inline(always)] +fn derive_program_address( + seeds: &[&[u8]; N], + program_id: &Address, +) -> (Address, u8) { + Address::derive_program_address(seeds, program_id) + .expect("Unable to find a viable program address bump seed") +} diff --git a/program/src/processor/set_authority.rs b/program/src/processor/set_authority.rs index 899bb84..db223e6 100644 --- a/program/src/processor/set_authority.rs +++ b/program/src/processor/set_authority.rs @@ -1,6 +1,4 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account::AccountView, error::ProgramError, Address, ProgramResult}; use crate::{ processor::validate_authority, @@ -9,7 +7,7 @@ use crate::{ /// Processor for the [`SetAuthority`](`crate::instruction::ProgramMetadataInstruction::SetAuthority`) /// instruction. -pub fn set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { +pub fn set_authority(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramResult { // Validates the instruction data. let [has_new_authority, new_authority @ ..] = instruction_data else { @@ -17,6 +15,9 @@ pub fn set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> Progr }; // Access accounts. + // + // Note that program owned and writable checks are done implicitly by writing + // to the account. let [account, authority, program, program_data] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -36,7 +37,7 @@ pub fn set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> Progr // - must have a valid authority // SAFETY: single mutable borrow of `account` account data. - let account_data = unsafe { account.borrow_mut_data_unchecked() }; + let account_data = unsafe { account.borrow_unchecked_mut() }; match AccountDiscriminator::try_from_bytes(account_data)? { Some(AccountDiscriminator::Buffer) => { @@ -48,7 +49,7 @@ pub fn set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> Progr return Err(ProgramError::InvalidArgument); } - let new_authority: Pubkey = new_authority + let new_authority: Address = new_authority .try_into() .map_err(|_| ProgramError::InvalidInstructionData)?; buffer.authority = new_authority.into(); @@ -63,9 +64,9 @@ pub fn set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> Progr validate_authority(header, authority, program, program_data)?; header.authority = if *has_new_authority == 0 { - Pubkey::ZERO.into() + Address::ZERO.into() } else { - let new_authority: Pubkey = new_authority + let new_authority: Address = new_authority .try_into() .map_err(|_| ProgramError::InvalidInstructionData)?; new_authority.into() diff --git a/program/src/processor/set_data.rs b/program/src/processor/set_data.rs index ed4dd61..fb9a4ff 100644 --- a/program/src/processor/set_data.rs +++ b/program/src/processor/set_data.rs @@ -1,6 +1,4 @@ -use pinocchio::{ - account_info::AccountInfo, memory::sol_memcpy, program_error::ProgramError, ProgramResult, -}; +use pinocchio::{account::AccountView, error::ProgramError, ProgramResult, Resize}; use crate::state::{ header::Header, AccountDiscriminator, Compression, DataSource, Encoding, Format, @@ -11,7 +9,7 @@ use super::{validate_authority, validate_metadata}; /// Processor for the [`SetData`](`crate::instruction::ProgramMetadataInstruction::SetData`) /// instruction. #[allow(clippy::arithmetic_side_effects)] -pub fn set_data(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { +pub fn set_data(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramResult { // Validates the instruction data. if instruction_data.len() < SetData::LEN { @@ -57,12 +55,12 @@ pub fn set_data(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes validate_authority(header, authority, program, program_data)?; // Get data from buffer or remaining instruction data, if any. - let has_buffer = buffer.key() != &crate::ID; + let has_buffer = buffer.address() != &crate::ID; let data = match (optional_data, has_buffer) { (Some((data_source, Some(remaining_data))), false) => Some((data_source, remaining_data)), (Some((data_source, None)), true) => { // SAFETY: singe immutable borrow of `buffer` account data. - let buffer_data = unsafe { buffer.borrow_data_unchecked() }; + let buffer_data = unsafe { buffer.borrow_unchecked() }; match AccountDiscriminator::try_from_bytes(buffer_data)? { Some(AccountDiscriminator::Buffer) => { Some((data_source, &buffer_data[Header::LEN..])) @@ -78,20 +76,23 @@ pub fn set_data(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes if let Some(data) = update_header(metadata, args, data)? { // Realloc the metadata account if necessary. + + // SAFETY: There are no other active borrows to the `metadata` account data. // // The realloc validates that the new size does not exceed the // maximum size of an account. - metadata.realloc(Header::LEN + data.len(), false)?; + unsafe { metadata.resize_unchecked(Header::LEN + data.len())? }; // SAFETY: There are no other active borrows to the `metadata` // account data and the account has been reallocated to accommodate // the new data. unsafe { - sol_memcpy( + core::ptr::copy_nonoverlapping( + data.as_ptr(), metadata - .borrow_mut_data_unchecked() - .get_unchecked_mut(Header::LEN..), - data, + .borrow_unchecked_mut() + .get_unchecked_mut(Header::LEN..) + .as_mut_ptr(), data.len(), ); } @@ -103,12 +104,12 @@ pub fn set_data(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramRes /// Updates the metadata header with the provided arguments and data. #[inline(always)] fn update_header<'a>( - metadata: &AccountInfo, + metadata: &mut AccountView, args: &SetData, data: Option<(&'a u8, &'a [u8])>, ) -> Result, ProgramError> { // SAFETY: There are no other active borrows to the `metadata` account data. - let metadata_account_data = unsafe { metadata.borrow_mut_data_unchecked() }; + let metadata_account_data = unsafe { metadata.borrow_unchecked_mut() }; // SAFETY: `metadata` is validated to be initialized and mutable. let header = unsafe { Header::from_bytes_mut_unchecked(metadata_account_data) }; diff --git a/program/src/processor/set_immutable.rs b/program/src/processor/set_immutable.rs index 42e8523..58c55fd 100644 --- a/program/src/processor/set_immutable.rs +++ b/program/src/processor/set_immutable.rs @@ -1,4 +1,4 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; +use pinocchio::{account::AccountView, error::ProgramError, ProgramResult}; use crate::state::header::Header; @@ -6,7 +6,7 @@ use super::{validate_authority, validate_metadata}; /// Processor for the [`SetImmutable`](`crate::instruction::ProgramMetadataInstruction::SetImmutable`) /// instruction. -pub fn set_immutable(accounts: &[AccountInfo]) -> ProgramResult { +pub fn set_immutable(accounts: &mut [AccountView]) -> ProgramResult { // Access accounts. let [metadata, authority, program, program_data] = accounts else { @@ -35,12 +35,12 @@ pub fn set_immutable(accounts: &[AccountInfo]) -> ProgramResult { // SAFETY: There are no active borrows of the `metadata` account data and the // account has been validated. - let header = unsafe { Header::from_bytes_mut_unchecked(metadata.borrow_mut_data_unchecked()) }; + let header = unsafe { Header::from_bytes_mut_unchecked(metadata.borrow_unchecked_mut()) }; if header.mutable() { header.mutable = 0; } else { - // TODO: use custom error (metadata already immutable) + // custom error (metadata already immutable) return Err(ProgramError::InvalidAccountData); } diff --git a/program/src/processor/trim.rs b/program/src/processor/trim.rs index 279d833..6140d24 100644 --- a/program/src/processor/trim.rs +++ b/program/src/processor/trim.rs @@ -1,5 +1,5 @@ use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, sysvars::rent::Rent, ProgramResult, + account::AccountView, error::ProgramError, sysvars::rent::Rent, ProgramResult, Resize, }; use crate::state::{buffer::Buffer, header::Header, AccountDiscriminator}; @@ -9,7 +9,7 @@ use super::{validate_authority, validate_metadata}; /// Processor for the [`Trim`](`crate::instruction::ProgramMetadataInstruction::Trim`) /// instruction. #[allow(clippy::arithmetic_side_effects)] -pub fn trim(accounts: &[AccountInfo]) -> ProgramResult { +pub fn trim(accounts: &mut [AccountView]) -> ProgramResult { // Access accounts. let [account, authority, program, program_data, destination, rent_sysvar] = accounts else { @@ -17,19 +17,22 @@ pub fn trim(accounts: &[AccountInfo]) -> ProgramResult { }; // Account validation. + // + // Note that program owned and writable checks are done implicitly by writing + // to the account. // account // - authority must be a signer (checked by `validate_authority`) // - must be a buffer or metadata account // - must have a valid authority - if account.data_is_empty() { + if account.is_data_empty() { return Err(ProgramError::UninitializedAccount); }; let length = { // SAFETY: scoped immutable borrow of `account` account data. - let data = unsafe { account.borrow_data_unchecked() }; + let data = unsafe { account.borrow_unchecked() }; // SAFETY: `account` is guaranteed to not be empty. let discriminator = unsafe { data.get_unchecked(0) }; @@ -53,11 +56,12 @@ pub fn trim(accounts: &[AccountInfo]) -> ProgramResult { let minimum_balance = { // SAFETY: single immutable borrow of `rent_sysver` account data. - let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar)? }; - rent.minimum_balance(length) + let rent = unsafe { Rent::from_account_view_unchecked(rent_sysvar)? }; + rent.try_minimum_balance(length)? }; - account.realloc(length, false)?; + // SAFETY: `account` is not borrowed at this point. + unsafe { account.resize_unchecked(length)? }; // Current lamports should always be greater than or equal to the minimum // balance since the account must be rent exempt. @@ -65,17 +69,14 @@ pub fn trim(accounts: &[AccountInfo]) -> ProgramResult { .lamports() .checked_sub(minimum_balance) .ok_or(ProgramError::AccountNotRentExempt)?; + let destination_lamports = destination.lamports(); - // SAFETY: single mutable borrow if `account` and `destination` lamports. - unsafe { - let account_lamports = account.borrow_mut_lamports_unchecked(); - let destination_lamports = destination.borrow_mut_lamports_unchecked(); - - *destination_lamports = destination_lamports + destination.set_lamports( + destination_lamports .checked_add(excess_lamports) - .ok_or(ProgramError::ArithmeticOverflow)?; - *account_lamports = minimum_balance; - } + .ok_or(ProgramError::ArithmeticOverflow)?, + ); + account.set_lamports(minimum_balance); Ok(()) } diff --git a/program/src/processor/write.rs b/program/src/processor/write.rs index e3736b8..fedee09 100644 --- a/program/src/processor/write.rs +++ b/program/src/processor/write.rs @@ -1,11 +1,9 @@ use core::cmp::max; use pinocchio::{ - account_info::AccountInfo, - memory::sol_memcpy, - program_error::ProgramError, + error::ProgramError, sysvars::{rent::Rent, Sysvar}, - ProgramResult, + AccountView, ProgramResult, Resize, }; use crate::state::{buffer::Buffer, header::Header, AccountDiscriminator}; @@ -13,7 +11,7 @@ use crate::state::{buffer::Buffer, header::Header, AccountDiscriminator}; /// Processor for the [`Write`](`crate::instruction::ProgramMetadataInstruction::Write`) /// instruction. #[allow(clippy::arithmetic_side_effects)] -pub fn write(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { +pub fn write(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramResult { // Validates the instruction data. let args = Write::try_from_bytes(instruction_data)?; @@ -43,7 +41,7 @@ pub fn write(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult let (required_length, source_data) = { // SAFETY: scoped immutable borrow of `buffer` account data. There // are no other borrows active. - let data = unsafe { target_buffer.borrow_data_unchecked() }; + let data = unsafe { target_buffer.borrow_unchecked() }; if data.is_empty() || data[0] != AccountDiscriminator::Buffer as u8 { return Err(ProgramError::InvalidAccountData); @@ -52,7 +50,7 @@ pub fn write(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult // SAFETY: `buffer` account data is guaranteed to be a `Buffer`. let buffer_header = unsafe { Buffer::from_bytes_unchecked(data) }; - if Some(authority.key()) != buffer_header.authority.as_ref() { + if Some(authority.address()) != buffer_header.authority.as_ref() { return Err(ProgramError::IncorrectAuthority); } @@ -62,9 +60,9 @@ pub fn write(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult _ => None, }; - let buffer_data = if source_buffer.key() != &crate::ID { + let buffer_data = if source_buffer.address() != &crate::ID { // SAFETY: singe immutable borrow of `source_buffer` account data. - Some(unsafe { source_buffer.borrow_data_unchecked() }) + Some(unsafe { source_buffer.borrow_unchecked() }) } else { None }; @@ -78,11 +76,11 @@ pub fn write(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult _ => return Err(ProgramError::InvalidInstructionData), }; - // The length of the data to write is validated by the `realloc`. + // The length of the data to write is validated by the `try_minimum_balance`. (max(data.len(), offset + source_data.len()), source_data) }; - let minimum_balance = Rent::get()?.minimum_balance(required_length); + let minimum_balance = Rent::get()?.try_minimum_balance(required_length)?; if target_buffer.lamports() < minimum_balance { return Err(ProgramError::AccountNotRentExempt); @@ -90,15 +88,17 @@ pub fn write(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult // Writes the source data to the buffer account. - target_buffer.realloc(required_length, false)?; + // SAFETY: `target_buffer` account is not borrowed at this point. + unsafe { target_buffer.resize_unchecked(required_length)? }; + // SAFETY: single mutable borrow of `buffer` account data. There // are no other borrows active. - let data = unsafe { target_buffer.borrow_mut_data_unchecked() }; + let data = unsafe { target_buffer.borrow_unchecked_mut() }; unsafe { - sol_memcpy( - data.get_unchecked_mut(offset..), - source_data, + core::ptr::copy_nonoverlapping( + source_data.as_ptr(), + data.get_unchecked_mut(offset..).as_mut_ptr(), source_data.len(), ); } @@ -117,7 +117,7 @@ struct Write<'a> { impl Write<'_> { #[inline] - pub fn try_from_bytes(bytes: &[u8]) -> Result { + pub fn try_from_bytes(bytes: &[u8]) -> Result, ProgramError> { // The minimum expected size of the instruction data. // - offset (4 bytes) // - data (...n bytes, optional) diff --git a/program/src/state/buffer.rs b/program/src/state/buffer.rs index 6efcfd6..19da923 100644 --- a/program/src/state/buffer.rs +++ b/program/src/state/buffer.rs @@ -1,7 +1,7 @@ use pinocchio::{ - account_info::{AccountInfo, Ref}, - program_error::ProgramError, - pubkey::Pubkey, + account::{AccountView, Ref}, + error::ProgramError, + Address, }; use super::{Account, AccountDiscriminator, ZeroableOption, SEED_LEN}; @@ -17,12 +17,12 @@ pub struct Buffer { /// Program ID that this metadata is associated with. /// /// Only for buffer PDA accounts; otherwise `None`. - pub program: ZeroableOption, + pub program: ZeroableOption
, /// Authority that can update this buffer. /// /// Only for buffer PDA accounts; otherwise `None`. - pub authority: ZeroableOption, + pub authority: ZeroableOption
, /// Indicates whether the buffer PDA is canonical. /// @@ -62,11 +62,11 @@ impl Buffer { /// 2. Account discriminator: it must match [`AccountDiscriminator::Buffer`]. /// 3. Borrow data: it must be allowed to borrow the account data. #[inline] - pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { - if !account_info.is_owned_by(&crate::ID) { + pub fn from_account_info(account_info: &AccountView) -> Result, ProgramError> { + if !account_info.owned_by(&crate::ID) { return Err(ProgramError::InvalidAccountOwner); } - let data = account_info.try_borrow_data()?; + let data = account_info.try_borrow()?; if data.len() < Self::LEN || data[0] != AccountDiscriminator::Buffer as u8 { return Err(ProgramError::InvalidAccountData); } @@ -88,12 +88,12 @@ impl Buffer { /// no mutable borrows of the account data. #[inline] pub unsafe fn from_account_info_unchecked( - account_info: &AccountInfo, + account_info: &AccountView, ) -> Result<&Self, ProgramError> { - if account_info.owner() != &crate::ID { + if !account_info.owned_by(&crate::ID) { return Err(ProgramError::InvalidAccountOwner); } - let data = account_info.borrow_data_unchecked(); + let data = account_info.borrow_unchecked(); if data.len() < Self::LEN || data[0] != AccountDiscriminator::Buffer as u8 { return Err(ProgramError::InvalidAccountData); } @@ -150,11 +150,11 @@ impl Buffer { } impl Account for Buffer { - fn get_authority(&self) -> Option<&Pubkey> { + fn get_authority(&self) -> Option<&Address> { self.authority.as_ref() } - fn is_canonical(&self, program: &Pubkey) -> bool { + fn is_canonical(&self, program: &Address) -> bool { self.canonical() && self.program.as_ref() == Some(program) } } diff --git a/program/src/state/data.rs b/program/src/state/data.rs index 3c01c6b..51434fc 100644 --- a/program/src/state/data.rs +++ b/program/src/state/data.rs @@ -1,4 +1,4 @@ -use pinocchio::{program_error::ProgramError, pubkey::Pubkey}; +use pinocchio::{error::ProgramError, Address}; use super::{DataSource, ZeroableOption}; @@ -52,8 +52,8 @@ pub struct UrlData<'a>(pub &'a str); /// External data contains a reference (address) to an external account /// and an offset and an optional length to specify the data range. pub struct ExternalData { - /// Pubkey of the external account. - pub address: Pubkey, + /// Address of the external account. + pub address: Address, /// Offset of the data in the external account. /// diff --git a/program/src/state/header.rs b/program/src/state/header.rs index 4da50e8..4613b9e 100644 --- a/program/src/state/header.rs +++ b/program/src/state/header.rs @@ -1,7 +1,7 @@ use pinocchio::{ - account_info::{AccountInfo, Ref}, - program_error::ProgramError, - pubkey::Pubkey, + account::{AccountView, Ref}, + error::ProgramError, + Address, }; use super::{ @@ -16,12 +16,12 @@ pub struct Header { pub(crate) discriminator: u8, /// Program ID that this metadata is associated with. - pub program: Pubkey, + pub program: Address, /// Authority that can update this metadata. /// /// For canonical metadata accounts, the authority can be `None`. - pub authority: ZeroableOption, + pub authority: ZeroableOption
, /// Indicates whether the metadata is mutable. pub(crate) mutable: u8, @@ -99,11 +99,11 @@ impl Header { /// 2. Account discriminator: it must match [`AccountDiscriminator::Metadata`]. /// 3. Borrow data: it must be allowed to borrow the account data. #[inline] - pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { - if !account_info.is_owned_by(&crate::ID) { + pub fn from_account_info(account_info: &AccountView) -> Result, ProgramError> { + if !account_info.owned_by(&crate::ID) { return Err(ProgramError::InvalidAccountOwner); } - let data = account_info.try_borrow_data()?; + let data = account_info.try_borrow()?; if data.len() < Self::LEN || data[0] != AccountDiscriminator::Metadata as u8 { return Err(ProgramError::InvalidAccountData); } @@ -125,12 +125,12 @@ impl Header { /// no mutable borrows of the account data. #[inline] pub unsafe fn from_account_info_unchecked( - account_info: &AccountInfo, + account_info: &AccountView, ) -> Result<&Self, ProgramError> { - if account_info.owner() != &crate::ID { + if !account_info.owned_by(&crate::ID) { return Err(ProgramError::InvalidAccountOwner); } - let data = account_info.borrow_data_unchecked(); + let data = account_info.borrow_unchecked(); if data.len() < Self::LEN || data[0] != AccountDiscriminator::Metadata as u8 { return Err(ProgramError::InvalidAccountData); } @@ -187,11 +187,11 @@ impl Header { } impl Account for Header { - fn get_authority(&self) -> Option<&Pubkey> { + fn get_authority(&self) -> Option<&Address> { self.authority.as_ref() } - fn is_canonical(&self, program: &Pubkey) -> bool { + fn is_canonical(&self, program: &Address) -> bool { self.canonical() && self.program == *program } } diff --git a/program/src/state/mod.rs b/program/src/state/mod.rs index 559b27b..64bd859 100644 --- a/program/src/state/mod.rs +++ b/program/src/state/mod.rs @@ -2,11 +2,7 @@ pub mod buffer; pub mod data; pub mod header; -use pinocchio::{ - program_error::ProgramError, - pubkey::{Pubkey, PUBKEY_BYTES}, - ProgramResult, -}; +use pinocchio::{address::ADDRESS_BYTES, error::ProgramError, Address, ProgramResult}; use data::{Data, ExternalData}; use header::Header; @@ -52,11 +48,11 @@ impl<'a> Metadata<'a> { /// Utility trait for an account. pub(crate) trait Account { /// Returns the account authority, if there is one. - fn get_authority(&self) -> Option<&Pubkey>; + fn get_authority(&self) -> Option<&Address>; /// Indicates whether the PDA represents a canonical PDA for /// the given program. - fn is_canonical(&self, program: &Pubkey) -> bool; + fn is_canonical(&self, program: &Address) -> bool; } /// Account discriminators. @@ -177,7 +173,7 @@ impl DataSource { (DataSource::Direct | DataSource::Url, l) if l > 0 => Ok(()), (DataSource::External, ExternalData::LEN) => Ok(()), _ => { - // TODO: use custom error (invalid data length) + // custom error (invalid data length) Err(ProgramError::InvalidAccountData) } } @@ -207,8 +203,8 @@ pub trait Zeroable: PartialEq + Sized { } } -impl Zeroable for Pubkey { - const ZERO: Self = [0u8; PUBKEY_BYTES]; +impl Zeroable for Address { + const ZERO: Self = Address::new_from_array([0u8; ADDRESS_BYTES]); } impl Zeroable for u32 { diff --git a/program/tests/setup/mod.rs b/program/tests/setup/mod.rs index 4ee4e49..f52fea5 100644 --- a/program/tests/setup/mod.rs +++ b/program/tests/setup/mod.rs @@ -17,7 +17,7 @@ use solana_pubkey::Pubkey; use solana_rent::Rent; use solana_sdk_ids::bpf_loader_upgradeable; -pub const PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_program_metadata::ID); +pub const PROGRAM_ID: Pubkey = Pubkey::new_from_array(*spl_program_metadata::ID.as_array()); pub fn create_account(data: Vec, executable: bool, owner: Pubkey) -> Account { let space = data.len(); @@ -68,12 +68,22 @@ pub fn process_instructions( instructions: &[(&Instruction, &[Check])], accounts: &[(Pubkey, Account)], ) { - let mollusk = Mollusk::new(&PROGRAM_ID, "spl_program_metadata"); + let mut mollusk = Mollusk::new(&PROGRAM_ID, "spl_program_metadata"); + let mut rent = Rent::default(); + rent.lamports_per_byte_year = rent + .lamports_per_byte_year + .saturating_mul(rent.exemption_threshold as u64); + mollusk.sysvars.rent = rent; + mollusk.process_and_validate_instruction_chain(instructions, accounts); } pub fn rent_sysvar() -> Account { - create_account_for_test(&Rent::default()) + let mut rent = Rent::default(); + rent.lamports_per_byte_year = rent + .lamports_per_byte_year + .saturating_mul(rent.exemption_threshold as u64); + create_account_for_test(&rent) } pub fn setup_program_account(program_data: &Pubkey) -> Account { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index cf6d0f5..b67e7d5 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.86.0" +channel = "1.89.0"