feat: compute pinata solution in wallet

This commit is contained in:
Daniil Polyakov 2025-11-30 03:16:47 +03:00
parent 2cf60fff10
commit 5801073f84
6 changed files with 81 additions and 52 deletions

View File

@ -1379,10 +1379,8 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
let pinata_account_id = PINATA_BASE58;
let pinata_prize = 150;
let solution = 989106;
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to_account_id: make_public_account_input_from_str(ACC_SENDER),
solution,
to: make_public_account_input_from_str(ACC_SENDER),
});
let wallet_config = fetch_config().await.unwrap();
@ -1508,11 +1506,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("########## test_pinata_private_receiver ##########");
let pinata_account_id = PINATA_BASE58;
let pinata_prize = 150;
let solution = 989106;
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to_account_id: make_private_account_input_from_str(ACC_SENDER_PRIVATE),
solution,
to: make_private_account_input_from_str(ACC_SENDER_PRIVATE),
});
let wallet_config = fetch_config().await.unwrap();
@ -1565,7 +1561,6 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
info!("########## test_pinata_private_receiver ##########");
let pinata_account_id = PINATA_BASE58;
let pinata_prize = 150;
let solution = 989106;
// Create new account for the token supply holder (private)
let SubcommandReturnValue::RegisterAccount {
@ -1580,8 +1575,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
};
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to_account_id: make_private_account_input_from_str(&winner_account_id.to_string()),
solution,
to: make_private_account_input_from_str(&winner_account_id.to_string()),
});
let wallet_config = fetch_config().await.unwrap();

View File

@ -233,8 +233,8 @@ impl V02State {
Account {
program_owner: Program::pinata().id(),
balance: 1500,
// Difficulty: 3
data: vec![3; 33],
// Difficulty: 2
data: vec![2; 33],
nonce: 0,
},
);

View File

@ -20,6 +20,7 @@ base58.workspace = true
hex = "0.4.3"
rand.workspace = true
itertools = "0.14.0"
sha2.workspace = true
[dependencies.key_protocol]
path = "../key_protocol"

View File

@ -61,7 +61,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
.register_account(account_id)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let transfer_tx =
wallet_core.poll_native_token_transfer(res.tx_hash).await?;
@ -79,7 +79,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
.register_account_private(account_id)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -320,7 +320,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
.send_private_transfer_to_owned_account(from, to, amount)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -364,7 +364,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
.send_private_transfer_to_outer_account(from, to_npk, to_ipk, amount)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -404,7 +404,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
.send_shielded_transfer(from, to, amount)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -449,7 +449,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
.send_shielded_transfer_to_outer_account(from, to_npk, to_ipk, amount)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
@ -483,7 +483,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
.send_deshielded_transfer(from, to, amount)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -513,7 +513,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
.send_public_transfer(from, to, amount)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?;

View File

