diff --git a/.github/workflows/linux-ci-rust.yml b/.github/workflows/linux-ci-rust.yml index 258c8f2d916..cd6302e6aa0 100644 --- a/.github/workflows/linux-ci-rust.yml +++ b/.github/workflows/linux-ci-rust.yml @@ -134,7 +134,7 @@ jobs: # Download previous release report, compare the release binary sizes, and post/update a comment at the Pull Request. - name: Download previous release report - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false uses: dawidd6/action-download-artifact@v3 with: commit: ${{github.event.pull_request.base.sha}} @@ -146,13 +146,13 @@ jobs: workflow_conclusion: "" - name: Craft Comment Body - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false run: | # Please note `previous/release-report.json` may not exist if the previous report was not found. ./tools/release-size compare --before previous/release-report.json --current release-report.json > report-diff.md - name: Create or Update Comment - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false uses: edumserrano/find-create-or-update-comment@v2 with: issue-number: ${{ github.event.pull_request.number }} diff --git a/rust/chains/tw_solana/src/modules/instruction_builder/stake_instruction.rs b/rust/chains/tw_solana/src/modules/instruction_builder/stake_instruction.rs index be6ba463aba..a0dfd9139fb 100644 --- a/rust/chains/tw_solana/src/modules/instruction_builder/stake_instruction.rs +++ b/rust/chains/tw_solana/src/modules/instruction_builder/stake_instruction.rs @@ -376,9 +376,9 @@ impl StakeInstructionBuilder { pub fn deposit_stake(args: DepositStakeArgs) -> SigningResult> { let stake_addr = args.stake_account.unwrap_or_else(|| { // no stake address specified, generate a new unique - StakeProgram::address_from_recent_blockhash(args.sender, args.recent_blockhash) + StakeProgram::address_from_recent_blockhash(&args.sender, &args.recent_blockhash) }); - let seed = args.recent_blockhash.to_string(); + let seed = StakeProgram::recent_blockhash_as_seed(&args.recent_blockhash); let authorized = Authorized { staker: args.sender, diff --git a/rust/chains/tw_solana/src/program/stake_program.rs b/rust/chains/tw_solana/src/program/stake_program.rs index 5f2ca1886dc..5161edec832 100644 --- a/rust/chains/tw_solana/src/program/stake_program.rs +++ b/rust/chains/tw_solana/src/program/stake_program.rs @@ -9,15 +9,25 @@ use tw_coin_entry::error::{AddressError, AddressResult}; use tw_hash::sha2::sha256; use tw_hash::H256; +pub const MAX_SEED_LEN: usize = 32; + pub struct StakeProgram; impl StakeProgram { + pub fn recent_blockhash_as_seed(recent_blockhash: &Blockhash) -> String { + recent_blockhash + .to_string() + .chars() + .take(MAX_SEED_LEN) + .collect() + } + pub fn address_from_recent_blockhash( - from: SolanaAddress, - recent_blockhash: Blockhash, + from: &SolanaAddress, + recent_blockhash: &Blockhash, ) -> SolanaAddress { let mut seed = from.bytes().to_vec(); - seed.extend_from_slice(recent_blockhash.to_string().as_bytes()); + seed.extend_from_slice(Self::recent_blockhash_as_seed(recent_blockhash).as_bytes()); seed.extend_from_slice(STAKE_PROGRAM_ID_ADDRESS.bytes().as_slice()); let bytes = H256::try_from(sha256(&seed).as_slice()).expect("sha256 expected to return 32 bytes"); diff --git a/rust/chains/tw_solana/tests/get_default_token_address.rs b/rust/chains/tw_solana/tests/get_default_token_address.rs index 94c3358ed5a..d2b4690f9dc 100644 --- a/rust/chains/tw_solana/tests/get_default_token_address.rs +++ b/rust/chains/tw_solana/tests/get_default_token_address.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use tw_solana::address::SolanaAddress; +use tw_solana::blockhash::Blockhash; use tw_solana::program::stake_program::StakeProgram; fn test_get_default_token_address_impl( @@ -48,3 +49,31 @@ fn test_get_default_token_address() { "ANVCrmRw7Ww7rTFfMbrjApSPXEEcZpBa6YEiBdf98pAf", ); } + +fn test_address_from_recent_blockhash_impl(main_address: &str, blockhash: &str, expected: &str) { + let main_address = SolanaAddress::from_str(main_address).unwrap(); + let expected = SolanaAddress::from_str(expected).unwrap(); + let blockhash = Blockhash::from_str(blockhash).unwrap(); + + let actual = StakeProgram::address_from_recent_blockhash(&main_address, &blockhash); + assert_eq!(actual, expected); +} + +#[test] +fn test_address_from_recent_blockhash() { + test_address_from_recent_blockhash_impl( + "zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu", + "11111111111111111111111111111111", + "GQDDc5EVGJZFC7AvpEJ8eoCQ75Yy4gr7eu17frCjvQRQ", + ); + test_address_from_recent_blockhash_impl( + "zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu", + "9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K", + "2Kos1xJRBq3Ae1GnVNBx7HgJhq8KvdUe2bXE4QGdNaXb", + ); + test_address_from_recent_blockhash_impl( + "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V", + "AfzzEC8NVXoxKoHdjXLDVzqwqvvZmgPuqyJqjuHiPY1D", + "Fxhhm82PZVuXEwycT28vGqknUEnVeoHh4UWEnJNQUDbv", + ); +} diff --git a/rust/tw_any_coin/tests/chains/solana/solana_sign.rs b/rust/tw_any_coin/tests/chains/solana/solana_sign.rs index 3f53846e94b..186105c5fda 100644 --- a/rust/tw_any_coin/tests/chains/solana/solana_sign.rs +++ b/rust/tw_any_coin/tests/chains/solana/solana_sign.rs @@ -219,6 +219,33 @@ fn test_solana_sign_delegate_stake_no_stake_account() { assert_eq!(output.encoded, "j24mVM9Zgu5vDZhPLGGuCRXQnP9djNtxdHh4txN3S7dwJsNNL5fbhzGpPgSUAcLGoMVCfF9TuqTYfpfJnb4sJFe1ahM8yPL5HwuKL6py5AZJFi8SWx9fvaVB699dCPo1GT3JoEBLPCZ9o2jQtnwzLkzTYJnKv2axqhKWFE2sz6TBA5J39eZcjMFUYgyxz6Q5S4MWqYQCb8UET2NAEZoKcfy7j8N25WXL6Gj4j3hBZjpHQQNaGaNEprEqyma3ZuVhpGiCALSsuzVLX3wZVo4icXwe952deMFA4tH3BK1jcSQCgfmcKDJ9nd7bdrnUUs4BoMdF1uDZB5LxE2UH8QiqtYvaUcorF4SJ3gPxM5ykbyPsNK1cSYZF9NMpW2GofyC17eELwnHQTQB2kqphxJZu7BahvkwiDPPeeydiXAkBspJ3nc3PCBujv6WJw22ZHw5j6zAP8ZGnCW44pqtWD5qifF9tTKhySKdANNiWifs3tSCCPQqjfJXu14drNinR6VG8rJxS1qgmRYiRQUa7m1vtoaZFRN5qKUeAfoFKkAVaNnMdwgsNqNH4dqBodTCJFs1LkYwhgRZdZGbwXTn1j7vpR3DSnv4g72i2H556srzK53jdUmdv6yfxt516XDSshqZtHnKZ1tudxKjBXwsqT3imDiZFVka9wKWUAYMCi4XZ79CY6Xpsd9c18U2e9TCngQmgkTATFgrqysfraokNffgqWxvsPMugksbvbPjJs3iCzByvphkC9p7hCf6LwbeF8XnVB91EAgRDA4VLE1f9wkcq5zjy879YWJ4r516h3PQszTz1EaJXNAXdbk5Em7eyuuabGP1Q3nijFTL2yhMDsXpgrjAuEAABNxFMd4J1JRMaic615mHrhwociksrsfQK"); } +#[test] +fn test_solana_sign_delegate_stake_no_stake_account_5zrqgk1() { + // Corresponding Solana address: GcQQ1qx822KK14zyfTkMLQMLEZ4a9d88HnKepaA2XbmW. + let private_key = "507479b94db463a33cdc413db98437b4aa8c74b6053aea936d1830c27027b1e9" + .decode_hex() + .unwrap(); + let delegate = Proto::DelegateStake { + validator_pubkey: "BWkvytz3MAiLkUbMuYK5yV1VYThbBYYQYG3gdef8NLw5".into(), + value: 10000000, + ..Proto::DelegateStake::default() + }; + let input = Proto::SigningInput { + private_key: private_key.into(), + recent_blockhash: "6ocSmEiuSHkN5yKDUaQrJHCzWCYXuFk3g3jB4rN1uDzv".into(), + transaction_type: TransactionType::delegate_stake_transaction(delegate), + ..Proto::SigningInput::default() + }; + + let mut signer = AnySignerHelper::::default(); + let output = signer.sign(CoinType::Solana, input); + + assert_eq!(output.error, SigningError::OK); + // Successfully broadcasted: + // https://solscan.io/tx/5zRQgK1oc1oHLhsM68AM2pSUUqif6VMMnuUKjyZgUsdySaNRufvzoEu8D8SF99GThw8iZiwRbPhnsDePpnDKKmRq + assert_eq!(output.encoded, "nuo7rnbTG4QLqpjYoPPPhDusRjpEVDyzos8YvdX67sDaw2XwfTJNm7eXcdxqjkgLqzFiHbD7kvm1i7f1caGjxZwTEzWqNkxK28YXJXU4S2NbQFa7HwSdamF38PLgKwNKmnUkh1quaZDFK3X5swL49QPxFhtSwFcFo9TphPsfeFjMbqqsLR8vjzLkePTrWKUSMmbwMG8U9TDEeWrsWbKaFeWsRQxzYP7ubDokPLVxGJopaEUobtUGyRA5K2A9H4dbuN7pZJSLwL926hGJQphjiXuJhD9PqY5TCRAq9PhyS6jtYP6ToQUiPfvigm5aHwb5rtEZKu5gM393G7LKfedMi263FVSnJyAb41i4xZXTMD3HdKiDBF5UomqCQEyPQhM4X8mYzPDPofRZfQjz2xS1fDesxY3BWMxwKQ6bgtazJDprBWWNJ7ULpHFEJ8wXtHAR3CfTWowQJ23zsKNUPbb6Ft4Lng3DJrRkMcTvvecLx9nnNqyuwjkqcBysWqJ4pJdvLC4QAnwoZzKAn8uzTKUSA85gSeE96RUmRVE4CgtPkZ7jYgmsSS5XgcC7g4XegHHJFQ3iMG4Uuxft635txXHAbkh6x9Ra9JnPFUq6Zdgc9UyCWrhhaKDvfmFgC2K7tykqHLXdDninmR2s7zmc1wsoGYeGvy2NbLTU3mRpyVwQPFaKPDPSisJYKYY4HnBQfG89wRLh4jkRsrH9snvxYwhgRLcsaMniwGNPpQEU4tLAkxHwco32rnxyFwycaPqEYsYpTR5vc5RUrnyy4nhEx1V79hqBb7NScxAbBsaBXvYpYitgdfX1h19uBr7A7uqZ3mqptKqA2Q3VjZthnLLGjJNVuR4BNJEa7VzPnR8SLCckjVycSHkbG26cUmB985K5"); +} + #[test] fn test_solana_sign_delegate_stake_with_account() { let delegate = Proto::DelegateStake {