From 87494812a73da2182b5277c00bc03c59fb52dc87 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 15 Apr 2021 04:13:14 -0600 Subject: [PATCH] v1.5: faucet backports (#16565) * Faucet: repurpose cap and slice args to apply to single IPs (#16381) * Single use stmt * Log request IP * Switch cap and slice to apply per IP * Use SOL in logs, error msgs * Use thiserror instead of overloading io::Error * Return memo transaction for requests that exceed per-request-cap * Handle faucet memos in cli * Add some docs, esp about memo transaction * Use SOL symbol & standardize memo Co-authored-by: Michael Vines * Differentiate faucet tx-length errors * Populate signature in cli airdrop memo case Co-authored-by: Michael Vines * Add address_cache and exclude loopback from ip limit (#16487) Co-authored-by: Michael Vines --- Cargo.lock | 254 ++++++++++--------- cli/src/cli.rs | 29 ++- cli/tests/nonce.rs | 4 - cli/tests/stake.rs | 29 +-- cli/tests/transfer.rs | 25 +- cli/tests/vote.rs | 1 - client/Cargo.toml | 1 + client/src/client_error.rs | 13 + faucet/Cargo.toml | 2 + faucet/src/bin/faucet.rs | 28 ++- faucet/src/faucet.rs | 499 ++++++++++++++++++++++++------------- faucet/src/faucet_mock.rs | 15 +- programs/bpf/Cargo.lock | 293 ++++++++++++++-------- 13 files changed, 723 insertions(+), 470 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a9bcb619f..d892d7e752 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,7 +127,7 @@ checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -138,7 +138,7 @@ checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -363,7 +363,7 @@ dependencies = [ "borsh-schema-derive-internal", "proc-macro-crate", "proc-macro2 1.0.24", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -374,7 +374,7 @@ checksum = "d813fa25eb0bed78c36492cff4415f38c760d6de833d255ba9095bd8ebb7d725" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -385,7 +385,7 @@ checksum = "dcf78ee4a98c8cb9eba1bac3d3e2a1ea3d7673c719ce691e67b5cbafc472d3b7" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -932,7 +932,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -1103,7 +1103,7 @@ checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -1121,9 +1121,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" +checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" dependencies = [ "atty", "humantime 2.0.1", @@ -1150,7 +1150,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "synstructure", ] @@ -1332,7 +1332,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2003,7 +2003,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2472,7 +2472,7 @@ checksum = "6f09b9841adb6b5e1f89ef7087ea636e0fd94b2851f887c1e3eb5d5f8228fab3" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2523,7 +2523,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2611,7 +2611,7 @@ dependencies = [ "Inflector", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2727,7 +2727,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2815,7 +2815,7 @@ checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2826,7 +2826,7 @@ checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2956,7 +2956,7 @@ dependencies = [ "itertools 0.8.2", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -3463,7 +3463,7 @@ checksum = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -3535,9 +3535,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] @@ -3563,13 +3563,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -3626,7 +3626,7 @@ checksum = "d08338d8024b227c62bd68a12c7c9883f5c66780abaef15c550dc56f46ee6515" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -4112,6 +4112,7 @@ dependencies = [ "serde_json", "solana-account-decoder", "solana-clap-utils", + "solana-faucet", "solana-logger 1.5.19", "solana-net-utils", "solana-sdk", @@ -4239,7 +4240,7 @@ dependencies = [ "reqwest", "serde", "syn 0.15.44", - "syn 1.0.48", + "syn 1.0.67", "tokio 0.1.22", "winapi 0.3.8", ] @@ -4319,27 +4320,9 @@ dependencies = [ "solana-metrics", "solana-sdk", "solana-version", - "tokio 0.3.5", -] - -[[package]] -name = "solana-frozen-abi" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc44c8096d5847d8cf7f3af3cce565de554cb56371decf93b060633ca8588913" -dependencies = [ - "bs58", - "bv", - "generic-array 0.14.3", - "log 0.4.11", - "memmap2", - "rustc_version", - "serde", - "serde_derive", - "sha2 0.9.2", - "solana-frozen-abi-macro 1.5.8", - "solana-logger 1.5.8", + "spl-memo 3.0.0", "thiserror", + "tokio 0.3.5", ] [[package]] @@ -4361,16 +4344,23 @@ dependencies = [ ] [[package]] -name = "solana-frozen-abi-macro" -version = "1.5.8" +name = "solana-frozen-abi" +version = "1.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f905159beff1b53e4ba8b018a9d13d96ba164c3973bf3b9d587e730bcc14fc18" +checksum = "c59a0527921b3e66e9c8abda26f03e28c05e1ac462bfca6e7b84a4076fadc041" dependencies = [ - "lazy_static", - "proc-macro2 1.0.24", - "quote 1.0.6", + "bs58", + "bv", + "generic-array 0.14.3", + "log 0.4.11", + "memmap2", "rustc_version", - "syn 1.0.48", + "serde", + "serde_derive", + "sha2 0.9.2", + "solana-frozen-abi-macro 1.6.5", + "solana-logger 1.6.5", + "thiserror", ] [[package]] @@ -4381,7 +4371,20 @@ dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", "rustc_version", - "syn 1.0.48", + "syn 1.0.67", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71a32b3430d885d98dca4daa0c32de9d29e43163e2822f80975d75d04dfa89ea" +dependencies = [ + "lazy_static", + "proc-macro2 1.0.24", + "quote 1.0.6", + "rustc_version", + "syn 1.0.67", ] [[package]] @@ -4609,20 +4612,20 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83a006d97da5514a4475141573383d3fcd71c729ff78494f96bb531cf734d21" +version = "1.5.19" dependencies = [ - "env_logger 0.8.2", + "env_logger 0.8.3", "lazy_static", "log 0.4.11", ] [[package]] name = "solana-logger" -version = "1.5.19" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d75a277c10051df00277b2212c9e51dc8cd44229cf6b356a4adb0dc12533507" dependencies = [ - "env_logger 0.8.2", + "env_logger 0.8.3", "lazy_static", "log 0.4.11", ] @@ -4665,7 +4668,7 @@ dependencies = [ name = "solana-metrics" version = "1.5.19" dependencies = [ - "env_logger 0.8.2", + "env_logger 0.8.3", "gethostname", "lazy_static", "log 0.4.11", @@ -4776,36 +4779,6 @@ dependencies = [ "solana-version", ] -[[package]] -name = "solana-program" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2007bf285617f8a783e96b20ccd2f8d813549090a5b520f22e5f65b3cd9b157" -dependencies = [ - "bincode", - "bs58", - "bv", - "curve25519-dalek 2.1.0", - "hex", - "itertools 0.9.0", - "lazy_static", - "log 0.4.11", - "num-derive", - "num-traits", - "rand 0.7.3", - "rustc_version", - "rustversion", - "serde", - "serde_bytes", - "serde_derive", - "sha2 0.9.2", - "solana-frozen-abi 1.5.8", - "solana-frozen-abi-macro 1.5.8", - "solana-logger 1.5.8", - "solana-sdk-macro 1.5.8", - "thiserror", -] - [[package]] name = "solana-program" version = "1.5.19" @@ -4839,6 +4812,39 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-program" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e452a9421cc6c0a313c9542d1b92be4491402073e35a2bb2d0b72e84c03a3945" +dependencies = [ + "bincode", + "blake3", + "borsh", + "borsh-derive", + "bs58", + "bv", + "curve25519-dalek 2.1.0", + "hex", + "itertools 0.9.0", + "lazy_static", + "log 0.4.11", + "num-derive", + "num-traits", + "rand 0.7.3", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.9.2", + "solana-frozen-abi 1.6.5", + "solana-frozen-abi-macro 1.6.5", + "solana-logger 1.6.5", + "solana-sdk-macro 1.6.5", + "thiserror", +] + [[package]] name = "solana-program-test" version = "1.5.19" @@ -5014,19 +5020,6 @@ dependencies = [ "tiny-bip39", ] -[[package]] -name = "solana-sdk-macro" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a6635f1798c8ff1b88bb0fad1d4693c011f36a73c9ae03f198203144edcabb" -dependencies = [ - "bs58", - "proc-macro2 1.0.24", - "quote 1.0.6", - "rustversion", - "syn 1.0.48", -] - [[package]] name = "solana-sdk-macro" version = "1.5.19" @@ -5035,7 +5028,20 @@ dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", "rustversion", - "syn 1.0.48", + "syn 1.0.67", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5649e54928a244aad80ee3ab817b6ac37bf7b3b1559fd72989d5978e308b616a" +dependencies = [ + "bs58", + "proc-macro2 1.0.24", + "quote 1.0.6", + "rustversion", + "syn 1.0.67", ] [[package]] @@ -5413,7 +5419,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4adc47eebe5d2b662cbaaba1843719c28a67e5ec5d0460bc3ca60900a51f74e2" dependencies = [ - "solana-program 1.5.8", + "solana-program 1.6.5", "spl-token", ] @@ -5423,7 +5429,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb2b771f6146dec14ef5fbf498f9374652c54badc3befc8c40c1d426dd45d720" dependencies = [ - "solana-program 1.5.8", + "solana-program 1.6.5", ] [[package]] @@ -5432,7 +5438,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e76b60c6f58279b5469beb1705744e9778ee94d643c8e3e2ff91874c59bb3c63" dependencies = [ - "solana-program 1.5.8", + "solana-program 1.6.5", ] [[package]] @@ -5445,7 +5451,7 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-program 1.5.8", + "solana-program 1.6.5", "thiserror", ] @@ -5494,7 +5500,7 @@ dependencies = [ "quote 1.0.6", "serde", "serde_derive", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -5510,7 +5516,7 @@ dependencies = [ "serde_derive", "serde_json", "sha1", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -5565,9 +5571,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.48" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", @@ -5582,7 +5588,7 @@ checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "unicode-xid 0.2.0", ] @@ -5655,7 +5661,7 @@ checksum = "edbaf92ceea0a2ab555bea18a47a891e46ba2d6f930ec9506771662f4ab82bb7" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -5726,7 +5732,7 @@ checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -5789,7 +5795,7 @@ dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", "standback", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -5950,7 +5956,7 @@ checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -5961,7 +5967,7 @@ checksum = "21d30fdbb5dc2d8f91049691aa1a9d4d4ae422a21c334ce8936e5886d30c5c45" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -6382,7 +6388,7 @@ checksum = "f0693bf8d6f2bf22c690fc61a9d21ac69efdbb894a17ed596b9af0f01e64b84b" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -6691,7 +6697,7 @@ dependencies = [ "log 0.4.11", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "wasm-bindgen-shared", ] @@ -6725,7 +6731,7 @@ checksum = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6912,7 +6918,7 @@ checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "synstructure", ] diff --git a/cli/src/cli.rs b/cli/src/cli.rs index d591a2adb6..6b2bb38e80 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -34,6 +34,7 @@ use solana_client::{ }; #[cfg(not(test))] use solana_faucet::faucet::request_airdrop_transaction; +use solana_faucet::faucet::FaucetError; #[cfg(test)] use solana_faucet::faucet_mock::request_airdrop_transaction; use solana_remote_wallet::remote_wallet::RemoteWalletManager; @@ -998,11 +999,25 @@ fn process_airdrop( faucet_addr ); - request_and_confirm_airdrop(&rpc_client, faucet_addr, &pubkey, lamports, &config)?; + let pre_balance = rpc_client.get_balance(&pubkey)?; - let current_balance = rpc_client.get_balance(&pubkey)?; + let result = request_and_confirm_airdrop(&rpc_client, faucet_addr, &pubkey, lamports); + if let Ok(signature) = result { + let signature_cli_message = log_instruction_custom_error::(result, &config)?; + println!("{}", signature_cli_message); - Ok(build_balance_message(current_balance, false, true)) + let current_balance = rpc_client.get_balance(&pubkey)?; + + if current_balance < pre_balance.saturating_add(lamports) { + println!("Balance unchanged"); + println!("Run `solana confirm -v {:?}` for more info", signature); + Ok("".to_string()) + } else { + Ok(build_balance_message(current_balance, false, true)) + } + } else { + log_instruction_custom_error::(result, &config) + } } fn process_balance( @@ -1875,7 +1890,7 @@ impl FaucetKeypair { to_pubkey: &Pubkey, lamports: u64, blockhash: Hash, - ) -> Result> { + ) -> Result { let transaction = request_airdrop_transaction(faucet_addr, to_pubkey, lamports, blockhash)?; Ok(Self { transaction }) } @@ -1909,8 +1924,7 @@ pub fn request_and_confirm_airdrop( faucet_addr: &SocketAddr, to_pubkey: &Pubkey, lamports: u64, - config: &CliConfig, -) -> ProcessResult { +) -> ClientResult { let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let keypair = { let mut retries = 5; @@ -1924,8 +1938,7 @@ pub fn request_and_confirm_airdrop( } }?; let tx = keypair.airdrop_transaction(); - let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); - log_instruction_custom_error::(result, &config) + rpc_client.send_and_confirm_transaction_with_spinner(&tx) } pub fn log_instruction_custom_error( diff --git a/cli/tests/nonce.rs b/cli/tests/nonce.rs index 6e51de4059..6c8acc3557 100644 --- a/cli/tests/nonce.rs +++ b/cli/tests/nonce.rs @@ -74,7 +74,6 @@ fn full_battery_tests( &faucet_addr, &config_payer.signers[0].pubkey(), 2000, - &config_payer, ) .unwrap(); check_recent_balance(2000, &rpc_client, &config_payer.signers[0].pubkey()); @@ -221,7 +220,6 @@ fn test_create_account_with_seed() { let offline_nonce_authority_signer = keypair_from_seed(&[1u8; 32]).unwrap(); let online_nonce_creator_signer = keypair_from_seed(&[2u8; 32]).unwrap(); let to_address = Pubkey::new(&[3u8; 32]); - let config = CliConfig::recent_for_tests(); // Setup accounts let rpc_client = @@ -231,7 +229,6 @@ fn test_create_account_with_seed() { &faucet_addr, &offline_nonce_authority_signer.pubkey(), 42, - &config, ) .unwrap(); request_and_confirm_airdrop( @@ -239,7 +236,6 @@ fn test_create_account_with_seed() { &faucet_addr, &online_nonce_creator_signer.pubkey(), 4242, - &config, ) .unwrap(); check_recent_balance(42, &rpc_client, &offline_nonce_authority_signer.pubkey()); diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index 8cd64af535..2b58596333 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -42,7 +42,6 @@ fn test_stake_delegation_force() { &faucet_addr, &config.signers[0].pubkey(), 100_000, - &config, ) .unwrap(); @@ -132,7 +131,6 @@ fn test_seed_stake_delegation_and_deactivation() { &faucet_addr, &config_validator.signers[0].pubkey(), 100_000, - &config_validator, ) .unwrap(); check_recent_balance(100_000, &rpc_client, &config_validator.signers[0].pubkey()); @@ -215,7 +213,6 @@ fn test_stake_delegation_and_deactivation() { &faucet_addr, &config_validator.signers[0].pubkey(), 100_000, - &config_validator, ) .unwrap(); check_recent_balance(100_000, &rpc_client, &config_validator.signers[0].pubkey()); @@ -303,7 +300,6 @@ fn test_offline_stake_delegation_and_deactivation() { &faucet_addr, &config_validator.signers[0].pubkey(), 100_000, - &config_offline, ) .unwrap(); check_recent_balance(100_000, &rpc_client, &config_validator.signers[0].pubkey()); @@ -313,7 +309,6 @@ fn test_offline_stake_delegation_and_deactivation() { &faucet_addr, &config_offline.signers[0].pubkey(), 100_000, - &config_validator, ) .unwrap(); check_recent_balance(100_000, &rpc_client, &config_offline.signers[0].pubkey()); @@ -430,7 +425,6 @@ fn test_nonced_stake_delegation_and_deactivation() { &faucet_addr, &config.signers[0].pubkey(), 100_000, - &config, ) .unwrap(); @@ -542,7 +536,6 @@ fn test_stake_authorize() { &faucet_addr, &config.signers[0].pubkey(), 100_000, - &config, ) .unwrap(); @@ -560,7 +553,6 @@ fn test_stake_authorize() { &faucet_addr, &config_offline.signers[0].pubkey(), 100_000, - &config, ) .unwrap(); @@ -816,16 +808,13 @@ fn test_stake_authorize_with_fee_payer() { config_offline.command = CliCommand::ClusterVersion; process_command(&config_offline).unwrap_err(); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &default_pubkey, 100_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &default_pubkey, 100_000).unwrap(); check_recent_balance(100_000, &rpc_client, &config.signers[0].pubkey()); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &payer_pubkey, 100_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &payer_pubkey, 100_000).unwrap(); check_recent_balance(100_000, &rpc_client, &payer_pubkey); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000).unwrap(); check_recent_balance(100_000, &rpc_client, &offline_pubkey); check_ready(&rpc_client); @@ -941,13 +930,11 @@ fn test_stake_split() { &faucet_addr, &config.signers[0].pubkey(), 500_000, - &config, ) .unwrap(); check_recent_balance(500_000, &rpc_client, &config.signers[0].pubkey()); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000).unwrap(); check_recent_balance(100_000, &rpc_client, &offline_pubkey); // Create stake account, identity is authority @@ -1086,13 +1073,11 @@ fn test_stake_set_lockup() { &faucet_addr, &config.signers[0].pubkey(), 500_000, - &config, ) .unwrap(); check_recent_balance(500_000, &rpc_client, &config.signers[0].pubkey()); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000).unwrap(); check_recent_balance(100_000, &rpc_client, &offline_pubkey); // Create stake account, identity is authority @@ -1342,13 +1327,11 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { &faucet_addr, &config.signers[0].pubkey(), 200_000, - &config, ) .unwrap(); check_recent_balance(200_000, &rpc_client, &config.signers[0].pubkey()); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 100_000).unwrap(); check_recent_balance(100_000, &rpc_client, &offline_pubkey); // Create nonce account diff --git a/cli/tests/transfer.rs b/cli/tests/transfer.rs index 6184bf83ae..c8341c0e90 100644 --- a/cli/tests/transfer.rs +++ b/cli/tests/transfer.rs @@ -38,8 +38,7 @@ fn test_transfer() { let sender_pubkey = config.signers[0].pubkey(); let recipient_pubkey = Pubkey::new(&[1u8; 32]); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000).unwrap(); check_recent_balance(50_000, &rpc_client, &sender_pubkey); check_recent_balance(0, &rpc_client, &recipient_pubkey); @@ -91,7 +90,7 @@ fn test_transfer() { process_command(&offline).unwrap_err(); let offline_pubkey = offline.signers[0].pubkey(); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 50, &config).unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 50).unwrap(); check_recent_balance(50, &rpc_client, &offline_pubkey); // Offline transfer @@ -265,25 +264,17 @@ fn test_transfer_multisession_signing() { let offline_from_signer = keypair_from_seed(&[2u8; 32]).unwrap(); let offline_fee_payer_signer = keypair_from_seed(&[3u8; 32]).unwrap(); let from_null_signer = NullSigner::new(&offline_from_signer.pubkey()); - let config = CliConfig::recent_for_tests(); // Setup accounts let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); - request_and_confirm_airdrop( - &rpc_client, - &faucet_addr, - &offline_from_signer.pubkey(), - 43, - &config, - ) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_from_signer.pubkey(), 43) + .unwrap(); request_and_confirm_airdrop( &rpc_client, &faucet_addr, &offline_fee_payer_signer.pubkey(), 3, - &config, ) .unwrap(); check_recent_balance(43, &rpc_client, &offline_from_signer.pubkey()); @@ -396,8 +387,7 @@ fn test_transfer_all() { let sender_pubkey = config.signers[0].pubkey(); let recipient_pubkey = Pubkey::new(&[1u8; 32]); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000).unwrap(); check_recent_balance(50_000, &rpc_client, &sender_pubkey); check_recent_balance(0, &rpc_client, &recipient_pubkey); @@ -450,9 +440,8 @@ fn test_transfer_with_seed() { ) .unwrap(); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 1, &config).unwrap(); - request_and_confirm_airdrop(&rpc_client, &faucet_addr, &derived_address, 50_000, &config) - .unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 1).unwrap(); + request_and_confirm_airdrop(&rpc_client, &faucet_addr, &derived_address, 50_000).unwrap(); check_recent_balance(1, &rpc_client, &sender_pubkey); check_recent_balance(50_000, &rpc_client, &derived_address); check_recent_balance(0, &rpc_client, &recipient_pubkey); diff --git a/cli/tests/vote.rs b/cli/tests/vote.rs index 8c1d82e18b..f6f6fa4643 100644 --- a/cli/tests/vote.rs +++ b/cli/tests/vote.rs @@ -35,7 +35,6 @@ fn test_vote_authorize_and_withdraw() { &faucet_addr, &config.signers[0].pubkey(), 100_000, - &config, ) .unwrap(); diff --git a/client/Cargo.toml b/client/Cargo.toml index 68f1e4fc67..2ef2f64e46 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -26,6 +26,7 @@ serde_derive = "1.0.103" serde_json = "1.0.56" solana-account-decoder = { path = "../account-decoder", version = "=1.5.19" } solana-clap-utils = { path = "../clap-utils", version = "=1.5.19" } +solana-faucet = { path = "../faucet", version = "=1.5.19" } solana-net-utils = { path = "../net-utils", version = "=1.5.19" } solana-sdk = { path = "../sdk", version = "=1.5.19" } solana-transaction-status = { path = "../transaction-status", version = "=1.5.19" } diff --git a/client/src/client_error.rs b/client/src/client_error.rs index 96f6660262..9c2a0f2988 100644 --- a/client/src/client_error.rs +++ b/client/src/client_error.rs @@ -1,4 +1,5 @@ use crate::rpc_request; +use solana_faucet::faucet::FaucetError; use solana_sdk::{ signature::SignerError, transaction::TransactionError, transport::TransportError, }; @@ -21,6 +22,8 @@ pub enum ClientErrorKind { SigningError(#[from] SignerError), #[error(transparent)] TransactionError(#[from] TransactionError), + #[error(transparent)] + FaucetError(#[from] FaucetError), #[error("Custom: {0}")] Custom(String), } @@ -44,6 +47,7 @@ impl From for TransportError { ClientErrorKind::RpcError(err) => Self::Custom(format!("{:?}", err)), ClientErrorKind::SerdeJson(err) => Self::Custom(format!("{:?}", err)), ClientErrorKind::SigningError(err) => Self::Custom(format!("{:?}", err)), + ClientErrorKind::FaucetError(err) => Self::Custom(format!("{:?}", err)), ClientErrorKind::Custom(err) => Self::Custom(format!("{:?}", err)), } } @@ -160,4 +164,13 @@ impl From for ClientError { } } +impl From for ClientError { + fn from(err: FaucetError) -> Self { + Self { + request: None, + kind: err.into(), + } + } +} + pub type Result = std::result::Result; diff --git a/faucet/Cargo.toml b/faucet/Cargo.toml index f8f039e027..039d07b6e9 100644 --- a/faucet/Cargo.toml +++ b/faucet/Cargo.toml @@ -22,6 +22,8 @@ solana-logger = { path = "../logger", version = "=1.5.19" } solana-metrics = { path = "../metrics", version = "=1.5.19" } solana-sdk = { path = "../sdk", version = "=1.5.19" } solana-version = { path = "../version", version = "=1.5.19" } +spl-memo = { version = "=3.0.0", features = ["no-entrypoint"] } +thiserror = "1.0" tokio = { version = "0.3.5", features = ["full"] } [lib] diff --git a/faucet/src/bin/faucet.rs b/faucet/src/bin/faucet.rs index 0d4b9b76dc..322a2d33ff 100644 --- a/faucet/src/bin/faucet.rs +++ b/faucet/src/bin/faucet.rs @@ -1,14 +1,17 @@ -use clap::{crate_description, crate_name, App, Arg}; -use solana_clap_utils::input_parsers::{lamports_of_sol, value_of}; -use solana_faucet::{ - faucet::{run_faucet, Faucet, FAUCET_PORT}, - socketaddr, -}; -use solana_sdk::signature::read_keypair_file; -use std::{ - net::{Ipv4Addr, SocketAddr}, - sync::{Arc, Mutex}, - thread, +use { + clap::{crate_description, crate_name, App, Arg}, + log::*, + solana_clap_utils::input_parsers::{lamports_of_sol, value_of}, + solana_faucet::{ + faucet::{run_faucet, Faucet, FAUCET_PORT}, + socketaddr, + }, + solana_sdk::signature::read_keypair_file, + std::{ + net::{Ipv4Addr, SocketAddr}, + sync::{Arc, Mutex}, + thread, + }, }; #[tokio::main] @@ -74,7 +77,8 @@ async fn main() { thread::spawn(move || loop { let time = faucet1.lock().unwrap().time_slice; thread::sleep(time); - faucet1.lock().unwrap().clear_request_count(); + debug!("clearing ip cache"); + faucet1.lock().unwrap().clear_caches(); }); run_faucet(faucet, faucet_addr, None).await; diff --git a/faucet/src/faucet.rs b/faucet/src/faucet.rs index ea3ebc28ee..ed0be44cf8 100644 --- a/faucet/src/faucet.rs +++ b/faucet/src/faucet.rs @@ -1,34 +1,40 @@ //! The `faucet` module provides an object for launching a Solana Faucet, //! which is the custodian of any remaining lamports in a mint. -//! The Solana Faucet builds and send airdrop transactions, -//! checking requests against a request cap for a given time time_slice -//! and (to come) an IP rate limit. +//! The Solana Faucet builds and sends airdrop transactions, +//! checking requests against a single-request cap and a per-IP limit +//! for a given time time_slice. -use bincode::{deserialize, serialize, serialized_size}; -use byteorder::{ByteOrder, LittleEndian}; -use log::*; -use serde_derive::{Deserialize, Serialize}; -use solana_metrics::datapoint_info; -use solana_sdk::{ - hash::Hash, - message::Message, - packet::PACKET_DATA_SIZE, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, -}; -use std::{ - io::{self, Error, ErrorKind, Read, Write}, - net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}, - sync::{mpsc::Sender, Arc, Mutex}, - thread, - time::Duration, -}; -use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::{TcpListener, TcpStream as TokioTcpStream}, - runtime::Runtime, +use { + bincode::{deserialize, serialize, serialized_size}, + byteorder::{ByteOrder, LittleEndian}, + log::*, + serde_derive::{Deserialize, Serialize}, + solana_metrics::datapoint_info, + solana_sdk::{ + hash::Hash, + instruction::Instruction, + message::Message, + native_token::lamports_to_sol, + packet::PACKET_DATA_SIZE, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + std::{ + collections::HashMap, + io::{Read, Write}, + net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}, + sync::{mpsc::Sender, Arc, Mutex}, + thread, + time::Duration, + }, + thiserror::Error, + tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::{TcpListener, TcpStream as TokioTcpStream}, + runtime::Runtime, + }, }; #[macro_export] @@ -42,11 +48,33 @@ macro_rules! socketaddr { }}; } +const ERROR_RESPONSE: [u8; 2] = 0u16.to_le_bytes(); + pub const TIME_SLICE: u64 = 60; -pub const REQUEST_CAP: u64 = solana_sdk::native_token::LAMPORTS_PER_SOL * 10_000_000; pub const FAUCET_PORT: u16 = 9900; pub const FAUCET_PORT_STR: &str = "9900"; +#[derive(Error, Debug)] +pub enum FaucetError { + #[error("IO Error: {0}")] + IoError(#[from] std::io::Error), + + #[error("serialization error: {0}")] + Serialize(#[from] bincode::Error), + + #[error("transaction_length from faucet exceeds limit: {0}")] + TransactionDataTooLarge(usize), + + #[error("transaction_length from faucet: 0")] + NoDataReceived, + + #[error("request too large; req: ◎{0}, cap: ◎{1}")] + PerRequestCapExceeded(f64, f64), + + #[error("limit reached; req: ◎{0}, to: {1}, current: ◎{2}, cap: ◎{3}")] + PerTimeCapExceeded(f64, String, f64, f64), +} + #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub enum FaucetRequest { GetAirdrop { @@ -66,13 +94,18 @@ impl Default for FaucetRequest { } } +pub enum FaucetTransaction { + Airdrop(Transaction), + Memo((Transaction, String)), +} + pub struct Faucet { faucet_keypair: Keypair, - ip_cache: Vec, + ip_cache: HashMap, + address_cache: HashMap, pub time_slice: Duration, - per_time_cap: u64, + per_time_cap: Option, per_request_cap: Option, - pub request_current: u64, } impl Faucet { @@ -83,40 +116,60 @@ impl Faucet { per_request_cap: Option, ) -> Faucet { let time_slice = Duration::new(time_input.unwrap_or(TIME_SLICE), 0); - let per_time_cap = per_time_cap.unwrap_or(REQUEST_CAP); + if let Some((per_request_cap, per_time_cap)) = per_request_cap.zip(per_time_cap) { + if per_time_cap < per_request_cap { + warn!( + "per_time_cap {} SOL < per_request_cap {} SOL; \ + maximum single requests will fail", + lamports_to_sol(per_time_cap), + lamports_to_sol(per_request_cap), + ); + } + } Faucet { faucet_keypair, - ip_cache: Vec::new(), + ip_cache: HashMap::new(), + address_cache: HashMap::new(), time_slice, per_time_cap, per_request_cap, - request_current: 0, } } - pub fn check_time_request_limit(&mut self, request_amount: u64) -> bool { - self.request_current - .checked_add(request_amount) - .map(|s| s <= self.per_time_cap) - .unwrap_or(false) + pub fn check_time_request_limit( + &mut self, + request_amount: u64, + to: T, + ) -> Result<(), FaucetError> { + let new_total = to.check_cache(self, request_amount); + to.datapoint_info(request_amount, new_total); + if let Some(cap) = self.per_time_cap { + if new_total > cap { + return Err(FaucetError::PerTimeCapExceeded( + lamports_to_sol(request_amount), + to.to_string(), + lamports_to_sol(new_total), + lamports_to_sol(cap), + )); + } + } + Ok(()) } - pub fn clear_request_count(&mut self) { - self.request_current = 0; - } - - pub fn add_ip_to_cache(&mut self, ip: IpAddr) { - self.ip_cache.push(ip); - } - - pub fn clear_ip_cache(&mut self) { + pub fn clear_caches(&mut self) { self.ip_cache.clear(); + self.address_cache.clear(); } + /// Checks per-request and per-time-ip limits; if both pass, this method returns a signed + /// SystemProgram::Transfer transaction from the faucet keypair to the requested recipient. If + /// the request exceeds this per-request limit, this method returns a signed SPL Memo + /// transaction with the memo: "request too large; req: SOL cap: SOL" pub fn build_airdrop_transaction( &mut self, req: FaucetRequest, - ) -> Result { + ip: IpAddr, + ) -> Result { trace!("build_airdrop_transaction: {:?}", req); match req { FaucetRequest::GetAirdrop { @@ -124,72 +177,83 @@ impl Faucet { to, blockhash, } => { + let mint_pubkey = self.faucet_keypair.pubkey(); + info!( + "Requesting airdrop of {} SOL to {:?}", + lamports_to_sol(lamports), + to + ); + if let Some(cap) = self.per_request_cap { if lamports > cap { - return Err(Error::new( - ErrorKind::Other, - format!("request too large; req: {} cap: {}", lamports, cap), - )); + let memo = format!( + "{}", + FaucetError::PerRequestCapExceeded( + lamports_to_sol(lamports), + lamports_to_sol(cap), + ) + ); + let memo_instruction = Instruction { + program_id: Pubkey::new(&spl_memo::id().to_bytes()), + accounts: vec![], + data: memo.as_bytes().to_vec(), + }; + let message = Message::new(&[memo_instruction], Some(&mint_pubkey)); + return Ok(FaucetTransaction::Memo(( + Transaction::new(&[&self.faucet_keypair], message, blockhash), + memo, + ))); } } - if self.check_time_request_limit(lamports) { - self.request_current = self.request_current.saturating_add(lamports); - datapoint_info!( - "faucet-airdrop", - ("request_amount", lamports, i64), - ("request_current", self.request_current, i64) - ); - info!("Requesting airdrop of {} to {:?}", lamports, to); - - let mint_pubkey = self.faucet_keypair.pubkey(); - let create_instruction = - system_instruction::transfer(&mint_pubkey, &to, lamports); - let message = Message::new(&[create_instruction], Some(&mint_pubkey)); - Ok(Transaction::new( - &[&self.faucet_keypair], - message, - blockhash, - )) - } else { - Err(Error::new( - ErrorKind::Other, - format!( - "token limit reached; req: {} current: {} cap: {}", - lamports, self.request_current, self.per_time_cap - ), - )) + if !ip.is_loopback() { + self.check_time_request_limit(lamports, ip)?; } + self.check_time_request_limit(lamports, to)?; + + let transfer_instruction = + system_instruction::transfer(&mint_pubkey, &to, lamports); + let message = Message::new(&[transfer_instruction], Some(&mint_pubkey)); + Ok(FaucetTransaction::Airdrop(Transaction::new( + &[&self.faucet_keypair], + message, + blockhash, + ))) } } } - pub fn process_faucet_request(&mut self, bytes: &[u8]) -> Result, io::Error> { - let req: FaucetRequest = deserialize(bytes).map_err(|err| { - io::Error::new( - io::ErrorKind::Other, - format!("deserialize packet in faucet: {:?}", err), - ) - })?; + + /// Deserializes a received airdrop request, and returns a serialized transaction + pub fn process_faucet_request( + &mut self, + bytes: &[u8], + ip: IpAddr, + ) -> Result, FaucetError> { + let req: FaucetRequest = deserialize(bytes)?; info!("Airdrop transaction requested...{:?}", req); - let res = self.build_airdrop_transaction(req); + let res = self.build_airdrop_transaction(req, ip); match res { Ok(tx) => { - let response_vec = bincode::serialize(&tx).map_err(|err| { - io::Error::new( - io::ErrorKind::Other, - format!("deserialize packet in faucet: {:?}", err), - ) - })?; + let tx = match tx { + FaucetTransaction::Airdrop(tx) => { + info!("Airdrop transaction granted"); + tx + } + FaucetTransaction::Memo((tx, memo)) => { + warn!("Memo transaction returned: {}", memo); + tx + } + }; + let response_vec = bincode::serialize(&tx)?; let mut response_vec_with_length = vec![0; 2]; LittleEndian::write_u16(&mut response_vec_with_length, response_vec.len() as u16); response_vec_with_length.extend_from_slice(&response_vec); - info!("Airdrop transaction granted"); Ok(response_vec_with_length) } Err(err) => { - warn!("Airdrop transaction failed: {:?}", err); + warn!("Airdrop transaction failed: {}", err); Err(err) } } @@ -207,7 +271,7 @@ pub fn request_airdrop_transaction( id: &Pubkey, lamports: u64, blockhash: Hash, -) -> Result { +) -> Result { info!( "request_airdrop_transaction: faucet_addr={} id={} lamports={} blockhash={}", faucet_addr, id, lamports, blockhash @@ -230,17 +294,13 @@ pub fn request_airdrop_transaction( "request_airdrop_transaction: buffer length read_exact error: {:?}", err ); - Error::new(ErrorKind::Other, "Airdrop failed") + err })?; let transaction_length = LittleEndian::read_u16(&buffer) as usize; - if transaction_length > PACKET_DATA_SIZE || transaction_length == 0 { - return Err(Error::new( - ErrorKind::Other, - format!( - "request_airdrop_transaction: invalid transaction_length from faucet: {}", - transaction_length - ), - )); + if transaction_length > PACKET_DATA_SIZE { + return Err(FaucetError::TransactionDataTooLarge(transaction_length)); + } else if transaction_length == 0 { + return Err(FaucetError::NoDataReceived); } // Read the transaction @@ -251,15 +311,10 @@ pub fn request_airdrop_transaction( "request_airdrop_transaction: buffer read_exact error: {:?}", err ); - Error::new(ErrorKind::Other, "Airdrop failed") + err })?; - let transaction: Transaction = deserialize(&buffer).map_err(|err| { - Error::new( - ErrorKind::Other, - format!("request_airdrop_transaction deserialize failure: {:?}", err), - ) - })?; + let transaction: Transaction = deserialize(&buffer)?; Ok(transaction) } @@ -347,14 +402,27 @@ async fn process( while stream.read_exact(&mut request).await.is_ok() { trace!("{:?}", request); - let response = match faucet.lock().unwrap().process_faucet_request(&request) { - Ok(response_bytes) => { - trace!("Airdrop response_bytes: {:?}", response_bytes); - response_bytes - } - Err(e) => { - info!("Error in request: {:?}", e); - 0u16.to_le_bytes().to_vec() + let response = { + match stream.peer_addr() { + Err(e) => { + info!("{:?}", e.into_inner()); + ERROR_RESPONSE.to_vec() + } + Ok(peer_addr) => { + let ip = peer_addr.ip(); + info!("Request IP: {:?}", ip); + + match faucet.lock().unwrap().process_faucet_request(&request, ip) { + Ok(response_bytes) => { + trace!("Airdrop response_bytes: {:?}", response_bytes); + response_bytes + } + Err(e) => { + info!("Error in request: {}", e); + ERROR_RESPONSE.to_vec() + } + } + } } }; stream.write_all(&response).await?; @@ -363,6 +431,49 @@ async fn process( Ok(()) } +pub trait LimitByTime { + fn check_cache(&self, faucet: &mut Faucet, request_amount: u64) -> u64; + fn datapoint_info(&self, request_amount: u64, new_total: u64); +} + +impl LimitByTime for IpAddr { + fn check_cache(&self, faucet: &mut Faucet, request_amount: u64) -> u64 { + *faucet + .ip_cache + .entry(*self) + .and_modify(|total| *total = total.saturating_add(request_amount)) + .or_insert(request_amount) + } + + fn datapoint_info(&self, request_amount: u64, new_total: u64) { + datapoint_info!( + "faucet-airdrop", + ("request_amount", request_amount, i64), + ("ip", self.to_string(), String), + ("new_total", new_total, i64) + ); + } +} + +impl LimitByTime for Pubkey { + fn check_cache(&self, faucet: &mut Faucet, request_amount: u64) -> u64 { + *faucet + .address_cache + .entry(*self) + .and_modify(|total| *total = total.saturating_add(request_amount)) + .or_insert(request_amount) + } + + fn datapoint_info(&self, request_amount: u64, new_total: u64) { + datapoint_info!( + "faucet-airdrop", + ("request_amount", request_amount, i64), + ("address", self.to_string(), String), + ("new_total", new_total, i64) + ); + } +} + #[cfg(test)] mod tests { use super::*; @@ -372,98 +483,135 @@ mod tests { #[test] fn test_check_time_request_limit() { let keypair = Keypair::new(); - let mut faucet = Faucet::new(keypair, None, Some(3), None); - assert!(faucet.check_time_request_limit(1)); - faucet.request_current = 3; - assert!(!faucet.check_time_request_limit(1)); - faucet.request_current = 1; - assert!(!faucet.check_time_request_limit(u64::MAX)); + let mut faucet = Faucet::new(keypair, None, Some(2), None); + let ip = socketaddr!([203, 0, 113, 1], 1234).ip(); + assert!(faucet.check_time_request_limit(1, ip).is_ok()); + assert!(faucet.check_time_request_limit(1, ip).is_ok()); + assert!(faucet.check_time_request_limit(1, ip).is_err()); + + let address = Pubkey::new_unique(); + assert!(faucet.check_time_request_limit(1, address).is_ok()); + assert!(faucet.check_time_request_limit(1, address).is_ok()); + assert!(faucet.check_time_request_limit(1, address).is_err()); } #[test] - fn test_clear_request_count() { + fn test_clear_caches() { let keypair = Keypair::new(); let mut faucet = Faucet::new(keypair, None, None, None); - faucet.request_current += 256; - assert_eq!(faucet.request_current, 256); - faucet.clear_request_count(); - assert_eq!(faucet.request_current, 0); - } - - #[test] - fn test_add_ip_to_cache() { - let keypair = Keypair::new(); - let mut faucet = Faucet::new(keypair, None, None, None); - let ip = "127.0.0.1".parse().expect("create IpAddr from string"); + let ip = socketaddr!([127, 0, 0, 1], 0).ip(); assert_eq!(faucet.ip_cache.len(), 0); - faucet.add_ip_to_cache(ip); + faucet.check_time_request_limit(1, ip).unwrap(); assert_eq!(faucet.ip_cache.len(), 1); - assert!(faucet.ip_cache.contains(&ip)); - } - - #[test] - fn test_clear_ip_cache() { - let keypair = Keypair::new(); - let mut faucet = Faucet::new(keypair, None, None, None); - let ip = "127.0.0.1".parse().expect("create IpAddr from string"); - assert_eq!(faucet.ip_cache.len(), 0); - faucet.add_ip_to_cache(ip); - assert_eq!(faucet.ip_cache.len(), 1); - faucet.clear_ip_cache(); + faucet.clear_caches(); assert_eq!(faucet.ip_cache.len(), 0); assert!(faucet.ip_cache.is_empty()); + + let address = Pubkey::new_unique(); + assert_eq!(faucet.address_cache.len(), 0); + faucet.check_time_request_limit(1, address).unwrap(); + assert_eq!(faucet.address_cache.len(), 1); + faucet.clear_caches(); + assert_eq!(faucet.address_cache.len(), 0); + assert!(faucet.address_cache.is_empty()); } #[test] fn test_faucet_default_init() { let keypair = Keypair::new(); let time_slice: Option = None; - let request_cap: Option = None; - let faucet = Faucet::new(keypair, time_slice, request_cap, Some(100)); + let per_time_cap: Option = Some(200); + let per_request_cap: Option = Some(100); + let faucet = Faucet::new(keypair, time_slice, per_time_cap, per_request_cap); assert_eq!(faucet.time_slice, Duration::new(TIME_SLICE, 0)); - assert_eq!(faucet.per_time_cap, REQUEST_CAP); - assert_eq!(faucet.per_request_cap, Some(100)); + assert_eq!(faucet.per_time_cap, per_time_cap); + assert_eq!(faucet.per_request_cap, per_request_cap); } #[test] fn test_faucet_build_airdrop_transaction() { - let to = solana_sdk::pubkey::new_rand(); + let to = Pubkey::new_unique(); let blockhash = Hash::default(); let request = FaucetRequest::GetAirdrop { lamports: 2, to, blockhash, }; + let ip = socketaddr!([203, 0, 113, 1], 1234).ip(); let mint = Keypair::new(); let mint_pubkey = mint.pubkey(); let mut faucet = Faucet::new(mint, None, None, None); - let tx = faucet.build_airdrop_transaction(request).unwrap(); - let message = tx.message(); + if let FaucetTransaction::Airdrop(tx) = + faucet.build_airdrop_transaction(request, ip).unwrap() + { + let message = tx.message(); - assert_eq!(tx.signatures.len(), 1); - assert_eq!( - message.account_keys, - vec![mint_pubkey, to, Pubkey::default()] - ); - assert_eq!(message.recent_blockhash, blockhash); + assert_eq!(tx.signatures.len(), 1); + assert_eq!( + message.account_keys, + vec![mint_pubkey, to, Pubkey::default()] + ); + assert_eq!(message.recent_blockhash, blockhash); - assert_eq!(message.instructions.len(), 1); - let instruction: SystemInstruction = deserialize(&message.instructions[0].data).unwrap(); - assert_eq!(instruction, SystemInstruction::Transfer { lamports: 2 }); + assert_eq!(message.instructions.len(), 1); + let instruction: SystemInstruction = + deserialize(&message.instructions[0].data).unwrap(); + assert_eq!(instruction, SystemInstruction::Transfer { lamports: 2 }); + } else { + panic!("airdrop should succeed"); + } // Test per-time request cap let mint = Keypair::new(); - faucet = Faucet::new(mint, None, Some(1), None); - let tx = faucet.build_airdrop_transaction(request); + faucet = Faucet::new(mint, None, Some(2), None); + let _tx = faucet.build_airdrop_transaction(request, ip).unwrap(); // first request succeeds + let tx = faucet.build_airdrop_transaction(request, ip); assert!(tx.is_err()); + // Test multiple requests from loopback with different addresses succeed + let mint = Keypair::new(); + faucet = Faucet::new(mint, None, Some(2), None); + let ip = socketaddr!([127, 0, 0, 1], 0).ip(); + let other = Pubkey::new_unique(); + let _tx0 = faucet.build_airdrop_transaction(request, ip).unwrap(); // first request succeeds + let request1 = FaucetRequest::GetAirdrop { + lamports: 2, + to: other, + blockhash, + }; + let _tx1 = faucet.build_airdrop_transaction(request1, ip).unwrap(); // first request succeeds + let tx0 = faucet.build_airdrop_transaction(request, ip); + assert!(tx0.is_err()); + let tx1 = faucet.build_airdrop_transaction(request1, ip); + assert!(tx1.is_err()); + // Test per-request cap let mint = Keypair::new(); - faucet = Faucet::new(mint, None, None, Some(1)); - let tx = faucet.build_airdrop_transaction(request); - assert!(tx.is_err()); + let mint_pubkey = mint.pubkey(); + let mut faucet = Faucet::new(mint, None, None, Some(1)); + + if let FaucetTransaction::Memo((tx, memo)) = + faucet.build_airdrop_transaction(request, ip).unwrap() + { + let message = tx.message(); + + assert_eq!(tx.signatures.len(), 1); + assert_eq!( + message.account_keys, + vec![mint_pubkey, Pubkey::new(&spl_memo::id().to_bytes())] + ); + assert_eq!(message.recent_blockhash, blockhash); + + assert_eq!(message.instructions.len(), 1); + let parsed_memo = std::str::from_utf8(&message.instructions[0].data).unwrap(); + let expected_memo = "request too large; req: ◎0.000000002, cap: ◎0.000000001"; + assert_eq!(parsed_memo, expected_memo); + assert_eq!(memo, expected_memo); + } else { + panic!("airdrop attempt should result in memo tx"); + } } #[test] @@ -476,6 +624,7 @@ mod tests { blockhash, to, }; + let ip = socketaddr!([203, 0, 113, 1], 1234).ip(); let req = serialize(&req).unwrap(); let keypair = Keypair::new(); @@ -488,11 +637,11 @@ mod tests { expected_vec_with_length.extend_from_slice(&expected_bytes); let mut faucet = Faucet::new(keypair, None, None, None); - let response = faucet.process_faucet_request(&req); + let response = faucet.process_faucet_request(&req, ip); let response_vec = response.unwrap().to_vec(); assert_eq!(expected_vec_with_length, response_vec); let bad_bytes = "bad bytes".as_bytes(); - assert!(faucet.process_faucet_request(&bad_bytes).is_err()); + assert!(faucet.process_faucet_request(&bad_bytes, ip).is_err()); } } diff --git a/faucet/src/faucet_mock.rs b/faucet/src/faucet_mock.rs index b5e27b10d9..74c740cac8 100644 --- a/faucet/src/faucet_mock.rs +++ b/faucet/src/faucet_mock.rs @@ -1,9 +1,12 @@ -use solana_sdk::{ - hash::Hash, pubkey::Pubkey, signature::Keypair, system_transaction, transaction::Transaction, -}; -use std::{ - io::{Error, ErrorKind}, - net::SocketAddr, +use { + solana_sdk::{ + hash::Hash, pubkey::Pubkey, signature::Keypair, system_transaction, + transaction::Transaction, + }, + std::{ + io::{Error, ErrorKind}, + net::SocketAddr, + }, }; pub fn request_airdrop_transaction( diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index fb927f8a1b..a9b97832ab 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -216,7 +216,7 @@ dependencies = [ "borsh-schema-derive-internal", "proc-macro-crate", "proc-macro2 1.0.24", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -227,7 +227,7 @@ checksum = "d813fa25eb0bed78c36492cff4415f38c760d6de833d255ba9095bd8ebb7d725" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -238,7 +238,7 @@ checksum = "dcf78ee4a98c8cb9eba1bac3d3e2a1ea3d7673c719ce691e67b5cbafc472d3b7" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -659,7 +659,7 @@ checksum = "eaed5874effa6cde088c644ddcdcb4ffd1511391c5be4fdd7a5ccd02c7e4a183" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -700,6 +700,27 @@ dependencies = [ "walkdir", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[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 0.3.8", +] + [[package]] name = "dtoa" version = "0.4.5" @@ -762,9 +783,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" +checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" dependencies = [ "atty", "humantime", @@ -791,7 +812,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "synstructure", ] @@ -910,7 +931,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -1402,6 +1423,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "lock_api" version = "0.3.4" @@ -1633,7 +1660,7 @@ checksum = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -1684,7 +1711,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -1772,7 +1799,7 @@ dependencies = [ "Inflector", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -1920,7 +1947,7 @@ checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2147,6 +2174,16 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom 0.2.1", + "redox_syscall 0.2.4", +] + [[package]] name = "regex" version = "1.3.9" @@ -2324,7 +2361,7 @@ checksum = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2395,9 +2432,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] @@ -2413,13 +2450,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -2445,6 +2482,18 @@ dependencies = [ "url", ] +[[package]] +name = "serde_yaml" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" +dependencies = [ + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", +] + [[package]] name = "sha-1" version = "0.8.2" @@ -2873,6 +2922,18 @@ dependencies = [ "url", ] +[[package]] +name = "solana-cli-config" +version = "1.5.19" +dependencies = [ + "dirs-next", + "lazy_static", + "serde", + "serde_derive", + "serde_yaml", + "url", +] + [[package]] name = "solana-cli-output" version = "1.5.19" @@ -2915,6 +2976,7 @@ dependencies = [ "serde_json", "solana-account-decoder", "solana-clap-utils", + "solana-faucet", "solana-net-utils", "solana-sdk", "solana-transaction-status", @@ -2955,29 +3017,30 @@ dependencies = [ "reqwest", "serde", "syn 0.15.44", - "syn 1.0.48", + "syn 1.0.67", "tokio 0.1.22", "winapi 0.3.8", ] [[package]] -name = "solana-frozen-abi" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc44c8096d5847d8cf7f3af3cce565de554cb56371decf93b060633ca8588913" +name = "solana-faucet" +version = "1.5.19" dependencies = [ - "bs58", - "bv", - "generic-array 0.14.3", + "bincode", + "byteorder 1.3.4", + "clap", "log", - "memmap2", - "rustc_version", "serde", "serde_derive", - "sha2 0.9.2", - "solana-frozen-abi-macro 1.5.8", - "solana-logger 1.5.8", + "solana-clap-utils", + "solana-cli-config", + "solana-logger 1.5.19", + "solana-metrics", + "solana-sdk", + "solana-version", + "spl-memo 3.0.0", "thiserror", + "tokio 0.3.6", ] [[package]] @@ -2999,16 +3062,23 @@ dependencies = [ ] [[package]] -name = "solana-frozen-abi-macro" -version = "1.5.8" +name = "solana-frozen-abi" +version = "1.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f905159beff1b53e4ba8b018a9d13d96ba164c3973bf3b9d587e730bcc14fc18" +checksum = "c59a0527921b3e66e9c8abda26f03e28c05e1ac462bfca6e7b84a4076fadc041" dependencies = [ - "lazy_static", - "proc-macro2 1.0.24", - "quote 1.0.6", + "bs58", + "bv", + "generic-array 0.14.3", + "log", + "memmap2", "rustc_version", - "syn 1.0.48", + "serde", + "serde_derive", + "sha2 0.9.2", + "solana-frozen-abi-macro 1.6.5", + "solana-logger 1.6.5", + "thiserror", ] [[package]] @@ -3019,14 +3089,25 @@ dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", "rustc_version", - "syn 1.0.48", + "syn 1.0.67", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71a32b3430d885d98dca4daa0c32de9d29e43163e2822f80975d75d04dfa89ea" +dependencies = [ + "lazy_static", + "proc-macro2 1.0.24", + "quote 1.0.6", + "rustc_version", + "syn 1.0.67", ] [[package]] name = "solana-logger" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83a006d97da5514a4475141573383d3fcd71c729ff78494f96bb531cf734d21" +version = "1.5.19" dependencies = [ "env_logger", "lazy_static", @@ -3035,7 +3116,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.5.19" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d75a277c10051df00277b2212c9e51dc8cd44229cf6b356a4adb0dc12533507" dependencies = [ "env_logger", "lazy_static", @@ -3084,36 +3167,6 @@ dependencies = [ "url", ] -[[package]] -name = "solana-program" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2007bf285617f8a783e96b20ccd2f8d813549090a5b520f22e5f65b3cd9b157" -dependencies = [ - "bincode", - "bs58", - "bv", - "curve25519-dalek 2.1.0", - "hex", - "itertools 0.9.0", - "lazy_static", - "log", - "num-derive 0.3.0", - "num-traits", - "rand 0.7.3", - "rustc_version", - "rustversion", - "serde", - "serde_bytes", - "serde_derive", - "sha2 0.9.2", - "solana-frozen-abi 1.5.8", - "solana-frozen-abi-macro 1.5.8", - "solana-logger 1.5.8", - "solana-sdk-macro 1.5.8", - "thiserror", -] - [[package]] name = "solana-program" version = "1.5.19" @@ -3145,6 +3198,39 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-program" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e452a9421cc6c0a313c9542d1b92be4491402073e35a2bb2d0b72e84c03a3945" +dependencies = [ + "bincode", + "blake3", + "borsh", + "borsh-derive", + "bs58", + "bv", + "curve25519-dalek 2.1.0", + "hex", + "itertools 0.9.0", + "lazy_static", + "log", + "num-derive 0.3.0", + "num-traits", + "rand 0.7.3", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.9.2", + "solana-frozen-abi 1.6.5", + "solana-frozen-abi-macro 1.6.5", + "solana-logger 1.6.5", + "solana-sdk-macro 1.6.5", + "thiserror", +] + [[package]] name = "solana-rayon-threadlimit" version = "1.5.19" @@ -3263,19 +3349,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "solana-sdk-macro" -version = "1.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a6635f1798c8ff1b88bb0fad1d4693c011f36a73c9ae03f198203144edcabb" -dependencies = [ - "bs58", - "proc-macro2 1.0.24", - "quote 1.0.6", - "rustversion", - "syn 1.0.48", -] - [[package]] name = "solana-sdk-macro" version = "1.5.19" @@ -3284,7 +3357,20 @@ dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", "rustversion", - "syn 1.0.48", + "syn 1.0.67", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5649e54928a244aad80ee3ab817b6ac37bf7b3b1559fd72989d5978e308b616a" +dependencies = [ + "bs58", + "proc-macro2 1.0.24", + "quote 1.0.6", + "rustversion", + "syn 1.0.67", ] [[package]] @@ -3407,7 +3493,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4adc47eebe5d2b662cbaaba1843719c28a67e5ec5d0460bc3ca60900a51f74e2" dependencies = [ - "solana-program 1.5.8", + "solana-program 1.6.5", "spl-token", ] @@ -3417,7 +3503,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb2b771f6146dec14ef5fbf498f9374652c54badc3befc8c40c1d426dd45d720" dependencies = [ - "solana-program 1.5.8", + "solana-program 1.6.5", ] [[package]] @@ -3426,7 +3512,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e76b60c6f58279b5469beb1705744e9778ee94d643c8e3e2ff91874c59bb3c63" dependencies = [ - "solana-program 1.5.8", + "solana-program 1.6.5", ] [[package]] @@ -3439,7 +3525,7 @@ dependencies = [ "num-derive 0.3.0", "num-traits", "num_enum", - "solana-program 1.5.8", + "solana-program 1.6.5", "thiserror", ] @@ -3486,9 +3572,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.48" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", @@ -3503,7 +3589,7 @@ checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "unicode-xid 0.2.0", ] @@ -3587,7 +3673,7 @@ checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -3750,7 +3836,7 @@ checksum = "46dfffa59fc3c8aad216ed61bdc2c263d2b9d87a9c8ac9de0c11a813e51b6db7" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", ] [[package]] @@ -4115,7 +4201,7 @@ dependencies = [ "log", "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "wasm-bindgen-shared", ] @@ -4149,7 +4235,7 @@ checksum = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4260,6 +4346,15 @@ dependencies = [ "libc", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "zeroize" version = "1.1.0" @@ -4277,7 +4372,7 @@ checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.6", - "syn 1.0.48", + "syn 1.0.67", "synstructure", ]