diff --git a/lints/duplicate_mutable_accounts/.cargo/config.toml b/lints/duplicate_mutable_accounts/.cargo/config.toml new file mode 100644 index 0000000..6f48fa3 --- /dev/null +++ b/lints/duplicate_mutable_accounts/.cargo/config.toml @@ -0,0 +1,14 @@ +[build] +target-dir = "../../target" + +[target.aarch64-apple-darwin] +linker = "dylint-link" + +[target.x86_64-apple-darwin] +linker = "dylint-link" + +[target.x86_64-unknown-linux-gnu] +linker = "dylint-link" + +[target.x86_64-pc-windows-msvc] +linker = "dylint-link" diff --git a/lints/duplicate_mutable_accounts/Cargo.lock b/lints/duplicate_mutable_accounts/Cargo.lock new file mode 100644 index 0000000..1d625fe --- /dev/null +++ b/lints/duplicate_mutable_accounts/Cargo.lock @@ -0,0 +1,1799 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.7", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9b75d05b6b4ac9d95bb6e3b786b27d3a708c4c5a87c92ffaa25bbe9ae4c5d91" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "485351a6d8157750d10d88c8e256f1bf8339262b2220ae9125aed3471309b5de" +dependencies = [ + "anchor-syn", + "anyhow", + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc632c540913dd051a78b00587cc47f57013d303163ddfaf4fa18717f7ccc1e0" +dependencies = [ + "anchor-syn", + "proc-macro2", + "syn", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5bd1dcfa7f3bc22dacef233d70a9e0bee269c4ac484510662f257cba2353a1" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c6f9e6ce551ac9a177a45c99a65699a860c9e95fac68675138af1246e2591b0" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "anchor-attribute-interface" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d104aa17418cb329ed7418b227e083d5f326a27f26ce98f5d92e33da62a5f459" +dependencies = [ + "anchor-syn", + "anyhow", + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6831b920b173c004ddf7ae1167d1d25e9f002ffcb1773bbc5c7ce532a4441e1" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "anchor-attribute-state" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde147b10c71d95dc679785db0b5f3abac0091f789167aa62ac0135e2f54e8b9" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cde98a0e1a56046b040ff591dfda391f88917af2b6487d02b45093c05be3514" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "anchor-lang" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a85dd2c5e29e20c7f4701a43724d6cd5406d0ee5694705522e43da0f26542a84" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-interface", + "anchor-attribute-program", + "anchor-attribute-state", + "anchor-derive-accounts", + "arrayref", + "base64 0.13.0", + "bincode", + "borsh", + "bytemuck", + "solana-program", + "thiserror", +] + +[[package]] +name = "anchor-syn" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03549dc2eae0b20beba6333b14520e511822a6321cdb1760f841064a69347316" +dependencies = [ + "anyhow", + "bs58 0.3.1", + "heck 0.3.3", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "serde", + "serde_json", + "sha2", + "syn", + "thiserror", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake3" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive", + "hashbrown", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bs58" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c53dfa917ec274df8ed3c572698f381a24eef2efba9492d797301b72b6db408a" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd2f4180c5721da6335cc9e9061cce522b87a35e51cc57636d28d22a9863c80" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clippy_utils" +version = "0.1.65" +source = "git+https://github.com/rust-lang/rust-clippy?rev=2b2190cb5667cdd276a24ef8b9f3692209c54a89#2b2190cb5667cdd276a24ef8b9f3692209c54a89" +dependencies = [ + "arrayvec", + "if_chain", + "rustc-semver", +] + +[[package]] +name = "compiletest_rs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262134ef87408da1ddfe45e33daa0ca43b75286d6b1076446e602d264cf9847e" +dependencies = [ + "diff", + "filetime", + "getopts", + "lazy_static", + "libc", + "log", + "miow", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tester", + "winapi", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "duplicate_mutable_accounts" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "clippy_utils", + "dylint_linting", + "dylint_testing", + "if_chain", + "proc-macro2", + "quote", + "solana-lints", +] + +[[package]] +name = "dylint" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd14a51dd176304a879c6d41bcce9b537618c7cbe67a0e0edf8015681ad5d3d" +dependencies = [ + "ansi_term", + "anyhow", + "atty", + "cargo_metadata", + "dirs", + "dylint_internal", + "heck 0.4.0", + "lazy_static", + "log", + "once_cell", + "semver", + "serde", + "serde_json", + "tempfile", + "walkdir", +] + +[[package]] +name = "dylint_internal" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fbed59f03a099ecc70f53214c4da67aa92ffb75c115418b6e74364b9185837" +dependencies = [ + "ansi_term", + "anyhow", + "cargo_metadata", + "if_chain", + "log", + "rust-embed", + "sedregex", + "walkdir", +] + +[[package]] +name = "dylint_linting" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d3be89f70c448bbecb3dcb30d76caeae6c14a4cc826d86226b7862ef778f8d" +dependencies = [ + "paste", +] + +[[package]] +name = "dylint_testing" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d39ee540202ded889a1f660b3cbf25dce88c453bdccbb59eb8d5e2d4079883f9" +dependencies = [ + "anyhow", + "cargo_metadata", + "compiletest_rs", + "dylint", + "dylint_internal", + "env_logger", + "lazy_static", + "once_cell", + "regex", + "serde_json", + "tempfile", +] + +[[package]] +name = "either" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "filetime" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "serde", + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "globset" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a79b39c93a7a5a27eeaf9a23b5ff43f1b9e0ad6b1cdd441140ae53c35613fc7" +dependencies = [ + "libc", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.7", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rust-embed" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a17e5ac65b318f397182ae94e532da0ba56b88dd1200b774715d36c4943b1c3" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029" +dependencies = [ + "globset", + "sha2", + "walkdir", +] + +[[package]] +name = "rustc-semver" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustfix" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" +dependencies = [ + "anyhow", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "rustversion" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sedregex" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19411e23596093f03bbd11dc45603b6329bb4bfec77b9fd13e2b9fc9b02efe3e" +dependencies = [ + "regex", +] + +[[package]] +name = "semver" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "solana-frozen-abi" +version = "1.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4fcb89eb3d0f30bd4b4a31ad1825c9d95cd638509acead00969d7601713288" +dependencies = [ + "bs58 0.4.0", + "bv", + "generic-array", + "log", + "memmap2", + "rustc_version", + "serde", + "serde_derive", + "sha2", + "solana-frozen-abi-macro", + "solana-logger", + "thiserror", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63ab101db88ecccd8da34065b9097b88367e0744fdfd05cb7de87b4ede3717f" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "solana-lints" +version = "0.1.0" + +[[package]] +name = "solana-logger" +version = "1.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1805d52fc8277a84c4803c7850c8f41471b57fb0dec7750338955ad6e43e2" +dependencies = [ + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "solana-program" +version = "1.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5deafc4902425d40197f74166640300dd20b078e4ffd518c1bb56ceb7e01680" +dependencies = [ + "base64 0.13.0", + "bincode", + "bitflags", + "blake3", + "borsh", + "borsh-derive", + "bs58 0.4.0", + "bv", + "bytemuck", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.1.16", + "itertools", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "num-derive", + "num-traits", + "parking_lot", + "rand", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "sha2", + "sha3", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-logger", + "solana-sdk-macro", + "thiserror", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db4c93bd43c91290ad54fe6ff86179a859954f196507c4789a4876d38a62f17" +dependencies = [ + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "tester" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb" +dependencies = [ + "cfg-if", + "getopts", + "libc", + "num_cpus", + "term", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/lints/duplicate_mutable_accounts/Cargo.toml b/lints/duplicate_mutable_accounts/Cargo.toml new file mode 100644 index 0000000..567f9f5 --- /dev/null +++ b/lints/duplicate_mutable_accounts/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "duplicate_mutable_accounts" +version = "0.1.0" +authors = ["authors go here"] +description = "decription goes here" +edition = "2018" +publish = false + +[lib] +crate-type = ["cdylib"] + +[[example]] +name = "insecure" +path = "ui/insecure/src/lib.rs" + +[[example]] +name = "insecure-2" +path = "ui/insecure-2/src/lib.rs" + +[[example]] +name = "secure" +path = "ui/secure/src/lib.rs" + +[[example]] +name = "recommended" +path = "ui/recommended/src/lib.rs" + +[[example]] +name = "recommended-2" +path = "ui/recommended-2/src/lib.rs" + +[dependencies] +clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "2b2190cb5667cdd276a24ef8b9f3692209c54a89" } +dylint_linting = "2.0.1" +if_chain = "1.0.2" +proc-macro2 = "1.0.40" +quote = "1.0.20" +solana-lints = { path = "../../crate" } + +[dev-dependencies] +anchor-lang = "0.24.2" +dylint_testing = "2.0.1" + +[workspace] + +[package.metadata.rust-analyzer] +rustc_private = true diff --git a/lints/duplicate_mutable_accounts/README.md b/lints/duplicate_mutable_accounts/README.md new file mode 100644 index 0000000..2acf315 --- /dev/null +++ b/lints/duplicate_mutable_accounts/README.md @@ -0,0 +1,47 @@ +# duplicate_mutable_accounts + +**What it does:** Checks to make sure there is a key check on identical Anchor accounts. +The key check serves to make sure that two identical accounts do not have the same key, +ie, they are unique. An Anchor account (`Account<'info, T>`) is identical to another if +the generic parameter `T` is the same type for each account. + +**Why is this bad?** If a program contains two identical, mutable Anchor accounts, and +performs some operation on those accounts, then a user could pass in the same account +twice. Then any previous operations may be overwritten by the last operation, which may +not be what the program wanted if it expected different accounts. + +**Known problems:** If a program is not using the anchor `#[account]` macro constraints, +and is instead using checks in the function bodies, and the program uses boolean operator +&& or || to link constraints in a single if statement, the lint will flag this as a false +positive since the lint only catches statements with `==` or `!=`. + +Another issue is if a program uses an if statement such as `a.key() == b.key()` and then +continues to modify the accounts, then this will not be caught. The reason is because the +lint regards expressions with `==` as a secure check, since it assumes the program will +then return an error (see the secure example). However, it does not explicitly check that +an error is returned. + +In general, this lint will catch all vulnerabilities if the anchor macro constraints are +used (see the recommended example). It is not as robust if alternative methods are utilized. +Thus it is encouraged to use the anchor `#[account]` macro constraints. + +**Example:** + +```rust +#[derive(Accounts)] +pub struct Update<'info> { + user_a: Account<'info, User>, + user_b: Account<'info, User>, +} +``` + +Use instead: + +```rust +#[derive(Accounts)] +pub struct Update<'info> { + #[account(constraint = user_a.key() != user_b.key())] + user_a: Account<'info, User>, + user_b: Account<'info, User>, +} +``` diff --git a/lints/duplicate_mutable_accounts/rust-toolchain b/lints/duplicate_mutable_accounts/rust-toolchain new file mode 100644 index 0000000..ccdc31c --- /dev/null +++ b/lints/duplicate_mutable_accounts/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2022-08-11" +components = ["llvm-tools-preview", "rustc-dev"] diff --git a/lints/duplicate_mutable_accounts/src/alternate_constraint.rs b/lints/duplicate_mutable_accounts/src/alternate_constraint.rs new file mode 100644 index 0000000..b95aed5 --- /dev/null +++ b/lints/duplicate_mutable_accounts/src/alternate_constraint.rs @@ -0,0 +1,112 @@ +use std::collections::HashMap; + +use rustc_hir::{ + def_id::DefId, + intravisit::{walk_expr, Visitor}, + BinOpKind, Body, Expr, ExprKind, Mutability, +}; +use rustc_lint::LateContext; +use rustc_middle::ty::TyKind as MiddleTyKind; + +use crate::ANCHOR_ACCOUNT_GENERIC_ARG_COUNT; +use clippy_utils::{ty::match_type, SpanlessEq}; +use if_chain::if_chain; +use solana_lints::paths; + +/// Stores the accounts and if-statements (constraints) found in a function body. +pub struct Values<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + /// Lists of account expressions, partitioned by the Account type T + pub accounts: HashMap>>, + /// List of tuples, where (x, y), where x is the left operand of the if statement and y is the right + pub if_statements: Vec<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>, +} + +impl<'cx, 'tcx> Values<'cx, 'tcx> { + pub fn new(cx: &'cx LateContext<'tcx>) -> Self { + Values { + cx, + accounts: HashMap::new(), + if_statements: Vec::new(), + } + } + + pub fn get_referenced_accounts_and_if_statements(&mut self, body: &'tcx Body<'tcx>) -> &Self { + self.visit_expr(&body.value); + self + } + + /// Checks if there is a valid key constraint for `first_account` and `second_account`. + /// TODO: if == relation used, should return some error in the THEN block + pub fn check_key_constraint( + &self, + first_account: &Expr<'_>, + second_account: &Expr<'_>, + ) -> bool { + for (left, right) in &self.if_statements { + if_chain! { + if let ExprKind::MethodCall(path_seg_left, exprs_left, _span) = left.kind; + if let ExprKind::MethodCall(path_seg_right, exprs_right, _span) = right.kind; + if path_seg_left.ident.name.as_str() == "key" + && path_seg_right.ident.name.as_str() == "key"; + if !exprs_left.is_empty() && !exprs_right.is_empty(); + let mut spanless_eq = SpanlessEq::new(self.cx); + if (spanless_eq.eq_expr(&exprs_left[0], first_account) + && spanless_eq.eq_expr(&exprs_right[0], second_account)) + || (spanless_eq.eq_expr(&exprs_left[0], second_account) + && spanless_eq.eq_expr(&exprs_right[0], first_account)); + then { + return true; + } + } + } + false + } +} + +impl<'cx, 'tcx> Visitor<'tcx> for Values<'cx, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if_chain! { + // get mutable reference expressions + if let ExprKind::AddrOf(_, mutability, mut_expr) = expr.kind; + if let Mutability::Mut = mutability; + // check type of expr == Account<'info, T> + let middle_ty = self.cx.typeck_results().expr_ty(mut_expr); + // let mut_expr_def_id = self.cx.tcx.hir().local_def_id(mut_expr.hir_id).to_def_id(); + // let middle_ty = self.cx.tcx.type_of(mut_expr_def_id); + if match_type(self.cx, middle_ty, &paths::ANCHOR_LANG_ACCOUNT); + // grab T generic parameter + if let MiddleTyKind::Adt(_adt_def, substs) = middle_ty.kind(); + if substs.len() == ANCHOR_ACCOUNT_GENERIC_ARG_COUNT; + let account_type = substs[1].expect_ty(); + if let Some(adt_def) = account_type.ty_adt_def(); + then { + let def_id = adt_def.did(); + if let Some(exprs) = self.accounts.get_mut(&def_id) { + let mut spanless_eq = SpanlessEq::new(self.cx); + // check that expr is not a duplicate within its particular key-pair + if exprs.iter().all(|e| !spanless_eq.eq_expr(e, mut_expr)) { + exprs.push(mut_expr); + } + } else { + self.accounts.insert(def_id, vec![mut_expr]); + } + } + } + + // get if statements + if_chain! { + if let ExprKind::If(wrapped_if_expr, _then, _else_opt) = expr.kind; + if let ExprKind::DropTemps(if_expr) = wrapped_if_expr.kind; + if let ExprKind::Binary(op, left, right) = if_expr.kind; + // TODO: leaves out || or &&. Could implement something that pulls apart + // an if expr that is of this form into individual == or != comparisons + if let BinOpKind::Ne | BinOpKind::Eq = op.node; + then { + // println!("{:#?}, {:#?}", expr, then); + self.if_statements.push((left, right)); + } + } + walk_expr(self, expr); + } +} diff --git a/lints/duplicate_mutable_accounts/src/anchor_constraint.rs b/lints/duplicate_mutable_accounts/src/anchor_constraint.rs new file mode 100644 index 0000000..4a44c4a --- /dev/null +++ b/lints/duplicate_mutable_accounts/src/anchor_constraint.rs @@ -0,0 +1,112 @@ +use std::default::Default; + +use rustc_ast::{ + token::{Delimiter, Token, TokenKind}, + tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}, +}; +use rustc_hir::{def::Res, FieldDef, GenericArg, QPath, TyKind}; +use rustc_span::{ + def_id::DefId, + symbol::{Ident, Symbol}, + DUMMY_SP, +}; + +use crate::ANCHOR_ACCOUNT_GENERIC_ARG_COUNT; +use if_chain::if_chain; + +/// Returns the `DefId` of the anchor account type, ie, `T` in `Account<'info, T>`. +/// Returns `None` if the type of `field` is not an anchor account. +pub fn get_anchor_account_type_def_id(field: &FieldDef) -> Option { + if_chain! { + if let TyKind::Path(qpath) = &field.ty.kind; + if let QPath::Resolved(_, path) = qpath; + if !path.segments.is_empty(); + if let Some(generic_args) = path.segments[0].args; + if generic_args.args.len() == ANCHOR_ACCOUNT_GENERIC_ARG_COUNT; + if let GenericArg::Type(hir_ty) = &generic_args.args[1]; + then { + get_def_id(hir_ty) + } else { + None + } + } +} + +/// Returns the `DefId` of `ty`, an hir type. Returns `None` if cannot resolve type. +pub fn get_def_id(ty: &rustc_hir::Ty) -> Option { + if_chain! { + if let TyKind::Path(qpath) = &ty.kind; + if let QPath::Resolved(_, path) = qpath; + if let Res::Def(_, def_id) = path.res; + then { + Some(def_id) + } else { + None + } + } +} + +/// Returns a `TokenStream` of form: `a`.key() != `b`.key(). +pub fn create_key_check_constraint_tokenstream(a: Symbol, b: Symbol) -> TokenStream { + // TODO: may be more efficient way to do this, since the stream is effectively fixed + // and determined. Only two tokens are variable. + let constraint = vec![ + create_token_from_ident(a.as_str()), + TokenTree::Token(Token::new(TokenKind::Dot, DUMMY_SP), Spacing::Alone), + create_token_from_ident("key"), + TokenTree::Delimited( + DelimSpan::dummy(), + Delimiter::Parenthesis, + TokenStream::new(vec![]), + ), + TokenTree::Token(Token::new(TokenKind::Ne, DUMMY_SP), Spacing::Alone), + create_token_from_ident(b.as_str()), + TokenTree::Token(Token::new(TokenKind::Dot, DUMMY_SP), Spacing::Alone), + create_token_from_ident("key"), + TokenTree::Delimited( + DelimSpan::dummy(), + Delimiter::Parenthesis, + TokenStream::new(vec![]), + ), + ]; + + TokenStream::new(constraint) +} + +/// Returns a `TokenTree::Token` which has `TokenKind::Ident`, with the string set to `s`. +fn create_token_from_ident(s: &str) -> TokenTree { + let ident = Ident::from_str(s); + TokenTree::Token(Token::from_ast_ident(ident), Spacing::Alone) +} + +#[derive(Debug, Default)] +pub struct Streams(pub Vec); + +impl Streams { + /// Returns true if `self` has a `TokenStream` that `other` is a substream of + pub fn contains(&self, other: &TokenStream) -> bool { + self.0 + .iter() + .any(|token_stream| Self::is_substream(token_stream, other)) + } + + /// Returns true if `other` is a substream of `stream`. By substream we mean in the sense of a substring. + // NOTE: a possible optimization is when a match is found, to remove the matched + // TokenTrees from the TokenStream, since the constraint has been "checked" so it never + // needs to be validated again. This cuts down the number of comparisons. + fn is_substream(stream: &TokenStream, other: &TokenStream) -> bool { + for i in 0..stream.len() { + if other + .trees() + .enumerate() + .all(|(j, other_token)| match stream.trees().nth(i + j) { + Some(token_tree) => token_tree.eq_unspanned(other_token), + None => false, + }) + { + return true; + } + } + false + } +} diff --git a/lints/duplicate_mutable_accounts/src/lib.rs b/lints/duplicate_mutable_accounts/src/lib.rs new file mode 100644 index 0000000..611dfe4 --- /dev/null +++ b/lints/duplicate_mutable_accounts/src/lib.rs @@ -0,0 +1,248 @@ +#![feature(rustc_private)] +#![warn(unused_extern_crates)] + +extern crate rustc_ast; +extern crate rustc_hir; +extern crate rustc_middle; +extern crate rustc_span; + +mod alternate_constraint; +mod anchor_constraint; + +use crate::alternate_constraint::Values; +use crate::anchor_constraint::{ + create_key_check_constraint_tokenstream, get_anchor_account_type_def_id, get_def_id, Streams, +}; + +use std::collections::{HashMap, VecDeque}; +use std::default::Default; + +use rustc_ast::{AttrKind, Attribute, MacArgs}; +use rustc_hir::{intravisit::FnKind, Body, FnDecl, HirId, VariantData}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_span::{def_id::DefId, symbol::Symbol, Span}; + +use clippy_utils::{diagnostics::span_lint_and_help, ty::match_type}; +use if_chain::if_chain; +use solana_lints::paths; + +const ANCHOR_ACCOUNT_GENERIC_ARG_COUNT: usize = 2; + +dylint_linting::impl_late_lint! { + /// **What it does:** Checks to make sure there is a key check on identical Anchor accounts. + /// The key check serves to make sure that two identical accounts do not have the same key, + /// ie, they are unique. An Anchor account (`Account<'info, T>`) is identical to another if + /// the generic parameter `T` is the same type for each account. + /// + /// **Why is this bad?** If a program contains two identical, mutable Anchor accounts, and + /// performs some operation on those accounts, then a user could pass in the same account + /// twice. Then any previous operations may be overwritten by the last operation, which may + /// not be what the program wanted if it expected different accounts. + /// + /// **Known problems:** If a program is not using the anchor #[account] macro constraints, + /// and is instead using checks in the function bodies, and the program uses boolean operator + /// && or || to link constraints in a single if statement, the lint will flag this as a false + /// positive since the lint only catches statements with `==` or `!=`. + /// Another issue is if a program uses an if statement such as `a.key() == b.key()` and then + /// continues to modify the accounts, then this will not be caught. The reason is because the + /// lint regards expressions with `==` as a secure check, since it assumes the program will + /// then return an error (see the secure example). However, it does not explicitly check that + /// an error is returned. + /// + /// In general, this lint will catch all vulnerabilities if the anchor macro constraints are + /// used (see the recommended example). It is not as robust if alternative methods are utilized. + /// Thus it is encouraged to use the anchor `#[account]` macro constraints. + /// + /// **Example:** + /// + /// ```rust + /// #[derive(Accounts)] + /// pub struct Update<'info> { + /// user_a: Account<'info, User>, + /// user_b: Account<'info, User>, + /// } + /// ``` + /// Use instead: + /// ```rust + /// #[derive(Accounts)] + /// pub struct Update<'info> { + /// #[account(constraint = user_a.key() != user_b.key())] + /// user_a: Account<'info, User>, + /// user_b: Account<'info, User>, + /// } + /// ``` + pub DUPLICATE_MUTABLE_ACCOUNTS, + Warn, + "does not check if multiple identical Anchor accounts have different keys", + DuplicateMutableAccounts::default() +} + +#[derive(Default, Debug)] +struct DuplicateMutableAccounts { + /// Lists of Anchor accounts found in structs that derive Anchor `Accounts` trait, partitioned by Anchor account type + anchor_accounts: HashMap>, + /// List of Anchor `#[account]` macro constraints + anchor_macro_constraints: Streams, + /// List of pairs of Anchor accounts with same types, without any alternate constraint + spans: Vec<(Span, Span)>, + /// Indicates if alternate constraints were used or not + no_alternate_constraints: bool, +} + +impl<'tcx> LateLintPass<'tcx> for DuplicateMutableAccounts { + fn check_struct_def(&mut self, cx: &LateContext<'tcx>, variant_data: &'tcx VariantData<'tcx>) { + if let VariantData::Struct(fields, _) = variant_data { + fields.iter().for_each(|field| { + if_chain! { + if let Some(def_id) = get_def_id(field.ty); + let middle_ty = cx.tcx.type_of(def_id); + if match_type(cx, middle_ty, &paths::ANCHOR_LANG_ACCOUNT); + if let Some(account_id) = get_anchor_account_type_def_id(field); + then { + if let Some(v) = self.anchor_accounts.get_mut(&account_id) { + v.push((field.ident.name, field.span)); + } else { + self.anchor_accounts + .insert(account_id, vec![(field.ident.name, field.span)]); + } + } + } + }); + } + } + + fn check_attribute(&mut self, _: &LateContext<'tcx>, attribute: &'tcx Attribute) { + if_chain! { + if let AttrKind::Normal(attr_item, _) = &attribute.kind; + let name = attribute.name_or_empty(); + if name.as_str() == "account"; + if let MacArgs::Delimited(_, _, token_stream) = &attr_item.args; + then { + self.anchor_macro_constraints.0.push(token_stream.clone()); + } + } + } + + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + span: Span, + _: HirId, + ) { + if !span.from_expansion() { + let mut values = Values::new(cx); + values.get_referenced_accounts_and_if_statements(body); + + values.accounts.values().for_each(|exprs| { + if exprs.len() > 1 { + self.no_alternate_constraints = true; // assume no alternate constraints + for current in 0..exprs.len() - 1 { + for next in current + 1..exprs.len() { + if values.check_key_constraint(exprs[current], exprs[next]) { + // if there is at least one alt constraint, set flag to false + self.no_alternate_constraints = false; + } else { + self.spans.push((exprs[current].span, exprs[next].span)); + } + } + } + } + }); + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + // if no anchor constraints, check for alternate constraints + if self.anchor_macro_constraints.0.is_empty() { + // if no alternate constraints either, recommend using anchor constraints + if self.no_alternate_constraints { + for ident_accounts in self.anchor_accounts.values() { + if ident_accounts.len() > 1 { + for current in 0..ident_accounts.len() - 1 { + for next in current + 1..ident_accounts.len() { + let first = ident_accounts[current]; + let second = ident_accounts[next]; + span_lint_and_help( + cx, + DUPLICATE_MUTABLE_ACCOUNTS, + first.1, + &format!("{} and {} have identical account types but do not have a key check constraint", first.0, second.0), + Some(second.1), + &format!("add an anchor key check constraint: #[account(constraint = {}.key() != {}.key())]", first.0, second.0) + ); + } + } + } + } + } else { + // flag lint for missing alternate constraints + for (first, second) in &self.spans { + span_lint_and_help( + cx, + DUPLICATE_MUTABLE_ACCOUNTS, + *first, + &format!("the expressions on line {:?} and {:?} have identical Account types, yet do not contain a proper key check.", first, second), + Some(*second), + "add a key check to make sure the accounts have different keys, e.g., x.key() != y.key()", + ); + } + } + } else { + // if using anchor constraints, check and flag for missing anchor constraints + for ident_accounts in self.anchor_accounts.values() { + if ident_accounts.len() > 1 { + let mut deq = VecDeque::from(ident_accounts.clone()); + for _ in 0..deq.len() - 1 { + let (first, first_span) = deq.pop_front().unwrap(); + for (other, other_span) in &deq { + let stream = create_key_check_constraint_tokenstream(first, *other); + let symmetric_stream = + create_key_check_constraint_tokenstream(*other, first); + + if !(self.anchor_macro_constraints.contains(&stream) + || self.anchor_macro_constraints.contains(&symmetric_stream)) + { + span_lint_and_help( + cx, + DUPLICATE_MUTABLE_ACCOUNTS, + first_span, + &format!("{} and {} have identical account types but do not have a key check constraint", first, other), + Some(*other_span), + &format!("add an anchor key check constraint: #[account(constraint = {}.key() != {}.key())]", first, other) + ); + } + } + } + } + } + } + } +} + +#[test] +fn insecure() { + dylint_testing::ui_test_example(env!("CARGO_PKG_NAME"), "insecure"); +} + +#[test] +fn insecure_2() { + dylint_testing::ui_test_example(env!("CARGO_PKG_NAME"), "insecure-2"); +} + +#[test] +fn secure() { + dylint_testing::ui_test_example(env!("CARGO_PKG_NAME"), "secure"); +} + +#[test] +fn recommended() { + dylint_testing::ui_test_example(env!("CARGO_PKG_NAME"), "recommended"); +} + +#[test] +fn recommended_2() { + dylint_testing::ui_test_example(env!("CARGO_PKG_NAME"), "recommended-2"); +} diff --git a/lints/duplicate_mutable_accounts/ui/insecure-2/Cargo.toml b/lints/duplicate_mutable_accounts/ui/insecure-2/Cargo.toml new file mode 100644 index 0000000..8f90916 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure-2/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "duplicate-mutable-accounts-insecure-2" +version = "0.1.0" +description = "Does not have all required key constraint checks" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "duplicate_mutable_accounts_insecure_2" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[workspace] + +[dependencies] +anchor-lang = "0.24.2" diff --git a/lints/duplicate_mutable_accounts/ui/insecure-2/Xargo.toml b/lints/duplicate_mutable_accounts/ui/insecure-2/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure-2/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/lints/duplicate_mutable_accounts/ui/insecure-2/src/lib.rs b/lints/duplicate_mutable_accounts/ui/insecure-2/src/lib.rs new file mode 100644 index 0000000..1ab1576 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure-2/src/lib.rs @@ -0,0 +1,38 @@ +use anchor_lang::prelude::*; + +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + +#[program] +pub mod duplicate_mutable_accounts_insecure { + use super::*; + + pub fn update( + ctx: Context, + a: u64, + b: u64, + c: u64, + ) -> anchor_lang::solana_program::entrypoint::ProgramResult { + let user_a = &mut ctx.accounts.user_a; + let user_b = &mut ctx.accounts.user_b; + let user_c = &mut ctx.accounts.user_c; + + user_a.data = a; + user_b.data = b; + user_c.data = c; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Update<'info> { + user_a: Account<'info, User>, + user_b: Account<'info, User>, + user_c: Account<'info, User>, +} + +#[account] +pub struct User { + data: u64, +} + +fn main() {} diff --git a/lints/duplicate_mutable_accounts/ui/insecure-2/src/lib.stderr b/lints/duplicate_mutable_accounts/ui/insecure-2/src/lib.stderr new file mode 100644 index 0000000..2dcf128 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure-2/src/lib.stderr @@ -0,0 +1,39 @@ +error: user_a and user_b have identical account types but do not have a key check constraint + --> $DIR/lib.rs:28:5 + | +LL | user_a: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D duplicate-mutable-accounts` implied by `-D warnings` +help: add an anchor key check constraint: #[account(constraint = user_a.key() != user_b.key())] + --> $DIR/lib.rs:29:5 + | +LL | user_b: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: user_a and user_c have identical account types but do not have a key check constraint + --> $DIR/lib.rs:28:5 + | +LL | user_a: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add an anchor key check constraint: #[account(constraint = user_a.key() != user_c.key())] + --> $DIR/lib.rs:30:5 + | +LL | user_c: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: user_b and user_c have identical account types but do not have a key check constraint + --> $DIR/lib.rs:29:5 + | +LL | user_b: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add an anchor key check constraint: #[account(constraint = user_b.key() != user_c.key())] + --> $DIR/lib.rs:30:5 + | +LL | user_c: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/lints/duplicate_mutable_accounts/ui/insecure/Cargo.toml b/lints/duplicate_mutable_accounts/ui/insecure/Cargo.toml new file mode 100644 index 0000000..8ade494 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "duplicate-mutable-accounts-insecure" +version = "0.1.0" +description = "Created with Anchor" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "duplicate_mutable_accounts_insecure" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[workspace] + +[dependencies] +anchor-lang = "0.24.2" diff --git a/lints/duplicate_mutable_accounts/ui/insecure/Xargo.toml b/lints/duplicate_mutable_accounts/ui/insecure/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/lints/duplicate_mutable_accounts/ui/insecure/src/lib.rs b/lints/duplicate_mutable_accounts/ui/insecure/src/lib.rs new file mode 100644 index 0000000..2e1d708 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure/src/lib.rs @@ -0,0 +1,34 @@ +use anchor_lang::prelude::*; + +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + +#[program] +pub mod duplicate_mutable_accounts_insecure { + use super::*; + + pub fn update( + ctx: Context, + a: u64, + b: u64, + ) -> anchor_lang::solana_program::entrypoint::ProgramResult { + let user_a = &mut ctx.accounts.user_a; + let user_b = &mut ctx.accounts.user_b; + + user_a.data = a; + user_b.data = b; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Update<'info> { + user_a: Account<'info, User>, + user_b: Account<'info, User>, +} + +#[account] +pub struct User { + data: u64, +} + +fn main() {} diff --git a/lints/duplicate_mutable_accounts/ui/insecure/src/lib.stderr b/lints/duplicate_mutable_accounts/ui/insecure/src/lib.stderr new file mode 100644 index 0000000..064418c --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/insecure/src/lib.stderr @@ -0,0 +1,15 @@ +error: user_a and user_b have identical account types but do not have a key check constraint + --> $DIR/lib.rs:25:5 + | +LL | user_a: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D duplicate-mutable-accounts` implied by `-D warnings` +help: add an anchor key check constraint: #[account(constraint = user_a.key() != user_b.key())] + --> $DIR/lib.rs:26:5 + | +LL | user_b: Account<'info, User>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/lints/duplicate_mutable_accounts/ui/recommended-2/Cargo.toml b/lints/duplicate_mutable_accounts/ui/recommended-2/Cargo.toml new file mode 100644 index 0000000..631313c --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/recommended-2/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "duplicate-mutable-accounts-recommended" +version = "0.1.0" +description = "Contains all necessary constraints for more than 2 duplicate accounts" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "duplicate_mutable_accounts_recommended" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = "0.24.2" diff --git a/lints/duplicate_mutable_accounts/ui/recommended-2/Xargo.toml b/lints/duplicate_mutable_accounts/ui/recommended-2/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/recommended-2/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/lints/duplicate_mutable_accounts/ui/recommended-2/src/lib.rs b/lints/duplicate_mutable_accounts/ui/recommended-2/src/lib.rs new file mode 100644 index 0000000..338054b --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/recommended-2/src/lib.rs @@ -0,0 +1,37 @@ +use anchor_lang::prelude::*; + +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + +#[program] +pub mod duplicate_mutable_accounts_recommended { + use super::*; + + pub fn update( + ctx: Context, + a: u64, + b: u64, + ) -> anchor_lang::solana_program::entrypoint::ProgramResult { + let user_a = &mut ctx.accounts.user_a; + let user_b = &mut ctx.accounts.user_b; + + user_a.data = a; + user_b.data = b; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Update<'info> { + #[account(constraint = user_a.key() != user_b.key() && user_a.key() != user_c.key())] + #[account(constraint = user_c.key() != user_b.key())] + user_a: Account<'info, User>, + user_b: Account<'info, User>, + user_c: Account<'info, User>, +} + +#[account] +pub struct User { + data: u64, +} + +fn main() {} diff --git a/lints/duplicate_mutable_accounts/ui/recommended-2/src/lib.stderr b/lints/duplicate_mutable_accounts/ui/recommended-2/src/lib.stderr new file mode 100644 index 0000000..e69de29 diff --git a/lints/duplicate_mutable_accounts/ui/recommended/Cargo.toml b/lints/duplicate_mutable_accounts/ui/recommended/Cargo.toml new file mode 100644 index 0000000..45a53d1 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/recommended/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "duplicate-mutable-accounts-recommended" +version = "0.1.0" +description = "Created with Anchor" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "duplicate_mutable_accounts_recommended" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = "0.24.2" diff --git a/lints/duplicate_mutable_accounts/ui/recommended/Xargo.toml b/lints/duplicate_mutable_accounts/ui/recommended/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/recommended/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/lints/duplicate_mutable_accounts/ui/recommended/src/lib.rs b/lints/duplicate_mutable_accounts/ui/recommended/src/lib.rs new file mode 100644 index 0000000..059fef2 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/recommended/src/lib.rs @@ -0,0 +1,35 @@ +use anchor_lang::prelude::*; + +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + +#[program] +pub mod duplicate_mutable_accounts_recommended { + use super::*; + + pub fn update( + ctx: Context, + a: u64, + b: u64, + ) -> anchor_lang::solana_program::entrypoint::ProgramResult { + let user_a = &mut ctx.accounts.user_a; + let user_b = &mut ctx.accounts.user_b; + + user_a.data = a; + user_b.data = b; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Update<'info> { + #[account(constraint = user_a.key() != user_b.key())] + user_a: Account<'info, User>, + user_b: Account<'info, User>, +} + +#[account] +pub struct User { + data: u64, +} + +fn main() {} diff --git a/lints/duplicate_mutable_accounts/ui/recommended/src/lib.stderr b/lints/duplicate_mutable_accounts/ui/recommended/src/lib.stderr new file mode 100644 index 0000000..e69de29 diff --git a/lints/duplicate_mutable_accounts/ui/secure/Cargo.toml b/lints/duplicate_mutable_accounts/ui/secure/Cargo.toml new file mode 100644 index 0000000..66812b2 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/secure/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "duplicate-mutable-accounts-secure" +version = "0.1.0" +description = "Created with Anchor" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "duplicate_mutable_accounts_secure" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = "0.24.2" diff --git a/lints/duplicate_mutable_accounts/ui/secure/Xargo.toml b/lints/duplicate_mutable_accounts/ui/secure/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/secure/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/lints/duplicate_mutable_accounts/ui/secure/src/lib.rs b/lints/duplicate_mutable_accounts/ui/secure/src/lib.rs new file mode 100644 index 0000000..b637022 --- /dev/null +++ b/lints/duplicate_mutable_accounts/ui/secure/src/lib.rs @@ -0,0 +1,37 @@ +use anchor_lang::prelude::*; + +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + +#[program] +pub mod duplicate_mutable_accounts_secure { + use super::*; + + pub fn update( + ctx: Context, + a: u64, + b: u64, + ) -> anchor_lang::solana_program::entrypoint::ProgramResult { + if ctx.accounts.user_a.key() == ctx.accounts.user_b.key() { + return Err(ProgramError::InvalidArgument); + } + let user_a = &mut ctx.accounts.user_a; + let user_b = &mut ctx.accounts.user_b; + + user_a.data = a; + user_b.data = b; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Update<'info> { + user_a: Account<'info, User>, + user_b: Account<'info, User>, +} + +#[account] +pub struct User { + data: u64, +} + +fn main() {} diff --git a/lints/duplicate_mutable_accounts/ui/secure/src/lib.stderr b/lints/duplicate_mutable_accounts/ui/secure/src/lib.stderr new file mode 100644 index 0000000..e69de29