Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rpc-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ solana-pubkey = { workspace = true, features = ["rand"] }
solana-signer = { workspace = true }
solana-system-transaction = { workspace = true }
static_assertions = { workspace = true }
test-case = { workspace = true }
3 changes: 2 additions & 1 deletion rpc-client/src/nonblocking/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4671,7 +4671,8 @@ impl RpcClient {
&self,
message: &impl SerializableMessage,
) -> ClientResult<u64> {
let serialized_encoded = serialize_and_encode(message, UiTransactionEncoding::Base64)?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't new code does the same as the function serialize_and_encode but just in place? I wonder if we even need this function if it is a 2 lines of code.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly. serialize_and_encode does bincode::serialize(thing) whereas the change does thing.serialize(). I'm always happy inlining code, but that's a matter for a different PR.

let serialized = message.serialize();
let serialized_encoded = BASE64_STANDARD.encode(serialized);
let result = self
.send::<Response<Option<u64>>>(
RpcRequest::GetFeeForMessage,
Expand Down
101 changes: 98 additions & 3 deletions rpc-client/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,19 @@ impl RpcClientConfig {

/// Trait used to add support for versioned messages to RPC APIs while
/// retaining backwards compatibility
pub trait SerializableMessage: Serialize {}
impl SerializableMessage for LegacyMessage {}
impl SerializableMessage for v0::Message {}
pub trait SerializableMessage {
fn serialize(&self) -> Vec<u8>;
}
impl SerializableMessage for LegacyMessage {
fn serialize(&self) -> Vec<u8> {
self.serialize()
}
}
impl SerializableMessage for v0::Message {
fn serialize(&self) -> Vec<u8> {
self.serialize()
}
}

/// Trait used to add support for versioned transactions to RPC APIs while
/// retaining backwards compatibility
Expand Down Expand Up @@ -3797,19 +3807,23 @@ mod tests {
super::*,
crate::mock_sender::PUBKEY,
assert_matches::assert_matches,
base64::{prelude::BASE64_STANDARD, Engine},
crossbeam_channel::unbounded,
jsonrpc_core::{futures::prelude::*, Error, IoHandler, Params},
jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder},
serde_json::{json, Number},
solana_account_decoder::encode_ui_account,
solana_account_decoder_client_types::UiAccountEncoding,
solana_hash::Hash,
solana_instruction::error::InstructionError,
solana_keypair::Keypair,
solana_message::{compiled_instruction::CompiledInstruction, MessageHeader},
solana_rpc_client_api::client_error::ErrorKind,
solana_signer::Signer,
solana_system_transaction as system_transaction,
solana_transaction_error::TransactionError,
std::{io, thread},
test_case::test_case,
};

#[test]
Expand Down Expand Up @@ -4254,4 +4268,85 @@ mod tests {
assert_eq!(expected_result, result1);
}
}

#[test_case(LegacyMessage {
header: MessageHeader {
num_required_signatures: 1,
num_readonly_signed_accounts: 0,
num_readonly_unsigned_accounts: 1,
},
account_keys: vec![Pubkey::new_unique()],
recent_blockhash: Hash::new_unique(),
instructions: vec![CompiledInstruction {
program_id_index: 1,
accounts: vec![0],
data: vec![],
}],
}; "legacy message")]
#[test_case(v0::Message {
header: MessageHeader {
num_required_signatures: 1,
num_readonly_signed_accounts: 0,
num_readonly_unsigned_accounts: 0,
},
account_keys: vec![Pubkey::new_unique()],
recent_blockhash: Hash::new_unique(),
instructions: vec![CompiledInstruction {
program_id_index: 0,
accounts: vec![],
data: vec![],
}],
address_table_lookups: vec![],
}; "v0 message")]
fn test_get_fee_for_message_sends_properly_serialized_v0_transaction<M>(message: M)
where
M: SerializableMessage,
{
let serialized_message = message.serialize();
let serialized_message_base64 = BASE64_STANDARD.encode(serialized_message);

let (sender, receiver) = unbounded();
thread::spawn(move || {
let rpc_addr = "0.0.0.0:0".parse().unwrap();
let mut io = IoHandler::default();
// Successful request
io.add_method("getFeeForMessage", move |params: Params| match params {
Params::Array(p) => {
let first_element = p.first().unwrap();
if let Value::String(actual_serialized_message) = first_element {
assert_eq!(actual_serialized_message, &serialized_message_base64);
return future::ok(json!(Response {
context: RpcResponseContext {
api_version: None,
slot: 1,
},
value: json!(42),
}));
}
future::err(Error::invalid_params(
"Expected the serialized message to be the first element of the params",
))
}
_ => {
panic!("Expected an array of params to be forwarded to `getFeeForMessage");
}
});

let server = ServerBuilder::new(io)
.threads(1)
.cors(DomainsValidation::AllowOnly(vec![
AccessControlAllowOrigin::Any,
]))
.start_http(&rpc_addr)
.expect("Unable to start RPC server");
sender.send(*server.address()).unwrap();
server.wait();
});

let rpc_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(rpc_addr);

let fee: u64 = rpc_client.get_fee_for_message(&message).unwrap();
assert_eq!(fee, 42);
}
}
Loading