use async_trait::async_trait;
use criterion::{criterion_group, criterion_main, Criterion};
use std::time::Duration;
use bsv::wallet::error::WalletError;
use bsv::wallet::interfaces::{
AbortActionArgs, AbortActionResult, AcquireCertificateArgs, Certificate, CreateActionArgs,
CreateActionResult, CreateHmacArgs, CreateHmacResult, CreateSignatureArgs,
CreateSignatureResult, DecryptArgs, DecryptResult, DiscoverByAttributesArgs,
DiscoverByIdentityKeyArgs, DiscoverCertificatesResult, EncryptArgs, EncryptResult,
GetHeaderArgs, GetHeaderResult, GetHeightResult, GetNetworkResult, GetPublicKeyArgs,
GetPublicKeyResult, GetVersionResult, InternalizeActionArgs, InternalizeActionResult,
ListActionsArgs, ListActionsResult, ListCertificatesArgs, ListCertificatesResult,
ListOutputsArgs, ListOutputsResult, ProveCertificateArgs, ProveCertificateResult,
RelinquishCertificateArgs, RelinquishCertificateResult, RelinquishOutputArgs,
RelinquishOutputResult, RevealCounterpartyKeyLinkageArgs, RevealCounterpartyKeyLinkageResult,
RevealSpecificKeyLinkageArgs, RevealSpecificKeyLinkageResult, SignActionArgs, SignActionResult,
VerifyHmacArgs, VerifyHmacResult, VerifySignatureArgs, VerifySignatureResult, WalletInterface,
};
use bsv::wallet::types::Protocol;
struct NoOpWallet;
#[async_trait]
impl WalletInterface for NoOpWallet {
async fn create_action(
&self,
_args: CreateActionArgs,
_originator: Option<&str>,
) -> Result<CreateActionResult, WalletError> {
Ok(CreateActionResult {
txid: None,
tx: None,
no_send_change: vec![],
send_with_results: vec![],
signable_transaction: None,
})
}
async fn sign_action(
&self,
_args: SignActionArgs,
_originator: Option<&str>,
) -> Result<SignActionResult, WalletError> {
Ok(SignActionResult {
txid: None,
tx: None,
send_with_results: vec![],
})
}
async fn abort_action(
&self,
_args: AbortActionArgs,
_originator: Option<&str>,
) -> Result<AbortActionResult, WalletError> {
Ok(AbortActionResult { aborted: true })
}
async fn list_actions(
&self,
_args: ListActionsArgs,
_originator: Option<&str>,
) -> Result<ListActionsResult, WalletError> {
Ok(ListActionsResult {
total_actions: 0,
actions: vec![],
})
}
async fn internalize_action(
&self,
_args: InternalizeActionArgs,
_originator: Option<&str>,
) -> Result<InternalizeActionResult, WalletError> {
Ok(InternalizeActionResult { accepted: true })
}
async fn list_outputs(
&self,
_args: ListOutputsArgs,
_originator: Option<&str>,
) -> Result<ListOutputsResult, WalletError> {
Ok(ListOutputsResult {
total_outputs: 0,
beef: None,
outputs: vec![],
})
}
async fn relinquish_output(
&self,
_args: RelinquishOutputArgs,
_originator: Option<&str>,
) -> Result<RelinquishOutputResult, WalletError> {
Ok(RelinquishOutputResult { relinquished: true })
}
async fn get_public_key(
&self,
_args: GetPublicKeyArgs,
_originator: Option<&str>,
) -> Result<GetPublicKeyResult, WalletError> {
Ok(GetPublicKeyResult {
public_key: bsv::primitives::public_key::PublicKey::from_private_key(
&bsv::primitives::private_key::PrivateKey::from_hex("1").expect("valid hex"),
),
})
}
async fn reveal_counterparty_key_linkage(
&self,
_args: RevealCounterpartyKeyLinkageArgs,
_originator: Option<&str>,
) -> Result<RevealCounterpartyKeyLinkageResult, WalletError> {
Err(WalletError::NotImplemented(
"reveal_counterparty_key_linkage".into(),
))
}
async fn reveal_specific_key_linkage(
&self,
_args: RevealSpecificKeyLinkageArgs,
_originator: Option<&str>,
) -> Result<RevealSpecificKeyLinkageResult, WalletError> {
Err(WalletError::NotImplemented(
"reveal_specific_key_linkage".into(),
))
}
async fn encrypt(
&self,
_args: EncryptArgs,
_originator: Option<&str>,
) -> Result<EncryptResult, WalletError> {
Ok(EncryptResult {
ciphertext: vec![0u8; 32],
})
}
async fn decrypt(
&self,
_args: DecryptArgs,
_originator: Option<&str>,
) -> Result<DecryptResult, WalletError> {
Ok(DecryptResult {
plaintext: vec![0u8; 32],
})
}
async fn create_hmac(
&self,
_args: CreateHmacArgs,
_originator: Option<&str>,
) -> Result<CreateHmacResult, WalletError> {
Ok(CreateHmacResult {
hmac: vec![0u8; 32],
})
}
async fn verify_hmac(
&self,
_args: VerifyHmacArgs,
_originator: Option<&str>,
) -> Result<VerifyHmacResult, WalletError> {
Ok(VerifyHmacResult { valid: true })
}
async fn create_signature(
&self,
_args: CreateSignatureArgs,
_originator: Option<&str>,
) -> Result<CreateSignatureResult, WalletError> {
Ok(CreateSignatureResult {
signature: vec![0u8; 64],
})
}
async fn verify_signature(
&self,
_args: VerifySignatureArgs,
_originator: Option<&str>,
) -> Result<VerifySignatureResult, WalletError> {
Ok(VerifySignatureResult { valid: true })
}
async fn acquire_certificate(
&self,
_args: AcquireCertificateArgs,
_originator: Option<&str>,
) -> Result<Certificate, WalletError> {
Err(WalletError::NotImplemented("acquire_certificate".into()))
}
async fn list_certificates(
&self,
_args: ListCertificatesArgs,
_originator: Option<&str>,
) -> Result<ListCertificatesResult, WalletError> {
Ok(ListCertificatesResult {
total_certificates: 0,
certificates: vec![],
})
}
async fn prove_certificate(
&self,
_args: ProveCertificateArgs,
_originator: Option<&str>,
) -> Result<ProveCertificateResult, WalletError> {
Err(WalletError::NotImplemented("prove_certificate".into()))
}
async fn relinquish_certificate(
&self,
_args: RelinquishCertificateArgs,
_originator: Option<&str>,
) -> Result<RelinquishCertificateResult, WalletError> {
Ok(RelinquishCertificateResult { relinquished: true })
}
async fn discover_by_identity_key(
&self,
_args: DiscoverByIdentityKeyArgs,
_originator: Option<&str>,
) -> Result<DiscoverCertificatesResult, WalletError> {
Ok(DiscoverCertificatesResult {
total_certificates: 0,
certificates: vec![],
})
}
async fn discover_by_attributes(
&self,
_args: DiscoverByAttributesArgs,
_originator: Option<&str>,
) -> Result<DiscoverCertificatesResult, WalletError> {
Ok(DiscoverCertificatesResult {
total_certificates: 0,
certificates: vec![],
})
}
async fn is_authenticated(
&self,
_originator: Option<&str>,
) -> Result<bsv::wallet::interfaces::AuthenticatedResult, WalletError> {
Ok(bsv::wallet::interfaces::AuthenticatedResult {
authenticated: true,
})
}
async fn wait_for_authentication(
&self,
_originator: Option<&str>,
) -> Result<bsv::wallet::interfaces::AuthenticatedResult, WalletError> {
Ok(bsv::wallet::interfaces::AuthenticatedResult {
authenticated: true,
})
}
async fn get_height(&self, _originator: Option<&str>) -> Result<GetHeightResult, WalletError> {
Ok(GetHeightResult { height: 800000 })
}
async fn get_header_for_height(
&self,
_args: GetHeaderArgs,
_originator: Option<&str>,
) -> Result<GetHeaderResult, WalletError> {
Ok(GetHeaderResult {
header: vec![0u8; 80],
})
}
async fn get_network(
&self,
_originator: Option<&str>,
) -> Result<GetNetworkResult, WalletError> {
Ok(GetNetworkResult {
network: bsv::wallet::interfaces::Network::Mainnet,
})
}
async fn get_version(
&self,
_originator: Option<&str>,
) -> Result<GetVersionResult, WalletError> {
Ok(GetVersionResult {
version: "0.1.3".into(),
})
}
}
#[async_trait]
trait WalletInterfaceBoxed: Send + Sync {
async fn get_public_key_boxed(
&self,
args: GetPublicKeyArgs,
originator: Option<&str>,
) -> Result<GetPublicKeyResult, WalletError>;
}
#[async_trait]
impl WalletInterfaceBoxed for NoOpWallet {
async fn get_public_key_boxed(
&self,
_args: GetPublicKeyArgs,
_originator: Option<&str>,
) -> Result<GetPublicKeyResult, WalletError> {
Ok(GetPublicKeyResult {
public_key: bsv::primitives::public_key::PublicKey::from_private_key(
&bsv::primitives::private_key::PrivateKey::from_hex("1").expect("valid hex"),
),
})
}
}
fn make_get_pk_args() -> GetPublicKeyArgs {
GetPublicKeyArgs {
identity_key: false,
protocol_id: Some(Protocol {
protocol: "tests".into(),
security_level: 2,
}),
key_id: Some("bench-key".into()),
counterparty: None,
privileged: false,
privileged_reason: None,
for_self: Some(false),
seek_permission: None,
}
}
async fn call_rpitit_generic<W: WalletInterface>(w: &W) -> GetPublicKeyResult {
let args = make_get_pk_args();
w.get_public_key(args, None)
.await
.expect("no-op should succeed")
}
async fn call_boxed_dyn(w: &dyn WalletInterfaceBoxed) -> GetPublicKeyResult {
let args = make_get_pk_args();
w.get_public_key_boxed(args, None)
.await
.expect("no-op should succeed")
}
fn dispatch_benchmarks(c: &mut Criterion) {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("tokio runtime");
let mut group = c.benchmark_group("dispatch_bench");
group.measurement_time(Duration::from_secs(5));
group.sample_size(100);
group.warm_up_time(Duration::from_secs(2));
let wallet = NoOpWallet;
group.bench_function("rpitit_direct", |bencher| {
bencher.iter(|| {
rt.block_on(async {
let args = make_get_pk_args();
criterion::black_box(
wallet
.get_public_key(args, None)
.await
.expect("no-op should succeed"),
)
})
});
});
group.bench_function("rpitit_generic", |bencher| {
bencher.iter(|| {
rt.block_on(async { criterion::black_box(call_rpitit_generic(&wallet).await) })
});
});
let wallet_boxed: &dyn WalletInterfaceBoxed = &wallet;
group.bench_function("async_trait_dyn", |bencher| {
bencher.iter(|| {
rt.block_on(async { criterion::black_box(call_boxed_dyn(wallet_boxed).await) })
});
});
group.finish();
}
criterion_group!(benches, dispatch_benchmarks);
criterion_main!(benches);