transaction-status: Add return data to meta (#23688)
* transaction-status: Add return data to meta * Add return data to simulation results * Use pretty-hex for printing return data * Update arg name, make TransactionRecord struct * Rename TransactionRecord -> ExecutionRecord
This commit is contained in:
parent
359e2de090
commit
7af48465fa
|
@ -4424,6 +4424,7 @@ dependencies = [
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"humantime",
|
"humantime",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
|
"pretty-hex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-account-decoder",
|
"solana-account-decoder",
|
||||||
|
@ -5309,6 +5310,7 @@ dependencies = [
|
||||||
name = "solana-program-test"
|
name = "solana-program-test"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"assert_matches",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.13.0",
|
"base64 0.13.0",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use {
|
use {
|
||||||
solana_sdk::{transaction::TransactionError, transport::TransportError},
|
solana_sdk::{
|
||||||
|
transaction::TransactionError, transaction_context::TransactionReturnData,
|
||||||
|
transport::TransportError,
|
||||||
|
},
|
||||||
std::io,
|
std::io,
|
||||||
tarpc::client::RpcError,
|
tarpc::client::RpcError,
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
@ -25,6 +28,7 @@ pub enum BanksClientError {
|
||||||
err: TransactionError,
|
err: TransactionError,
|
||||||
logs: Vec<String>,
|
logs: Vec<String>,
|
||||||
units_consumed: u64,
|
units_consumed: u64,
|
||||||
|
return_data: Option<TransactionReturnData>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,6 +247,7 @@ impl BanksClient {
|
||||||
err,
|
err,
|
||||||
logs: simulation_details.logs,
|
logs: simulation_details.logs,
|
||||||
units_consumed: simulation_details.units_consumed,
|
units_consumed: simulation_details.units_consumed,
|
||||||
|
return_data: simulation_details.return_data,
|
||||||
}),
|
}),
|
||||||
BanksTransactionResultWithSimulation {
|
BanksTransactionResultWithSimulation {
|
||||||
result: Some(result),
|
result: Some(result),
|
||||||
|
|
|
@ -12,6 +12,7 @@ use {
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
transaction::{self, Transaction, TransactionError},
|
transaction::{self, Transaction, TransactionError},
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ pub struct TransactionStatus {
|
||||||
pub struct TransactionSimulationDetails {
|
pub struct TransactionSimulationDetails {
|
||||||
pub logs: Vec<String>,
|
pub logs: Vec<String>,
|
||||||
pub units_consumed: u64,
|
pub units_consumed: u64,
|
||||||
|
pub return_data: Option<TransactionReturnData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
|
|
@ -266,6 +266,7 @@ impl Banks for BanksServer {
|
||||||
logs,
|
logs,
|
||||||
post_simulation_accounts: _,
|
post_simulation_accounts: _,
|
||||||
units_consumed,
|
units_consumed,
|
||||||
|
return_data,
|
||||||
} = self
|
} = self
|
||||||
.bank(commitment)
|
.bank(commitment)
|
||||||
.simulate_transaction_unchecked(sanitized_transaction)
|
.simulate_transaction_unchecked(sanitized_transaction)
|
||||||
|
@ -275,6 +276,7 @@ impl Banks for BanksServer {
|
||||||
simulation_details: Some(TransactionSimulationDetails {
|
simulation_details: Some(TransactionSimulationDetails {
|
||||||
logs,
|
logs,
|
||||||
units_consumed,
|
units_consumed,
|
||||||
|
return_data,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ clap = "2.33.0"
|
||||||
console = "0.15.0"
|
console = "0.15.0"
|
||||||
humantime = "2.0.1"
|
humantime = "2.0.1"
|
||||||
indicatif = "0.16.2"
|
indicatif = "0.16.2"
|
||||||
|
pretty-hex = "0.2.1"
|
||||||
serde = "1.0.136"
|
serde = "1.0.136"
|
||||||
serde_json = "1.0.79"
|
serde_json = "1.0.79"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "=1.11.0" }
|
solana-account-decoder = { path = "../account-decoder", version = "=1.11.0" }
|
||||||
|
|
|
@ -14,6 +14,7 @@ use {
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
stake,
|
stake,
|
||||||
transaction::{TransactionError, TransactionVersion, VersionedTransaction},
|
transaction::{TransactionError, TransactionVersion, VersionedTransaction},
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
solana_transaction_status::{Rewards, UiTransactionStatusMeta},
|
solana_transaction_status::{Rewards, UiTransactionStatusMeta},
|
||||||
spl_memo::{id as spl_memo_id, v1::id as spl_memo_v1_id},
|
spl_memo::{id as spl_memo_id, v1::id as spl_memo_v1_id},
|
||||||
|
@ -246,6 +247,7 @@ fn write_transaction<W: io::Write>(
|
||||||
write_fees(w, transaction_status.fee, prefix)?;
|
write_fees(w, transaction_status.fee, prefix)?;
|
||||||
write_balances(w, transaction_status, prefix)?;
|
write_balances(w, transaction_status, prefix)?;
|
||||||
write_log_messages(w, transaction_status.log_messages.as_ref(), prefix)?;
|
write_log_messages(w, transaction_status.log_messages.as_ref(), prefix)?;
|
||||||
|
write_return_data(w, transaction_status.return_data.as_ref(), prefix)?;
|
||||||
write_rewards(w, transaction_status.rewards.as_ref(), prefix)?;
|
write_rewards(w, transaction_status.rewards.as_ref(), prefix)?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(w, "{}Status: Unavailable", prefix)?;
|
writeln!(w, "{}Status: Unavailable", prefix)?;
|
||||||
|
@ -576,6 +578,25 @@ fn write_balances<W: io::Write>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_return_data<W: io::Write>(
|
||||||
|
w: &mut W,
|
||||||
|
return_data: Option<&TransactionReturnData>,
|
||||||
|
prefix: &str,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if let Some(return_data) = return_data {
|
||||||
|
if !return_data.data.is_empty() {
|
||||||
|
use pretty_hex::*;
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
"{}Return Data from Program {}:",
|
||||||
|
prefix, return_data.program_id
|
||||||
|
)?;
|
||||||
|
writeln!(w, "{} {:?}", prefix, return_data.data.hex_dump())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write_log_messages<W: io::Write>(
|
fn write_log_messages<W: io::Write>(
|
||||||
w: &mut W,
|
w: &mut W,
|
||||||
log_messages: Option<&Vec<String>>,
|
log_messages: Option<&Vec<String>>,
|
||||||
|
@ -750,6 +771,10 @@ mod test {
|
||||||
commission: None,
|
commission: None,
|
||||||
}]),
|
}]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData {
|
||||||
|
program_id: Pubkey::new_from_array([2u8; 32]),
|
||||||
|
data: vec![1, 2, 3],
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = {
|
let output = {
|
||||||
|
@ -786,6 +811,9 @@ Status: Ok
|
||||||
Account 1 balance: ◎0.00001 -> ◎0.0000099
|
Account 1 balance: ◎0.00001 -> ◎0.0000099
|
||||||
Log Messages:
|
Log Messages:
|
||||||
Test message
|
Test message
|
||||||
|
Return Data from Program 8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR:
|
||||||
|
Length: 3 (0x3) bytes
|
||||||
|
0000: 01 02 03 ...
|
||||||
Rewards:
|
Rewards:
|
||||||
Address Type Amount New Balance \0
|
Address Type Amount New Balance \0
|
||||||
4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLKi rent -◎0.000000100 ◎0.000009900 \0
|
4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLKi rent -◎0.000000100 ◎0.000009900 \0
|
||||||
|
@ -820,6 +848,10 @@ Rewards:
|
||||||
commission: None,
|
commission: None,
|
||||||
}]),
|
}]),
|
||||||
loaded_addresses,
|
loaded_addresses,
|
||||||
|
return_data: Some(TransactionReturnData {
|
||||||
|
program_id: Pubkey::new_from_array([2u8; 32]),
|
||||||
|
data: vec![1, 2, 3],
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = {
|
let output = {
|
||||||
|
@ -865,6 +897,9 @@ Status: Ok
|
||||||
Account 3 balance: ◎0.00002
|
Account 3 balance: ◎0.00002
|
||||||
Log Messages:
|
Log Messages:
|
||||||
Test message
|
Test message
|
||||||
|
Return Data from Program 8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR:
|
||||||
|
Length: 3 (0x3) bytes
|
||||||
|
0000: 01 02 03 ...
|
||||||
Rewards:
|
Rewards:
|
||||||
Address Type Amount New Balance \0
|
Address Type Amount New Balance \0
|
||||||
CktRuQ2mttgRGkXJtyksdKHjUdc2C4TgDzyB98oEzy8 rent -◎0.000000100 ◎0.000014900 \0
|
CktRuQ2mttgRGkXJtyksdKHjUdc2C4TgDzyB98oEzy8 rent -◎0.000000100 ◎0.000014900 \0
|
||||||
|
|
|
@ -229,6 +229,7 @@ impl RpcSender for MockSender {
|
||||||
post_token_balances: None,
|
post_token_balances: None,
|
||||||
rewards: None,
|
rewards: None,
|
||||||
loaded_addresses: None,
|
loaded_addresses: None,
|
||||||
|
return_data: None,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
block_time: Some(1628633791),
|
block_time: Some(1628633791),
|
||||||
|
@ -340,6 +341,7 @@ impl RpcSender for MockSender {
|
||||||
logs: None,
|
logs: None,
|
||||||
accounts: None,
|
accounts: None,
|
||||||
units_consumed: None,
|
units_consumed: None,
|
||||||
|
return_data: None,
|
||||||
},
|
},
|
||||||
})?,
|
})?,
|
||||||
"getMinimumBalanceForRentExemption" => json![20],
|
"getMinimumBalanceForRentExemption" => json![20],
|
||||||
|
|
|
@ -7,6 +7,7 @@ use {
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
inflation::Inflation,
|
inflation::Inflation,
|
||||||
transaction::{Result, TransactionError},
|
transaction::{Result, TransactionError},
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus, UiConfirmedBlock,
|
ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus, UiConfirmedBlock,
|
||||||
|
@ -347,6 +348,7 @@ pub struct RpcSimulateTransactionResult {
|
||||||
pub logs: Option<Vec<String>>,
|
pub logs: Option<Vec<String>>,
|
||||||
pub accounts: Option<Vec<Option<UiAccount>>>,
|
pub accounts: Option<Vec<Option<UiAccount>>>,
|
||||||
pub units_consumed: Option<u64>,
|
pub units_consumed: Option<u64>,
|
||||||
|
pub return_data: Option<TransactionReturnData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
|
|
@ -1180,6 +1180,7 @@ impl BankingStage {
|
||||||
MAX_PROCESSING_AGE,
|
MAX_PROCESSING_AGE,
|
||||||
transaction_status_sender.is_some(),
|
transaction_status_sender.is_some(),
|
||||||
transaction_status_sender.is_some(),
|
transaction_status_sender.is_some(),
|
||||||
|
transaction_status_sender.is_some(),
|
||||||
&mut execute_and_commit_timings.execute_timings,
|
&mut execute_and_commit_timings.execute_timings,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -2149,6 +2150,7 @@ mod tests {
|
||||||
log_messages: None,
|
log_messages: None,
|
||||||
inner_instructions: None,
|
inner_instructions: None,
|
||||||
durable_nonce_fee: None,
|
durable_nonce_fee: None,
|
||||||
|
return_data: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1331,7 +1331,7 @@ fn load_blockstore(
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
exit,
|
exit,
|
||||||
enable_rpc_transaction_history,
|
enable_rpc_transaction_history,
|
||||||
config.rpc_config.enable_cpi_and_log_storage,
|
config.rpc_config.enable_extended_tx_metadata_storage,
|
||||||
transaction_notifier,
|
transaction_notifier,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1538,7 +1538,7 @@ fn initialize_rpc_transaction_history_services(
|
||||||
blockstore: Arc<Blockstore>,
|
blockstore: Arc<Blockstore>,
|
||||||
exit: &Arc<AtomicBool>,
|
exit: &Arc<AtomicBool>,
|
||||||
enable_rpc_transaction_history: bool,
|
enable_rpc_transaction_history: bool,
|
||||||
enable_cpi_and_log_storage: bool,
|
enable_extended_tx_metadata_storage: bool,
|
||||||
transaction_notifier: Option<TransactionNotifierLock>,
|
transaction_notifier: Option<TransactionNotifierLock>,
|
||||||
) -> TransactionHistoryServices {
|
) -> TransactionHistoryServices {
|
||||||
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
||||||
|
@ -1552,7 +1552,7 @@ fn initialize_rpc_transaction_history_services(
|
||||||
enable_rpc_transaction_history,
|
enable_rpc_transaction_history,
|
||||||
transaction_notifier.clone(),
|
transaction_notifier.clone(),
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
enable_cpi_and_log_storage,
|
enable_extended_tx_metadata_storage,
|
||||||
exit,
|
exit,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -4697,6 +4697,7 @@ pub mod tests {
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
solana_storage_proto::convert::generated,
|
solana_storage_proto::convert::generated,
|
||||||
solana_transaction_status::{InnerInstructions, Reward, Rewards, TransactionTokenBalance},
|
solana_transaction_status::{InnerInstructions, Reward, Rewards, TransactionTokenBalance},
|
||||||
|
@ -6858,6 +6859,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
blockstore
|
blockstore
|
||||||
|
@ -6875,6 +6877,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
blockstore
|
blockstore
|
||||||
|
@ -6892,6 +6895,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
blockstore
|
blockstore
|
||||||
|
@ -6911,6 +6915,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -7023,6 +7028,10 @@ pub mod tests {
|
||||||
writable: vec![Pubkey::new_unique()],
|
writable: vec![Pubkey::new_unique()],
|
||||||
readonly: vec![Pubkey::new_unique()],
|
readonly: vec![Pubkey::new_unique()],
|
||||||
};
|
};
|
||||||
|
let test_return_data = TransactionReturnData {
|
||||||
|
program_id: Pubkey::new_unique(),
|
||||||
|
data: vec![1, 2, 3],
|
||||||
|
};
|
||||||
|
|
||||||
// result not found
|
// result not found
|
||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
|
@ -7042,6 +7051,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(post_token_balances_vec.clone()),
|
post_token_balances: Some(post_token_balances_vec.clone()),
|
||||||
rewards: Some(rewards_vec.clone()),
|
rewards: Some(rewards_vec.clone()),
|
||||||
loaded_addresses: test_loaded_addresses.clone(),
|
loaded_addresses: test_loaded_addresses.clone(),
|
||||||
|
return_data: Some(test_return_data.clone()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
|
@ -7060,6 +7070,7 @@ pub mod tests {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses,
|
loaded_addresses,
|
||||||
|
return_data,
|
||||||
} = transaction_status_cf
|
} = transaction_status_cf
|
||||||
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((0, Signature::default(), 0))
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((0, Signature::default(), 0))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -7076,6 +7087,7 @@ pub mod tests {
|
||||||
assert_eq!(post_token_balances.unwrap(), post_token_balances_vec);
|
assert_eq!(post_token_balances.unwrap(), post_token_balances_vec);
|
||||||
assert_eq!(rewards.unwrap(), rewards_vec);
|
assert_eq!(rewards.unwrap(), rewards_vec);
|
||||||
assert_eq!(loaded_addresses, test_loaded_addresses);
|
assert_eq!(loaded_addresses, test_loaded_addresses);
|
||||||
|
assert_eq!(return_data.unwrap(), test_return_data);
|
||||||
|
|
||||||
// insert value
|
// insert value
|
||||||
let status = TransactionStatusMeta {
|
let status = TransactionStatusMeta {
|
||||||
|
@ -7089,6 +7101,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(post_token_balances_vec.clone()),
|
post_token_balances: Some(post_token_balances_vec.clone()),
|
||||||
rewards: Some(rewards_vec.clone()),
|
rewards: Some(rewards_vec.clone()),
|
||||||
loaded_addresses: test_loaded_addresses.clone(),
|
loaded_addresses: test_loaded_addresses.clone(),
|
||||||
|
return_data: Some(test_return_data.clone()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
|
@ -7107,6 +7120,7 @@ pub mod tests {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses,
|
loaded_addresses,
|
||||||
|
return_data,
|
||||||
} = transaction_status_cf
|
} = transaction_status_cf
|
||||||
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
|
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
|
||||||
0,
|
0,
|
||||||
|
@ -7129,6 +7143,7 @@ pub mod tests {
|
||||||
assert_eq!(post_token_balances.unwrap(), post_token_balances_vec);
|
assert_eq!(post_token_balances.unwrap(), post_token_balances_vec);
|
||||||
assert_eq!(rewards.unwrap(), rewards_vec);
|
assert_eq!(rewards.unwrap(), rewards_vec);
|
||||||
assert_eq!(loaded_addresses, test_loaded_addresses);
|
assert_eq!(loaded_addresses, test_loaded_addresses);
|
||||||
|
assert_eq!(return_data.unwrap(), test_return_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -7357,6 +7372,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
@ -7552,6 +7568,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
@ -7723,6 +7740,10 @@ pub mod tests {
|
||||||
let post_token_balances = Some(vec![]);
|
let post_token_balances = Some(vec![]);
|
||||||
let rewards = Some(vec![]);
|
let rewards = Some(vec![]);
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
|
let return_data = Some(TransactionReturnData {
|
||||||
|
program_id: Pubkey::new_unique(),
|
||||||
|
data: vec![1, 2, 3],
|
||||||
|
});
|
||||||
let status = TransactionStatusMeta {
|
let status = TransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
|
@ -7734,6 +7755,7 @@ pub mod tests {
|
||||||
post_token_balances: post_token_balances.clone(),
|
post_token_balances: post_token_balances.clone(),
|
||||||
rewards: rewards.clone(),
|
rewards: rewards.clone(),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: return_data.clone(),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
blockstore
|
blockstore
|
||||||
|
@ -7753,6 +7775,7 @@ pub mod tests {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -7824,6 +7847,10 @@ pub mod tests {
|
||||||
let pre_token_balances = Some(vec![]);
|
let pre_token_balances = Some(vec![]);
|
||||||
let post_token_balances = Some(vec![]);
|
let post_token_balances = Some(vec![]);
|
||||||
let rewards = Some(vec![]);
|
let rewards = Some(vec![]);
|
||||||
|
let return_data = Some(TransactionReturnData {
|
||||||
|
program_id: Pubkey::new_unique(),
|
||||||
|
data: vec![1, 2, 3],
|
||||||
|
});
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
let status = TransactionStatusMeta {
|
let status = TransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
|
@ -7836,6 +7863,7 @@ pub mod tests {
|
||||||
post_token_balances: post_token_balances.clone(),
|
post_token_balances: post_token_balances.clone(),
|
||||||
rewards: rewards.clone(),
|
rewards: rewards.clone(),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: return_data.clone(),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
blockstore
|
blockstore
|
||||||
|
@ -7855,6 +7883,7 @@ pub mod tests {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -8614,6 +8643,7 @@ pub mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
|
@ -9171,6 +9201,10 @@ pub mod tests {
|
||||||
commission: None,
|
commission: None,
|
||||||
}]),
|
}]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData {
|
||||||
|
program_id: Pubkey::new_unique(),
|
||||||
|
data: vec![1, 2, 3],
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
let deprecated_status: StoredTransactionStatusMeta = status.clone().try_into().unwrap();
|
let deprecated_status: StoredTransactionStatusMeta = status.clone().try_into().unwrap();
|
||||||
let protobuf_status: generated::TransactionStatusMeta = status.into();
|
let protobuf_status: generated::TransactionStatusMeta = status.into();
|
||||||
|
|
|
@ -181,6 +181,7 @@ fn execute_batch(
|
||||||
transaction_status_sender.is_some(),
|
transaction_status_sender.is_some(),
|
||||||
transaction_status_sender.is_some(),
|
transaction_status_sender.is_some(),
|
||||||
transaction_status_sender.is_some(),
|
transaction_status_sender.is_some(),
|
||||||
|
transaction_status_sender.is_some(),
|
||||||
timings,
|
timings,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3510,6 +3511,7 @@ pub mod tests {
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
&mut ExecuteTimings::default(),
|
&mut ExecuteTimings::default(),
|
||||||
);
|
);
|
||||||
let (err, signature) = get_first_error(&batch, fee_collection_results).unwrap();
|
let (err, signature) = get_first_error(&batch, fee_collection_results).unwrap();
|
||||||
|
|
|
@ -55,6 +55,9 @@ while [[ -n $1 ]]; do
|
||||||
elif [[ $1 = --enable-cpi-and-log-storage ]]; then
|
elif [[ $1 = --enable-cpi-and-log-storage ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
|
elif [[ $1 = --enable-extended-tx-metadata-storage ]]; then
|
||||||
|
args+=("$1")
|
||||||
|
shift
|
||||||
elif [[ $1 = --enable-rpc-bigtable-ledger-storage ]]; then
|
elif [[ $1 = --enable-rpc-bigtable-ledger-storage ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
|
|
|
@ -141,6 +141,9 @@ while [[ -n $1 ]]; do
|
||||||
elif [[ $1 = --enable-cpi-and-log-storage ]]; then
|
elif [[ $1 = --enable-cpi-and-log-storage ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
|
elif [[ $1 = --enable-extended-tx-metadata-storage ]]; then
|
||||||
|
args+=("$1")
|
||||||
|
shift
|
||||||
elif [[ $1 = --skip-poh-verify ]]; then
|
elif [[ $1 = --skip-poh-verify ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
|
|
|
@ -280,7 +280,7 @@ EOF
|
||||||
|
|
||||||
if $maybeFullRpc; then
|
if $maybeFullRpc; then
|
||||||
args+=(--enable-rpc-transaction-history)
|
args+=(--enable-rpc-transaction-history)
|
||||||
args+=(--enable-cpi-and-log-storage)
|
args+=(--enable-extended-tx-metadata-storage)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $airdropsEnabled = true ]]; then
|
if [[ $airdropsEnabled = true ]]; then
|
||||||
|
@ -408,7 +408,7 @@ EOF
|
||||||
|
|
||||||
if $maybeFullRpc; then
|
if $maybeFullRpc; then
|
||||||
args+=(--enable-rpc-transaction-history)
|
args+=(--enable-rpc-transaction-history)
|
||||||
args+=(--enable-cpi-and-log-storage)
|
args+=(--enable-extended-tx-metadata-storage)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat >> ~/solana/on-reboot <<EOF
|
cat >> ~/solana/on-reboot <<EOF
|
||||||
|
|
|
@ -8,6 +8,7 @@ repository = "https://github.com/solana-labs/solana"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
assert_matches = "1.5.0"
|
||||||
async-trait = "0.1.52"
|
async-trait = "0.1.52"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
use {
|
use {
|
||||||
|
assert_matches::assert_matches,
|
||||||
|
solana_banks_client::BanksClientError,
|
||||||
solana_program_test::{processor, ProgramTest},
|
solana_program_test::{processor, ProgramTest},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account_info::{next_account_info, AccountInfo},
|
account_info::{next_account_info, AccountInfo},
|
||||||
|
commitment_config::CommitmentLevel,
|
||||||
entrypoint::ProgramResult,
|
entrypoint::ProgramResult,
|
||||||
instruction::{AccountMeta, Instruction},
|
instruction::{AccountMeta, Instruction},
|
||||||
msg,
|
msg,
|
||||||
program::{get_return_data, invoke, set_return_data},
|
program::{get_return_data, invoke, set_return_data},
|
||||||
|
program_error::ProgramError,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signer,
|
signature::Signer,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
std::str::from_utf8,
|
std::str::from_utf8,
|
||||||
};
|
};
|
||||||
|
@ -85,3 +90,55 @@ async fn return_data() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process instruction to echo input back to another program
|
||||||
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
|
fn error_set_return_data_process_instruction(
|
||||||
|
_program_id: &Pubkey,
|
||||||
|
_accounts: &[AccountInfo],
|
||||||
|
input: &[u8],
|
||||||
|
) -> ProgramResult {
|
||||||
|
set_return_data(input);
|
||||||
|
Err(ProgramError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn simulation_return_data() {
|
||||||
|
let error_set_return_data_program_id = Pubkey::new_unique();
|
||||||
|
let program_test = ProgramTest::new(
|
||||||
|
"error_set_return_data",
|
||||||
|
error_set_return_data_program_id,
|
||||||
|
processor!(error_set_return_data_process_instruction),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut context = program_test.start_with_context().await;
|
||||||
|
let expected_data = vec![240, 159, 166, 150];
|
||||||
|
let instructions = vec![Instruction {
|
||||||
|
program_id: error_set_return_data_program_id,
|
||||||
|
accounts: vec![],
|
||||||
|
data: expected_data.clone(),
|
||||||
|
}];
|
||||||
|
|
||||||
|
let transaction = Transaction::new_signed_with_payer(
|
||||||
|
&instructions,
|
||||||
|
Some(&context.payer.pubkey()),
|
||||||
|
&[&context.payer],
|
||||||
|
context.last_blockhash,
|
||||||
|
);
|
||||||
|
|
||||||
|
let error = context
|
||||||
|
.banks_client
|
||||||
|
.process_transaction_with_preflight_and_commitment(transaction, CommitmentLevel::Confirmed)
|
||||||
|
.await
|
||||||
|
.unwrap_err();
|
||||||
|
assert_matches!(
|
||||||
|
error,
|
||||||
|
BanksClientError::SimulationError {
|
||||||
|
return_data: Some(TransactionReturnData {
|
||||||
|
program_id,
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
..
|
||||||
|
} if program_id == error_set_return_data_program_id && data == expected_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1862,6 +1862,12 @@ version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty-hex"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -3075,6 +3081,7 @@ dependencies = [
|
||||||
"console",
|
"console",
|
||||||
"humantime",
|
"humantime",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
|
"pretty-hex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-account-decoder",
|
"solana-account-decoder",
|
||||||
|
@ -3419,6 +3426,7 @@ dependencies = [
|
||||||
name = "solana-program-test"
|
name = "solana-program-test"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"assert_matches",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.13.0",
|
"base64 0.13.0",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
|
|
@ -323,6 +323,7 @@ fn process_transaction_and_record_inner(
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
&mut ExecuteTimings::default(),
|
&mut ExecuteTimings::default(),
|
||||||
)
|
)
|
||||||
.0;
|
.0;
|
||||||
|
@ -364,6 +365,7 @@ fn execute_transactions(
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
&mut timings,
|
&mut timings,
|
||||||
);
|
);
|
||||||
let tx_post_token_balances = collect_token_balances(&bank, &batch, &mut mint_decimals);
|
let tx_post_token_balances = collect_token_balances(&bank, &batch, &mut mint_decimals);
|
||||||
|
@ -392,6 +394,7 @@ fn execute_transactions(
|
||||||
log_messages,
|
log_messages,
|
||||||
inner_instructions,
|
inner_instructions,
|
||||||
durable_nonce_fee,
|
durable_nonce_fee,
|
||||||
|
return_data,
|
||||||
} = details;
|
} = details;
|
||||||
|
|
||||||
let lamports_per_signature = match durable_nonce_fee {
|
let lamports_per_signature = match durable_nonce_fee {
|
||||||
|
@ -432,6 +435,7 @@ fn execute_transactions(
|
||||||
log_messages,
|
log_messages,
|
||||||
rewards: None,
|
rewards: None,
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ConfirmedTransactionWithStatusMeta {
|
Ok(ConfirmedTransactionWithStatusMeta {
|
||||||
|
|
|
@ -143,7 +143,7 @@ fn is_finalized(
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct JsonRpcConfig {
|
pub struct JsonRpcConfig {
|
||||||
pub enable_rpc_transaction_history: bool,
|
pub enable_rpc_transaction_history: bool,
|
||||||
pub enable_cpi_and_log_storage: bool,
|
pub enable_extended_tx_metadata_storage: bool,
|
||||||
pub faucet_addr: Option<SocketAddr>,
|
pub faucet_addr: Option<SocketAddr>,
|
||||||
pub health_check_slot_distance: u64,
|
pub health_check_slot_distance: u64,
|
||||||
pub rpc_bigtable_config: Option<RpcBigtableConfig>,
|
pub rpc_bigtable_config: Option<RpcBigtableConfig>,
|
||||||
|
@ -3551,6 +3551,7 @@ pub mod rpc_full {
|
||||||
logs,
|
logs,
|
||||||
post_simulation_accounts: _,
|
post_simulation_accounts: _,
|
||||||
units_consumed,
|
units_consumed,
|
||||||
|
return_data,
|
||||||
} = preflight_bank.simulate_transaction(transaction)
|
} = preflight_bank.simulate_transaction(transaction)
|
||||||
{
|
{
|
||||||
match err {
|
match err {
|
||||||
|
@ -3568,6 +3569,7 @@ pub mod rpc_full {
|
||||||
logs: Some(logs),
|
logs: Some(logs),
|
||||||
accounts: None,
|
accounts: None,
|
||||||
units_consumed: Some(units_consumed),
|
units_consumed: Some(units_consumed),
|
||||||
|
return_data,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
|
@ -3625,6 +3627,7 @@ pub mod rpc_full {
|
||||||
logs,
|
logs,
|
||||||
post_simulation_accounts,
|
post_simulation_accounts,
|
||||||
units_consumed,
|
units_consumed,
|
||||||
|
return_data,
|
||||||
} = bank.simulate_transaction(transaction);
|
} = bank.simulate_transaction(transaction);
|
||||||
|
|
||||||
let accounts = if let Some(config_accounts) = config.accounts {
|
let accounts = if let Some(config_accounts) = config.accounts {
|
||||||
|
@ -3676,6 +3679,7 @@ pub mod rpc_full {
|
||||||
logs: Some(logs),
|
logs: Some(logs),
|
||||||
accounts,
|
accounts,
|
||||||
units_consumed: Some(units_consumed),
|
units_consumed: Some(units_consumed),
|
||||||
|
return_data,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -5574,6 +5578,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 invoke [1]",
|
"Program 11111111111111111111111111111111 invoke [1]",
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5660,6 +5665,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 invoke [1]",
|
"Program 11111111111111111111111111111111 invoke [1]",
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5688,6 +5694,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 invoke [1]",
|
"Program 11111111111111111111111111111111 invoke [1]",
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5737,6 +5744,7 @@ pub mod tests {
|
||||||
"err":"BlockhashNotFound",
|
"err":"BlockhashNotFound",
|
||||||
"accounts":null,
|
"accounts":null,
|
||||||
"logs":[],
|
"logs":[],
|
||||||
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5766,6 +5774,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 invoke [1]",
|
"Program 11111111111111111111111111111111 invoke [1]",
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6123,7 +6132,7 @@ pub mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
res,
|
res,
|
||||||
Some(
|
Some(
|
||||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","logs":[],"unitsConsumed":0}},"id":1}"#.to_string(),
|
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","logs":[],"returnData":null,"unitsConsumed":0}},"id":1}"#.to_string(),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl TransactionStatusService {
|
||||||
enable_rpc_transaction_history: bool,
|
enable_rpc_transaction_history: bool,
|
||||||
transaction_notifier: Option<TransactionNotifierLock>,
|
transaction_notifier: Option<TransactionNotifierLock>,
|
||||||
blockstore: Arc<Blockstore>,
|
blockstore: Arc<Blockstore>,
|
||||||
enable_cpi_and_log_storage: bool,
|
enable_extended_tx_metadata_storage: bool,
|
||||||
exit: &Arc<AtomicBool>,
|
exit: &Arc<AtomicBool>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let exit = exit.clone();
|
let exit = exit.clone();
|
||||||
|
@ -51,7 +51,7 @@ impl TransactionStatusService {
|
||||||
enable_rpc_transaction_history,
|
enable_rpc_transaction_history,
|
||||||
transaction_notifier.clone(),
|
transaction_notifier.clone(),
|
||||||
&blockstore,
|
&blockstore,
|
||||||
enable_cpi_and_log_storage,
|
enable_extended_tx_metadata_storage,
|
||||||
) {
|
) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ impl TransactionStatusService {
|
||||||
enable_rpc_transaction_history: bool,
|
enable_rpc_transaction_history: bool,
|
||||||
transaction_notifier: Option<TransactionNotifierLock>,
|
transaction_notifier: Option<TransactionNotifierLock>,
|
||||||
blockstore: &Arc<Blockstore>,
|
blockstore: &Arc<Blockstore>,
|
||||||
enable_cpi_and_log_storage: bool,
|
enable_extended_tx_metadata_storage: bool,
|
||||||
) -> Result<(), RecvTimeoutError> {
|
) -> Result<(), RecvTimeoutError> {
|
||||||
match write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))? {
|
match write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))? {
|
||||||
TransactionStatusMessage::Batch(TransactionStatusBatch {
|
TransactionStatusMessage::Batch(TransactionStatusBatch {
|
||||||
|
@ -101,6 +101,7 @@ impl TransactionStatusService {
|
||||||
log_messages,
|
log_messages,
|
||||||
inner_instructions,
|
inner_instructions,
|
||||||
durable_nonce_fee,
|
durable_nonce_fee,
|
||||||
|
return_data,
|
||||||
} = details;
|
} = details;
|
||||||
let lamports_per_signature = match durable_nonce_fee {
|
let lamports_per_signature = match durable_nonce_fee {
|
||||||
Some(DurableNonceFee::Valid(lamports_per_signature)) => {
|
Some(DurableNonceFee::Valid(lamports_per_signature)) => {
|
||||||
|
@ -156,6 +157,7 @@ impl TransactionStatusService {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses,
|
loaded_addresses,
|
||||||
|
return_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(transaction_notifier) = transaction_notifier.as_ref() {
|
if let Some(transaction_notifier) = transaction_notifier.as_ref() {
|
||||||
|
@ -167,9 +169,11 @@ impl TransactionStatusService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(enable_cpi_and_log_storage || transaction_notifier.is_some()) {
|
if !(enable_extended_tx_metadata_storage || transaction_notifier.is_some())
|
||||||
|
{
|
||||||
transaction_status_meta.log_messages.take();
|
transaction_status_meta.log_messages.take();
|
||||||
transaction_status_meta.inner_instructions.take();
|
transaction_status_meta.inner_instructions.take();
|
||||||
|
transaction_status_meta.return_data.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
if enable_rpc_transaction_history {
|
if enable_rpc_transaction_history {
|
||||||
|
@ -347,6 +351,7 @@ pub(crate) mod tests {
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)),
|
)),
|
||||||
|
return_data: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let balances = TransactionBalancesSet {
|
let balances = TransactionBalancesSet {
|
||||||
|
|
|
@ -1374,6 +1374,7 @@ mod tests {
|
||||||
log_messages: None,
|
log_messages: None,
|
||||||
inner_instructions: None,
|
inner_instructions: None,
|
||||||
durable_nonce_fee: nonce.map(DurableNonceFee::from),
|
durable_nonce_fee: nonce.map(DurableNonceFee::from),
|
||||||
|
return_data: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,10 @@ use {
|
||||||
MessageHash, Result, SanitizedTransaction, Transaction, TransactionError,
|
MessageHash, Result, SanitizedTransaction, Transaction, TransactionError,
|
||||||
TransactionVerificationMode, VersionedTransaction,
|
TransactionVerificationMode, VersionedTransaction,
|
||||||
},
|
},
|
||||||
transaction_context::{InstructionTrace, TransactionAccount, TransactionContext},
|
transaction_context::{
|
||||||
|
ExecutionRecord, InstructionTrace, TransactionAccount, TransactionContext,
|
||||||
|
TransactionReturnData,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
solana_stake_program::stake_state::{
|
solana_stake_program::stake_state::{
|
||||||
self, InflationPointCalculationEvent, PointValue, StakeState,
|
self, InflationPointCalculationEvent, PointValue, StakeState,
|
||||||
|
@ -579,6 +582,7 @@ pub struct TransactionExecutionDetails {
|
||||||
pub log_messages: Option<Vec<String>>,
|
pub log_messages: Option<Vec<String>>,
|
||||||
pub inner_instructions: Option<InnerInstructionsList>,
|
pub inner_instructions: Option<InnerInstructionsList>,
|
||||||
pub durable_nonce_fee: Option<DurableNonceFee>,
|
pub durable_nonce_fee: Option<DurableNonceFee>,
|
||||||
|
pub return_data: Option<TransactionReturnData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type safe representation of a transaction execution attempt which
|
/// Type safe representation of a transaction execution attempt which
|
||||||
|
@ -670,6 +674,7 @@ pub struct TransactionSimulationResult {
|
||||||
pub logs: TransactionLogMessages,
|
pub logs: TransactionLogMessages,
|
||||||
pub post_simulation_accounts: Vec<TransactionAccount>,
|
pub post_simulation_accounts: Vec<TransactionAccount>,
|
||||||
pub units_consumed: u64,
|
pub units_consumed: u64,
|
||||||
|
pub return_data: Option<TransactionReturnData>,
|
||||||
}
|
}
|
||||||
pub struct TransactionBalancesSet {
|
pub struct TransactionBalancesSet {
|
||||||
pub pre_balances: TransactionBalances,
|
pub pre_balances: TransactionBalances,
|
||||||
|
@ -3541,6 +3546,7 @@ impl Bank {
|
||||||
MAX_PROCESSING_AGE - MAX_TRANSACTION_FORWARDING_DELAY,
|
MAX_PROCESSING_AGE - MAX_TRANSACTION_FORWARDING_DELAY,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
&mut timings,
|
&mut timings,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3571,17 +3577,20 @@ impl Bank {
|
||||||
|
|
||||||
let execution_result = execution_results.pop().unwrap();
|
let execution_result = execution_results.pop().unwrap();
|
||||||
let flattened_result = execution_result.flattened_result();
|
let flattened_result = execution_result.flattened_result();
|
||||||
let logs = match execution_result {
|
let (logs, return_data) = match execution_result {
|
||||||
TransactionExecutionResult::Executed(details) => details.log_messages,
|
TransactionExecutionResult::Executed(details) => {
|
||||||
TransactionExecutionResult::NotExecuted(_) => None,
|
(details.log_messages, details.return_data)
|
||||||
}
|
}
|
||||||
.unwrap_or_default();
|
TransactionExecutionResult::NotExecuted(_) => (None, None),
|
||||||
|
};
|
||||||
|
let logs = logs.unwrap_or_default();
|
||||||
|
|
||||||
TransactionSimulationResult {
|
TransactionSimulationResult {
|
||||||
result: flattened_result,
|
result: flattened_result,
|
||||||
logs,
|
logs,
|
||||||
post_simulation_accounts,
|
post_simulation_accounts,
|
||||||
units_consumed,
|
units_consumed,
|
||||||
|
return_data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3858,6 +3867,7 @@ impl Bank {
|
||||||
|
|
||||||
/// Execute a transaction using the provided loaded accounts and update
|
/// Execute a transaction using the provided loaded accounts and update
|
||||||
/// the executors cache if the transaction was successful.
|
/// the executors cache if the transaction was successful.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn execute_loaded_transaction(
|
fn execute_loaded_transaction(
|
||||||
&self,
|
&self,
|
||||||
tx: &SanitizedTransaction,
|
tx: &SanitizedTransaction,
|
||||||
|
@ -3866,6 +3876,7 @@ impl Bank {
|
||||||
durable_nonce_fee: Option<DurableNonceFee>,
|
durable_nonce_fee: Option<DurableNonceFee>,
|
||||||
enable_cpi_recording: bool,
|
enable_cpi_recording: bool,
|
||||||
enable_log_recording: bool,
|
enable_log_recording: bool,
|
||||||
|
enable_return_data_recording: bool,
|
||||||
timings: &mut ExecuteTimings,
|
timings: &mut ExecuteTimings,
|
||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
) -> TransactionExecutionResult {
|
) -> TransactionExecutionResult {
|
||||||
|
@ -3960,7 +3971,11 @@ impl Bank {
|
||||||
.ok()
|
.ok()
|
||||||
});
|
});
|
||||||
|
|
||||||
let (accounts, instruction_trace) = transaction_context.deconstruct();
|
let ExecutionRecord {
|
||||||
|
accounts,
|
||||||
|
instruction_trace,
|
||||||
|
mut return_data,
|
||||||
|
} = transaction_context.into();
|
||||||
loaded_transaction.accounts = accounts;
|
loaded_transaction.accounts = accounts;
|
||||||
|
|
||||||
let inner_instructions = if enable_cpi_recording {
|
let inner_instructions = if enable_cpi_recording {
|
||||||
|
@ -3971,11 +3986,25 @@ impl Bank {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let return_data = if enable_return_data_recording {
|
||||||
|
if let Some(end_index) = return_data.data.iter().rposition(|&x| x != 0) {
|
||||||
|
let end_index = end_index.saturating_add(1);
|
||||||
|
error!("end index {}", end_index);
|
||||||
|
return_data.data.truncate(end_index);
|
||||||
|
Some(return_data)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
TransactionExecutionResult::Executed(TransactionExecutionDetails {
|
TransactionExecutionResult::Executed(TransactionExecutionDetails {
|
||||||
status,
|
status,
|
||||||
log_messages,
|
log_messages,
|
||||||
inner_instructions,
|
inner_instructions,
|
||||||
durable_nonce_fee,
|
durable_nonce_fee,
|
||||||
|
return_data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3986,6 +4015,7 @@ impl Bank {
|
||||||
max_age: usize,
|
max_age: usize,
|
||||||
enable_cpi_recording: bool,
|
enable_cpi_recording: bool,
|
||||||
enable_log_recording: bool,
|
enable_log_recording: bool,
|
||||||
|
enable_return_data_recording: bool,
|
||||||
timings: &mut ExecuteTimings,
|
timings: &mut ExecuteTimings,
|
||||||
) -> LoadAndExecuteTransactionsOutput {
|
) -> LoadAndExecuteTransactionsOutput {
|
||||||
let sanitized_txs = batch.sanitized_transactions();
|
let sanitized_txs = batch.sanitized_transactions();
|
||||||
|
@ -4089,6 +4119,7 @@ impl Bank {
|
||||||
durable_nonce_fee,
|
durable_nonce_fee,
|
||||||
enable_cpi_recording,
|
enable_cpi_recording,
|
||||||
enable_log_recording,
|
enable_log_recording,
|
||||||
|
enable_return_data_recording,
|
||||||
timings,
|
timings,
|
||||||
&mut error_counters,
|
&mut error_counters,
|
||||||
)
|
)
|
||||||
|
@ -5240,6 +5271,7 @@ impl Bank {
|
||||||
collect_balances: bool,
|
collect_balances: bool,
|
||||||
enable_cpi_recording: bool,
|
enable_cpi_recording: bool,
|
||||||
enable_log_recording: bool,
|
enable_log_recording: bool,
|
||||||
|
enable_return_data_recording: bool,
|
||||||
timings: &mut ExecuteTimings,
|
timings: &mut ExecuteTimings,
|
||||||
) -> (TransactionResults, TransactionBalancesSet) {
|
) -> (TransactionResults, TransactionBalancesSet) {
|
||||||
let pre_balances = if collect_balances {
|
let pre_balances = if collect_balances {
|
||||||
|
@ -5260,6 +5292,7 @@ impl Bank {
|
||||||
max_age,
|
max_age,
|
||||||
enable_cpi_recording,
|
enable_cpi_recording,
|
||||||
enable_log_recording,
|
enable_log_recording,
|
||||||
|
enable_return_data_recording,
|
||||||
timings,
|
timings,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -5346,6 +5379,7 @@ impl Bank {
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
&mut ExecuteTimings::default(),
|
&mut ExecuteTimings::default(),
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
|
@ -6774,6 +6808,7 @@ pub(crate) mod tests {
|
||||||
message::{Message, MessageHeader},
|
message::{Message, MessageHeader},
|
||||||
nonce,
|
nonce,
|
||||||
poh_config::PohConfig,
|
poh_config::PohConfig,
|
||||||
|
program::MAX_RETURN_DATA,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
signature::{keypair_from_seed, Keypair, Signer},
|
signature::{keypair_from_seed, Keypair, Signer},
|
||||||
stake::{
|
stake::{
|
||||||
|
@ -6813,6 +6848,7 @@ pub(crate) mod tests {
|
||||||
log_messages: None,
|
log_messages: None,
|
||||||
inner_instructions: None,
|
inner_instructions: None,
|
||||||
durable_nonce_fee: nonce.map(DurableNonceFee::from),
|
durable_nonce_fee: nonce.map(DurableNonceFee::from),
|
||||||
|
return_data: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9949,6 +9985,7 @@ pub(crate) mod tests {
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
&mut ExecuteTimings::default(),
|
&mut ExecuteTimings::default(),
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
|
@ -12482,6 +12519,7 @@ pub(crate) mod tests {
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
&mut ExecuteTimings::default(),
|
&mut ExecuteTimings::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -15407,6 +15445,7 @@ pub(crate) mod tests {
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
&mut ExecuteTimings::default(),
|
&mut ExecuteTimings::default(),
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
|
@ -15449,6 +15488,91 @@ pub(crate) mod tests {
|
||||||
assert!(failure_log.contains(&"failed".to_string()));
|
assert!(failure_log.contains(&"failed".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tx_return_data() {
|
||||||
|
solana_logger::setup();
|
||||||
|
let GenesisConfigInfo {
|
||||||
|
genesis_config,
|
||||||
|
mint_keypair,
|
||||||
|
..
|
||||||
|
} = create_genesis_config_with_leader(
|
||||||
|
1_000_000_000_000_000,
|
||||||
|
&Pubkey::new_unique(),
|
||||||
|
bootstrap_validator_stake_lamports(),
|
||||||
|
);
|
||||||
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
|
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
||||||
|
fn mock_process_instruction(
|
||||||
|
_first_instruction_account: usize,
|
||||||
|
data: &[u8],
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> result::Result<(), InstructionError> {
|
||||||
|
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
||||||
|
let transaction_context = &mut invoke_context.transaction_context;
|
||||||
|
let mut return_data = [0u8; MAX_RETURN_DATA];
|
||||||
|
if !data.is_empty() {
|
||||||
|
let index = usize::from_le_bytes(data.try_into().unwrap());
|
||||||
|
return_data[index] = 1;
|
||||||
|
transaction_context
|
||||||
|
.set_return_data(mock_program_id, return_data.to_vec())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
let blockhash = bank.last_blockhash();
|
||||||
|
bank.add_builtin("mock_program", &mock_program_id, mock_process_instruction);
|
||||||
|
|
||||||
|
for index in [
|
||||||
|
None,
|
||||||
|
Some(0),
|
||||||
|
Some(MAX_RETURN_DATA / 2),
|
||||||
|
Some(MAX_RETURN_DATA - 1),
|
||||||
|
] {
|
||||||
|
let data = if let Some(index) = index {
|
||||||
|
usize::to_le_bytes(index).to_vec()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
let txs = vec![Transaction::new_signed_with_payer(
|
||||||
|
&[Instruction {
|
||||||
|
program_id: mock_program_id,
|
||||||
|
data,
|
||||||
|
accounts: vec![AccountMeta::new(Pubkey::new_unique(), false)],
|
||||||
|
}],
|
||||||
|
Some(&mint_keypair.pubkey()),
|
||||||
|
&[&mint_keypair],
|
||||||
|
blockhash,
|
||||||
|
)];
|
||||||
|
let batch = bank.prepare_batch_for_tests(txs);
|
||||||
|
let return_data = bank
|
||||||
|
.load_execute_and_commit_transactions(
|
||||||
|
&batch,
|
||||||
|
MAX_PROCESSING_AGE,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
&mut ExecuteTimings::default(),
|
||||||
|
)
|
||||||
|
.0
|
||||||
|
.execution_results[0]
|
||||||
|
.details()
|
||||||
|
.unwrap()
|
||||||
|
.return_data
|
||||||
|
.clone();
|
||||||
|
if let Some(index) = index {
|
||||||
|
let return_data = return_data.unwrap();
|
||||||
|
assert_eq!(return_data.program_id, mock_program_id);
|
||||||
|
let mut expected_data = vec![0u8; index];
|
||||||
|
expected_data.push(1u8);
|
||||||
|
assert_eq!(return_data.data, expected_data);
|
||||||
|
} else {
|
||||||
|
assert!(return_data.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_largest_accounts() {
|
fn test_get_largest_accounts() {
|
||||||
let GenesisConfigInfo { genesis_config, .. } =
|
let GenesisConfigInfo { genesis_config, .. } =
|
||||||
|
|
|
@ -108,7 +108,7 @@ args=(
|
||||||
--rpc-faucet-address 127.0.0.1:9900
|
--rpc-faucet-address 127.0.0.1:9900
|
||||||
--log -
|
--log -
|
||||||
--enable-rpc-transaction-history
|
--enable-rpc-transaction-history
|
||||||
--enable-cpi-and-log-storage
|
--enable-extended-tx-metadata-storage
|
||||||
--init-complete-file "$dataDir"/init-completed
|
--init-complete-file "$dataDir"/init-completed
|
||||||
--snapshot-compression none
|
--snapshot-compression none
|
||||||
--require-tower
|
--require-tower
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub struct TransactionContext {
|
||||||
instruction_stack: Vec<usize>,
|
instruction_stack: Vec<usize>,
|
||||||
number_of_instructions_at_transaction_level: usize,
|
number_of_instructions_at_transaction_level: usize,
|
||||||
instruction_trace: InstructionTrace,
|
instruction_trace: InstructionTrace,
|
||||||
return_data: (Pubkey, Vec<u8>),
|
return_data: TransactionReturnData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransactionContext {
|
impl TransactionContext {
|
||||||
|
@ -57,25 +57,10 @@ impl TransactionContext {
|
||||||
instruction_stack: Vec::with_capacity(instruction_context_capacity),
|
instruction_stack: Vec::with_capacity(instruction_context_capacity),
|
||||||
number_of_instructions_at_transaction_level,
|
number_of_instructions_at_transaction_level,
|
||||||
instruction_trace: Vec::with_capacity(number_of_instructions_at_transaction_level),
|
instruction_trace: Vec::with_capacity(number_of_instructions_at_transaction_level),
|
||||||
return_data: (Pubkey::default(), Vec::new()),
|
return_data: TransactionReturnData::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used by the bank in the runtime to write back the processed accounts and recorded instructions
|
|
||||||
pub fn deconstruct(self) -> (Vec<TransactionAccount>, Vec<Vec<InstructionContext>>) {
|
|
||||||
(
|
|
||||||
Vec::from(Pin::into_inner(self.account_keys))
|
|
||||||
.into_iter()
|
|
||||||
.zip(
|
|
||||||
Vec::from(Pin::into_inner(self.accounts))
|
|
||||||
.into_iter()
|
|
||||||
.map(|account| account.into_inner()),
|
|
||||||
)
|
|
||||||
.collect(),
|
|
||||||
self.instruction_trace,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used in mock_process_instruction
|
/// Used in mock_process_instruction
|
||||||
pub fn deconstruct_without_keys(self) -> Result<Vec<AccountSharedData>, InstructionError> {
|
pub fn deconstruct_without_keys(self) -> Result<Vec<AccountSharedData>, InstructionError> {
|
||||||
if !self.instruction_stack.is_empty() {
|
if !self.instruction_stack.is_empty() {
|
||||||
|
@ -225,7 +210,7 @@ impl TransactionContext {
|
||||||
|
|
||||||
/// Gets the return data of the current InstructionContext or any above
|
/// Gets the return data of the current InstructionContext or any above
|
||||||
pub fn get_return_data(&self) -> (&Pubkey, &[u8]) {
|
pub fn get_return_data(&self) -> (&Pubkey, &[u8]) {
|
||||||
(&self.return_data.0, &self.return_data.1)
|
(&self.return_data.program_id, &self.return_data.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the return data of the current InstructionContext
|
/// Set the return data of the current InstructionContext
|
||||||
|
@ -234,7 +219,7 @@ impl TransactionContext {
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
self.return_data = (program_id, data);
|
self.return_data = TransactionReturnData { program_id, data };
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +239,13 @@ impl TransactionContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return data at the end of a transaction
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||||
|
pub struct TransactionReturnData {
|
||||||
|
pub program_id: Pubkey,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
/// List of (stack height, instruction) for each top-level instruction
|
/// List of (stack height, instruction) for each top-level instruction
|
||||||
pub type InstructionTrace = Vec<Vec<InstructionContext>>;
|
pub type InstructionTrace = Vec<Vec<InstructionContext>>;
|
||||||
|
|
||||||
|
@ -628,3 +620,27 @@ impl<'a> BorrowedAccount<'a> {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Everything that needs to be recorded from a TransactionContext after execution
|
||||||
|
pub struct ExecutionRecord {
|
||||||
|
pub accounts: Vec<TransactionAccount>,
|
||||||
|
pub instruction_trace: InstructionTrace,
|
||||||
|
pub return_data: TransactionReturnData,
|
||||||
|
}
|
||||||
|
/// Used by the bank in the runtime to write back the processed accounts and recorded instructions
|
||||||
|
impl From<TransactionContext> for ExecutionRecord {
|
||||||
|
fn from(context: TransactionContext) -> Self {
|
||||||
|
Self {
|
||||||
|
accounts: Vec::from(Pin::into_inner(context.account_keys))
|
||||||
|
.into_iter()
|
||||||
|
.zip(
|
||||||
|
Vec::from(Pin::into_inner(context.accounts))
|
||||||
|
.into_iter()
|
||||||
|
.map(|account| account.into_inner()),
|
||||||
|
)
|
||||||
|
.collect(),
|
||||||
|
instruction_trace: context.instruction_trace,
|
||||||
|
return_data: context.return_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -792,7 +792,7 @@ mod tests {
|
||||||
prost::Message,
|
prost::Message,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
hash::Hash, message::v0::LoadedAddresses, signature::Keypair, system_transaction,
|
hash::Hash, message::v0::LoadedAddresses, signature::Keypair, system_transaction,
|
||||||
transaction::VersionedTransaction,
|
transaction::VersionedTransaction, transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
solana_storage_proto::convert::generated,
|
solana_storage_proto::convert::generated,
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
|
@ -842,6 +842,7 @@ mod tests {
|
||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: Some(TransactionReturnData::default()),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
let expected_block = ConfirmedBlock {
|
let expected_block = ConfirmedBlock {
|
||||||
|
@ -899,6 +900,7 @@ mod tests {
|
||||||
meta.pre_token_balances = None; // Legacy bincode implementation does not support token balances
|
meta.pre_token_balances = None; // Legacy bincode implementation does not support token balances
|
||||||
meta.post_token_balances = None; // Legacy bincode implementation does not support token balances
|
meta.post_token_balances = None; // Legacy bincode implementation does not support token balances
|
||||||
meta.rewards = None; // Legacy bincode implementation does not support rewards
|
meta.rewards = None; // Legacy bincode implementation does not support rewards
|
||||||
|
meta.return_data = None; // Legacy bincode implementation does not support return data
|
||||||
}
|
}
|
||||||
assert_eq!(block, bincode_block.into());
|
assert_eq!(block, bincode_block.into());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -237,6 +237,7 @@ impl From<StoredConfirmedBlockTransactionStatusMeta> for TransactionStatusMeta {
|
||||||
post_token_balances: None,
|
post_token_balances: None,
|
||||||
rewards: None,
|
rewards: None,
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ message TransactionStatusMeta {
|
||||||
repeated Reward rewards = 9;
|
repeated Reward rewards = 9;
|
||||||
repeated bytes loaded_writable_addresses = 12;
|
repeated bytes loaded_writable_addresses = 12;
|
||||||
repeated bytes loaded_readonly_addresses = 13;
|
repeated bytes loaded_readonly_addresses = 13;
|
||||||
|
ReturnData return_data = 14;
|
||||||
|
bool return_data_none = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionError {
|
message TransactionError {
|
||||||
|
@ -88,6 +90,11 @@ message UiTokenAmount {
|
||||||
string ui_amount_string = 4;
|
string ui_amount_string = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ReturnData {
|
||||||
|
bytes program_id = 1;
|
||||||
|
bytes data = 2;
|
||||||
|
}
|
||||||
|
|
||||||
enum RewardType {
|
enum RewardType {
|
||||||
Unspecified = 0;
|
Unspecified = 0;
|
||||||
Fee = 1;
|
Fee = 1;
|
||||||
|
|
|
@ -12,6 +12,7 @@ use {
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
transaction::{Transaction, TransactionError, VersionedTransaction},
|
transaction::{Transaction, TransactionError, VersionedTransaction},
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionByAddrInfo,
|
ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionByAddrInfo,
|
||||||
|
@ -363,6 +364,7 @@ impl From<TransactionStatusMeta> for generated::TransactionStatusMeta {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses,
|
loaded_addresses,
|
||||||
|
return_data,
|
||||||
} = value;
|
} = value;
|
||||||
let err = match status {
|
let err = match status {
|
||||||
Ok(()) => None,
|
Ok(()) => None,
|
||||||
|
@ -403,6 +405,8 @@ impl From<TransactionStatusMeta> for generated::TransactionStatusMeta {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|key| <Pubkey as AsRef<[u8]>>::as_ref(&key).into())
|
.map(|key| <Pubkey as AsRef<[u8]>>::as_ref(&key).into())
|
||||||
.collect();
|
.collect();
|
||||||
|
let return_data_none = return_data.is_none();
|
||||||
|
let return_data = return_data.map(|return_data| return_data.into());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
err,
|
err,
|
||||||
|
@ -418,6 +422,8 @@ impl From<TransactionStatusMeta> for generated::TransactionStatusMeta {
|
||||||
rewards,
|
rewards,
|
||||||
loaded_writable_addresses,
|
loaded_writable_addresses,
|
||||||
loaded_readonly_addresses,
|
loaded_readonly_addresses,
|
||||||
|
return_data,
|
||||||
|
return_data_none,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,6 +453,8 @@ impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
|
||||||
rewards,
|
rewards,
|
||||||
loaded_writable_addresses,
|
loaded_writable_addresses,
|
||||||
loaded_readonly_addresses,
|
loaded_readonly_addresses,
|
||||||
|
return_data,
|
||||||
|
return_data_none,
|
||||||
} = value;
|
} = value;
|
||||||
let status = match &err {
|
let status = match &err {
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
|
@ -490,6 +498,11 @@ impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
|
||||||
.map(|key| Pubkey::new(&key))
|
.map(|key| Pubkey::new(&key))
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
let return_data = if return_data_none {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
return_data.map(|return_data| return_data.into())
|
||||||
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
status,
|
status,
|
||||||
fee,
|
fee,
|
||||||
|
@ -501,6 +514,7 @@ impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses,
|
loaded_addresses,
|
||||||
|
return_data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -587,6 +601,24 @@ impl From<generated::MessageAddressTableLookup> for MessageAddressTableLookup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<TransactionReturnData> for generated::ReturnData {
|
||||||
|
fn from(value: TransactionReturnData) -> Self {
|
||||||
|
Self {
|
||||||
|
program_id: <Pubkey as AsRef<[u8]>>::as_ref(&value.program_id).into(),
|
||||||
|
data: value.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<generated::ReturnData> for TransactionReturnData {
|
||||||
|
fn from(value: generated::ReturnData) -> Self {
|
||||||
|
Self {
|
||||||
|
program_id: Pubkey::new(&value.program_id),
|
||||||
|
data: value.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<CompiledInstruction> for generated::CompiledInstruction {
|
impl From<CompiledInstruction> for generated::CompiledInstruction {
|
||||||
fn from(value: CompiledInstruction) -> Self {
|
fn from(value: CompiledInstruction) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use {
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
deserialize_utils::default_on_eof, message::v0::LoadedAddresses, transaction::Result,
|
deserialize_utils::default_on_eof, message::v0::LoadedAddresses, transaction::Result,
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
InnerInstructions, Reward, RewardType, TransactionStatusMeta, TransactionTokenBalance,
|
InnerInstructions, Reward, RewardType, TransactionStatusMeta, TransactionTokenBalance,
|
||||||
|
@ -167,6 +168,8 @@ pub struct StoredTransactionStatusMeta {
|
||||||
pub post_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
|
pub post_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
|
||||||
#[serde(deserialize_with = "default_on_eof")]
|
#[serde(deserialize_with = "default_on_eof")]
|
||||||
pub rewards: Option<Vec<StoredExtendedReward>>,
|
pub rewards: Option<Vec<StoredExtendedReward>>,
|
||||||
|
#[serde(deserialize_with = "default_on_eof")]
|
||||||
|
pub return_data: Option<TransactionReturnData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StoredTransactionStatusMeta> for TransactionStatusMeta {
|
impl From<StoredTransactionStatusMeta> for TransactionStatusMeta {
|
||||||
|
@ -181,6 +184,7 @@ impl From<StoredTransactionStatusMeta> for TransactionStatusMeta {
|
||||||
pre_token_balances,
|
pre_token_balances,
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
|
return_data,
|
||||||
} = value;
|
} = value;
|
||||||
Self {
|
Self {
|
||||||
status,
|
status,
|
||||||
|
@ -196,6 +200,7 @@ impl From<StoredTransactionStatusMeta> for TransactionStatusMeta {
|
||||||
rewards: rewards
|
rewards: rewards
|
||||||
.map(|rewards| rewards.into_iter().map(|reward| reward.into()).collect()),
|
.map(|rewards| rewards.into_iter().map(|reward| reward.into()).collect()),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,6 +219,7 @@ impl TryFrom<TransactionStatusMeta> for StoredTransactionStatusMeta {
|
||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses,
|
loaded_addresses,
|
||||||
|
return_data,
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
if !loaded_addresses.is_empty() {
|
if !loaded_addresses.is_empty() {
|
||||||
|
@ -237,6 +243,7 @@ impl TryFrom<TransactionStatusMeta> for StoredTransactionStatusMeta {
|
||||||
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
|
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
|
||||||
rewards: rewards
|
rewards: rewards
|
||||||
.map(|rewards| rewards.into_iter().map(|reward| reward.into()).collect()),
|
.map(|rewards| rewards.into_iter().map(|reward| reward.into()).collect()),
|
||||||
|
return_data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ use {
|
||||||
Result as TransactionResult, Transaction, TransactionError, TransactionVersion,
|
Result as TransactionResult, Transaction, TransactionError, TransactionVersion,
|
||||||
VersionedTransaction,
|
VersionedTransaction,
|
||||||
},
|
},
|
||||||
|
transaction_context::TransactionReturnData,
|
||||||
},
|
},
|
||||||
std::fmt,
|
std::fmt,
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
@ -279,6 +280,7 @@ pub struct TransactionStatusMeta {
|
||||||
pub post_token_balances: Option<Vec<TransactionTokenBalance>>,
|
pub post_token_balances: Option<Vec<TransactionTokenBalance>>,
|
||||||
pub rewards: Option<Rewards>,
|
pub rewards: Option<Rewards>,
|
||||||
pub loaded_addresses: LoadedAddresses,
|
pub loaded_addresses: LoadedAddresses,
|
||||||
|
pub return_data: Option<TransactionReturnData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TransactionStatusMeta {
|
impl Default for TransactionStatusMeta {
|
||||||
|
@ -294,6 +296,7 @@ impl Default for TransactionStatusMeta {
|
||||||
post_token_balances: None,
|
post_token_balances: None,
|
||||||
rewards: None,
|
rewards: None,
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
|
return_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,6 +317,7 @@ pub struct UiTransactionStatusMeta {
|
||||||
pub rewards: Option<Rewards>,
|
pub rewards: Option<Rewards>,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub loaded_addresses: Option<UiLoadedAddresses>,
|
pub loaded_addresses: Option<UiLoadedAddresses>,
|
||||||
|
pub return_data: Option<TransactionReturnData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A duplicate representation of LoadedAddresses
|
/// A duplicate representation of LoadedAddresses
|
||||||
|
@ -364,6 +368,7 @@ impl UiTransactionStatusMeta {
|
||||||
.map(|balance| balance.into_iter().map(Into::into).collect()),
|
.map(|balance| balance.into_iter().map(Into::into).collect()),
|
||||||
rewards: meta.rewards,
|
rewards: meta.rewards,
|
||||||
loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)),
|
loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)),
|
||||||
|
return_data: meta.return_data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,6 +393,7 @@ impl From<TransactionStatusMeta> for UiTransactionStatusMeta {
|
||||||
.map(|balance| balance.into_iter().map(Into::into).collect()),
|
.map(|balance| balance.into_iter().map(Into::into).collect()),
|
||||||
rewards: meta.rewards,
|
rewards: meta.rewards,
|
||||||
loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)),
|
loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)),
|
||||||
|
return_data: meta.return_data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -657,7 +657,7 @@ fn main() {
|
||||||
)
|
)
|
||||||
.rpc_config(JsonRpcConfig {
|
.rpc_config(JsonRpcConfig {
|
||||||
enable_rpc_transaction_history: true,
|
enable_rpc_transaction_history: true,
|
||||||
enable_cpi_and_log_storage: true,
|
enable_extended_tx_metadata_storage: true,
|
||||||
rpc_bigtable_config,
|
rpc_bigtable_config,
|
||||||
faucet_addr,
|
faucet_addr,
|
||||||
..JsonRpcConfig::default_for_test()
|
..JsonRpcConfig::default_for_test()
|
||||||
|
|
|
@ -656,8 +656,18 @@ pub fn main() {
|
||||||
.long("enable-cpi-and-log-storage")
|
.long("enable-cpi-and-log-storage")
|
||||||
.requires("enable_rpc_transaction_history")
|
.requires("enable_rpc_transaction_history")
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Include CPI inner instructions and logs in the \
|
.hidden(true)
|
||||||
historical transaction info stored"),
|
.help("Deprecated, please use \"enable-extended-tx-metadata-storage\". \
|
||||||
|
Include CPI inner instructions, logs and return data in \
|
||||||
|
the historical transaction info stored"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("enable_extended_tx_metadata_storage")
|
||||||
|
.long("enable-extended-tx-metadata-storage")
|
||||||
|
.requires("enable_rpc_transaction_history")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Include CPI inner instructions, logs, and return data in \
|
||||||
|
the historical transaction info stored"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("rpc_max_multiple_accounts")
|
Arg::with_name("rpc_max_multiple_accounts")
|
||||||
|
@ -2294,7 +2304,15 @@ pub fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches.is_present("minimal_rpc_api") {
|
if matches.is_present("minimal_rpc_api") {
|
||||||
warn!("--minimal-rpc-api is now the default behavior. This flag is deprecated and can be removed from the launch args")
|
warn!("--minimal-rpc-api is now the default behavior. This flag is deprecated and can be removed from the launch args");
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches.is_present("enable_cpi_and_log_storage") {
|
||||||
|
warn!(
|
||||||
|
"--enable-cpi-and-log-storage is deprecated. Please update the \
|
||||||
|
launch args to use --enable-extended-tx-metadata-storage and remove \
|
||||||
|
--enable-cpi-and-log-storage"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rpc_bigtable_config = if matches.is_present("enable_rpc_bigtable_ledger_storage")
|
let rpc_bigtable_config = if matches.is_present("enable_rpc_bigtable_ledger_storage")
|
||||||
|
@ -2325,7 +2343,8 @@ pub fn main() {
|
||||||
new_hard_forks: hardforks_of(&matches, "hard_forks"),
|
new_hard_forks: hardforks_of(&matches, "hard_forks"),
|
||||||
rpc_config: JsonRpcConfig {
|
rpc_config: JsonRpcConfig {
|
||||||
enable_rpc_transaction_history: matches.is_present("enable_rpc_transaction_history"),
|
enable_rpc_transaction_history: matches.is_present("enable_rpc_transaction_history"),
|
||||||
enable_cpi_and_log_storage: matches.is_present("enable_cpi_and_log_storage"),
|
enable_extended_tx_metadata_storage: matches.is_present("enable_cpi_and_log_storage")
|
||||||
|
|| matches.is_present("enable_extended_tx_metadata_storage"),
|
||||||
rpc_bigtable_config,
|
rpc_bigtable_config,
|
||||||
faucet_addr: matches.value_of("rpc_faucet_addr").map(|address| {
|
faucet_addr: matches.value_of("rpc_faucet_addr").map(|address| {
|
||||||
solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
|
solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
|
||||||
|
|
Loading…
Reference in New Issue