@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{Context, Result};
use clap::Subcommand;
use common::{PINATA_BASE58, transaction::NSSATransaction};
@ -14,12 +14,9 @@ use crate::{
pub enum PinataProgramAgnosticSubcommand {
/// Claim pinata
Claim {
/// to_account_id - valid 32 byte base58 string with privacy prefix
/// to - valid 32 byte base58 string with privacy prefix
#[arg(long)]
to_account_id: String,
/// solution - solution to pinata challenge
#[arg(long)]
solution: u128,
to: String,
},
}
@ -29,26 +26,20 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand {
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
let underlying_subcommand = match self {
PinataProgramAgnosticSubcommand::Claim {
to_account_id,
solution,
} => {
let (to_account_id, to_addr_privacy) =
parse_addr_with_privacy_prefix(&to_account_id)?;
PinataProgramAgnosticSubcommand::Claim { to } => {
let (to, to_addr_privacy) = parse_addr_with_privacy_prefix(&to)?;
match to_addr_privacy {
AccountPrivacyKind::Public => {
PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim {
pinata_account_id: PINATA_BASE58.to_string(),
winner_account_id: to_account_id,
solution,
winner_account_id: to,
})
}
AccountPrivacyKind::Private => PinataProgramSubcommand::Private(
PinataProgramSubcommandPrivate::ClaimPrivateOwned {
pinata_account_id: PINATA_BASE58.to_string(),
winner_account_id: to_account_id,
solution,
winner_account_id: to,
},
),
}
@ -82,9 +73,6 @@ pub enum PinataProgramSubcommandPublic {
/// winner_account_id - valid 32 byte hex string
#[arg(long)]
winner_account_id: String,
/// solution - solution to pinata challenge
#[arg(long)]
solution: u128,
},
}
@ -100,9 +88,6 @@ pub enum PinataProgramSubcommandPrivate {
/// winner_account_id - valid 32 byte hex string
#[arg(long)]
winner_account_id: String,
/// solution - solution to pinata challenge
#[arg(long)]
solution: u128,
},
}
@ -115,17 +100,21 @@ impl WalletSubcommand for PinataProgramSubcommandPublic {
PinataProgramSubcommandPublic::Claim {
pinata_account_id,
winner_account_id,
solution,
} => {
let pinata_account_id = pinata_account_id.parse().unwrap();
let solution = find_solution(wallet_core, pinata_account_id)
.await
.context("failed to compute solution")?;
let res = Pinata(wallet_core)
.claim(
pinata_account_id.parse().unwrap(),
pinata_account_id,
winner_account_id.parse().unwrap(),
solution,
)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -153,16 +142,18 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
PinataProgramSubcommandPrivate::ClaimPrivateOwned {
pinata_account_id,
winner_account_id,
solution,
} => {
let pinata_account_id = pinata_account_id.parse().unwrap();
let winner_account_id = winner_account_id.parse().unwrap();
let solution = find_solution(wallet_core, pinata_account_id)
.await
.context("failed to compute solution")?;
let (res, secret_winner) = Pinata(wallet_core)
.claim_private_owned_account(pinata_account_id, winner_account_id, solution)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -205,3 +196,46 @@ impl WalletSubcommand for PinataProgramSubcommand {
}
}
}
async fn find_solution(wallet: &WalletCore, pinata_account_id: nssa::AccountId) -> Result<u128> {
let account = wallet.get_account_public(pinata_account_id).await?;
let data: [u8; 33] = account
.data
.try_into()
.map_err(|_| anyhow::Error::msg("invalid pinata account data"))?;
println!("Computing solution for pinata...");
let now = std::time::Instant::now();
let solution = compute_solution(data);
println!("Found solution {solution} in {:?}", now.elapsed());
Ok(solution)
}
fn compute_solution(data: [u8; 33]) -> u128 {
let difficulty = data[0];
let seed = &data[1..];
let mut solution = 0u128;
while !validate_solution(difficulty, seed, solution) {
solution = solution.checked_add(1).expect("solution overflowed u128");
}
solution
}
fn validate_solution(difficulty: u8, seed: &[u8], solution: u128) -> bool {
use sha2::{Digest as _, digest::FixedOutput as _};
let mut bytes = [0; 32 + 16];
bytes[..32].copy_from_slice(seed);
bytes[32..].copy_from_slice(&solution.to_le_bytes());
let mut hasher = sha2::Sha256::new();
hasher.update(bytes);
let digest: [u8; 32] = hasher.finalize_fixed().into();
let difficulty = difficulty as usize;
digest[..difficulty].iter().all(|&b| b == 0)
}

View File

@ -399,7 +399,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -437,7 +437,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -490,7 +490,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -538,7 +538,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -598,7 +598,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core
@ -631,7 +631,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
)
.await?;
println!("Results of tx send is {res:#?}");
println!("Results of tx send are {res:#?}");
let tx_hash = res.tx_hash;
let transfer_tx = wallet_core