Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add enable_dc_burn setting to mobile packet verifier #425

Merged
merged 2 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 103 additions & 89 deletions mobile_packet_verifier/src/burner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub struct Burner {
program_cache: BurnProgramCache,
keypair: [u8; 64],
cluster: String,
enable_dc_burn: bool,
}

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -92,6 +93,7 @@ impl Burner {
valid_sessions,
keypair: keypair.to_bytes(),
cluster: settings.cluster.clone(),
enable_dc_burn: settings.enable_dc_burn,
})
}

Expand Down Expand Up @@ -119,99 +121,12 @@ impl Burner {
},
) in payer_totals.into_iter()
{
// Fetch the sub dao epoch info:
const EPOCH_LENGTH: u64 = 60 * 60 * 24;
let epoch = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)?
.as_secs()
/ EPOCH_LENGTH;
let (sub_dao_epoch_info, _) = Pubkey::find_program_address(
&[
"sub_dao_epoch_info".as_bytes(),
self.program_cache.sub_dao.as_ref(),
&epoch.to_le_bytes(),
],
&helium_sub_daos::ID,
);

let amount = bytes_to_dc(total_bytes);

// Burn the DC for the payer
let ddc_key = crate::pdas::delegated_data_credits(&self.program_cache.sub_dao, &payer);
let account_data = self.provider.get_account_data(&ddc_key).await?;
let mut account_data = account_data.as_ref();
let escrow_account =
DelegatedDataCreditsV0::try_deserialize(&mut account_data)?.escrow_account;

tracing::info!("Burning {} DC from {}", amount, payer);

let instructions = {
let request = RequestBuilder::from(
data_credits::id(),
&self.cluster,
std::rc::Rc::new(Keypair::from_bytes(&self.keypair).unwrap()),
Some(CommitmentConfig::confirmed()),
RequestNamespace::Global,
);

let accounts = accounts::BurnDelegatedDataCreditsV0 {
sub_dao_epoch_info,
dao: self.program_cache.dao,
sub_dao: self.program_cache.sub_dao,
account_payer: self.program_cache.account_payer,
data_credits: self.program_cache.data_credits,
delegated_data_credits: ddc_key,
token_program: spl_token::id(),
helium_sub_daos_program: helium_sub_daos::id(),
system_program: solana_program::system_program::id(),
dc_burn_authority: self.program_cache.dc_burn_authority,
dc_mint: self.program_cache.dc_mint,
escrow_account,
registrar: self.program_cache.registrar,
};
let args = instruction::BurnDelegatedDataCreditsV0 {
args: data_credits::BurnDelegatedDataCreditsArgsV0 { amount },
};

// As far as I can tell, the instructions function does not actually have any
// error paths.
request
.accounts(accounts)
.args(args)
.instructions()
.unwrap()
};

let blockhash = self.provider.get_latest_blockhash().await?;
let signer = Keypair::from_bytes(&self.keypair).unwrap();

let tx = SolanaTransaction::new_signed_with_payer(
&instructions,
Some(&signer.pubkey()),
&[&signer],
blockhash,
);

// Preflight can be flakey, so we skip it for now
let config = RpcSendTransactionConfig {
skip_preflight: true,
..Default::default()
};
let signature = self
.provider
.send_transaction_with_config(&tx, config)
.await?;
let result = self.provider.confirm_transaction(&signature).await?;

if !result {
return Err(BurnError::TransactionFailed(signature));
if self.enable_dc_burn {
self.burn_data_credits(&payer, amount).await?;
}

tracing::info!(
"Successfully burned data credits. Transaction: {}",
signature
);

// Delete from the data transfer session and write out to S3

sqlx::query("DELETE FROM data_tranfer_sessions WHERE payer = $1")
Expand Down Expand Up @@ -239,6 +154,105 @@ impl Burner {

Ok(())
}

async fn burn_data_credits(
&self,
payer: &PublicKeyBinary,
amount: u64,
) -> Result<(), BurnError> {
tracing::info!("Burning {} DC from {}", amount, payer);

// Fetch the sub dao epoch info:
const EPOCH_LENGTH: u64 = 60 * 60 * 24;
let epoch = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)?
.as_secs()
/ EPOCH_LENGTH;
let (sub_dao_epoch_info, _) = Pubkey::find_program_address(
&[
"sub_dao_epoch_info".as_bytes(),
self.program_cache.sub_dao.as_ref(),
&epoch.to_le_bytes(),
],
&helium_sub_daos::ID,
);

// Burn the DC for the payer
let ddc_key = crate::pdas::delegated_data_credits(&self.program_cache.sub_dao, payer);
let account_data = self.provider.get_account_data(&ddc_key).await?;
let mut account_data = account_data.as_ref();
let escrow_account =
DelegatedDataCreditsV0::try_deserialize(&mut account_data)?.escrow_account;

let instructions = {
let request = RequestBuilder::from(
data_credits::id(),
&self.cluster,
std::rc::Rc::new(Keypair::from_bytes(&self.keypair).unwrap()),
Some(CommitmentConfig::confirmed()),
RequestNamespace::Global,
);

let accounts = accounts::BurnDelegatedDataCreditsV0 {
sub_dao_epoch_info,
dao: self.program_cache.dao,
sub_dao: self.program_cache.sub_dao,
account_payer: self.program_cache.account_payer,
data_credits: self.program_cache.data_credits,
delegated_data_credits: ddc_key,
token_program: spl_token::id(),
helium_sub_daos_program: helium_sub_daos::id(),
system_program: solana_program::system_program::id(),
dc_burn_authority: self.program_cache.dc_burn_authority,
dc_mint: self.program_cache.dc_mint,
escrow_account,
registrar: self.program_cache.registrar,
};
let args = instruction::BurnDelegatedDataCreditsV0 {
args: data_credits::BurnDelegatedDataCreditsArgsV0 { amount },
};

// As far as I can tell, the instructions function does not actually have any
// error paths.
request
.accounts(accounts)
.args(args)
.instructions()
.unwrap()
};

let blockhash = self.provider.get_latest_blockhash().await?;
let signer = Keypair::from_bytes(&self.keypair).unwrap();

let tx = SolanaTransaction::new_signed_with_payer(
&instructions,
Some(&signer.pubkey()),
&[&signer],
blockhash,
);

// Preflight can be flakey, so we skip it for now
let config = RpcSendTransactionConfig {
skip_preflight: true,
..Default::default()
};
let signature = self
.provider
.send_transaction_with_config(&tx, config)
.await?;
let result = self.provider.confirm_transaction(&signature).await?;

if !result {
return Err(BurnError::TransactionFailed(signature));
}

tracing::info!(
"Successfully burned data credits. Transaction: {}",
signature
);

Ok(())
}
}

const BYTES_PER_DC: u64 = 20_000;
Expand Down
2 changes: 2 additions & 0 deletions mobile_packet_verifier/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub struct Settings {
pub ingest: file_store::Settings,
pub output: file_store::Settings,
pub metrics: poc_metrics::Settings,
#[serde(default)]
pub enable_dc_burn: bool,
}

pub fn default_url() -> http::Uri {
Expand Down