only add transactions to signing-queue if it is enabled (#11272)
* only add transactions to signing-queue if it is enabled * Update rpc/src/v1/helpers/errors.rs Co-Authored-By: David <dvdplm@gmail.com> * use errors::codes::ACCOUNT_LOCKED * bail early if account isn't unlocked * use errors::signing * Update rpc/src/v1/helpers/errors.rs * Update rpc/src/v1/helpers/errors.rs * test * adds cli flag to enable signing queue. * use helper method siginig_queue_disabled instead of accounts::SignError * fix typo, use raw i64 * fixed tests
This commit is contained in:
parent
f6c3d4c695
commit
80a83c95d3
@ -348,6 +348,10 @@ usage! {
|
||||
"--unlock=[ACCOUNTS]",
|
||||
"Unlock ACCOUNTS for the duration of the execution. ACCOUNTS is a comma-delimited list of addresses.",
|
||||
|
||||
ARG arg_enable_signing_queue: (bool) = false, or |c: &Config| c.account.as_ref()?.enable_signing_queue,
|
||||
"--enable-signing-queue=[BOOLEAN]",
|
||||
"Enables the signing queue for external transaction signing either via CLI or personal_unlockAccount, turned off by default.",
|
||||
|
||||
ARG arg_password: (Vec<String>) = Vec::new(), or |c: &Config| c.account.as_ref()?.password.clone(),
|
||||
"--password=[FILE]...",
|
||||
"Provide a file containing a password for unlocking an account. Leading and trailing whitespace is trimmed.",
|
||||
@ -1194,6 +1198,7 @@ struct Operating {
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Account {
|
||||
unlock: Option<Vec<String>>,
|
||||
enable_signing_queue: Option<bool>,
|
||||
password: Option<Vec<String>>,
|
||||
keys_iterations: Option<u32>,
|
||||
refresh_time: Option<u64>,
|
||||
@ -1728,6 +1733,7 @@ mod tests {
|
||||
arg_restore_file: None,
|
||||
arg_tools_hash_file: None,
|
||||
|
||||
arg_enable_signing_queue: false,
|
||||
arg_signer_sign_id: None,
|
||||
arg_signer_reject_id: None,
|
||||
arg_dapp_path: None,
|
||||
@ -2045,6 +2051,7 @@ mod tests {
|
||||
_legacy_public_node: None,
|
||||
}),
|
||||
account: Some(Account {
|
||||
enable_signing_queue: None,
|
||||
unlock: Some(vec!["0x1".into(), "0x2".into(), "0x3".into()]),
|
||||
password: Some(vec!["passwdfile path".into()]),
|
||||
keys_iterations: None,
|
||||
|
@ -898,7 +898,7 @@ impl Configuration {
|
||||
fn ws_config(&self) -> Result<WsConfiguration, String> {
|
||||
let support_token_api =
|
||||
// enabled when not unlocking
|
||||
self.args.arg_unlock.is_none();
|
||||
self.args.arg_unlock.is_none() && self.args.arg_enable_signing_queue;
|
||||
|
||||
let conf = WsConfiguration {
|
||||
enabled: self.ws_enabled(),
|
||||
@ -1388,7 +1388,7 @@ mod tests {
|
||||
origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]),
|
||||
hosts: Some(vec![]),
|
||||
signer_path: expected.into(),
|
||||
support_token_api: true,
|
||||
support_token_api: false,
|
||||
max_connections: 100,
|
||||
}, LogConfig {
|
||||
color: !cfg!(windows),
|
||||
|
@ -119,7 +119,7 @@ impl Default for WsConfiguration {
|
||||
origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]),
|
||||
hosts: Some(Vec::new()),
|
||||
signer_path: replace_home(&data_dir, "$BASE/signer").into(),
|
||||
support_token_api: true,
|
||||
support_token_api: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -380,6 +380,16 @@ pub fn invalid_call_data<T: fmt::Display>(error: T) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signing_queue_disabled() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(-32020),
|
||||
message: "Your account is locked and the signing queue is disabled. \
|
||||
You can either Unlock the account via CLI, personal_unlockAccount or \
|
||||
enable the signing queue to use Trusted Signer.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "accounts"))]
|
||||
pub fn signing(error: ::accounts::SignError) -> Error {
|
||||
Error {
|
||||
|
@ -114,6 +114,12 @@ impl<D: Dispatcher + 'static> SigningQueueClient<D> {
|
||||
|
||||
fn dispatch(&self, payload: RpcConfirmationPayload, origin: Origin) -> BoxFuture<DispatchResult> {
|
||||
let default_account = self.accounts.default_account();
|
||||
let from = &payload.sender().unwrap_or(&default_account);
|
||||
// bail early if the account isn't unlocked
|
||||
if !self.accounts.is_unlocked(from) && !self.signer.is_enabled() {
|
||||
return Box::new(future::done(Err(errors::signing_queue_disabled())))
|
||||
}
|
||||
|
||||
let accounts = self.accounts.clone();
|
||||
let dispatcher = self.dispatcher.clone();
|
||||
let signer = self.signer.clone();
|
||||
@ -127,7 +133,9 @@ impl<D: Dispatcher + 'static> SigningQueueClient<D> {
|
||||
} else {
|
||||
Either::B(future::done(
|
||||
signer.add_request(payload, origin)
|
||||
.map(|(id, future)| DispatchResult::Future(id, future))
|
||||
.map(|(id, future)| {
|
||||
DispatchResult::Future(id, future)
|
||||
})
|
||||
.map_err(|_| errors::request_rejected_limit())
|
||||
))
|
||||
}
|
||||
|
@ -50,10 +50,10 @@ struct SigningTester {
|
||||
pub io: IoHandler<Metadata>,
|
||||
}
|
||||
|
||||
impl Default for SigningTester {
|
||||
fn default() -> Self {
|
||||
impl SigningTester {
|
||||
fn new(signing_queue_enabled: bool) ->Self {
|
||||
let runtime = Runtime::with_thread_count(1);
|
||||
let signer = Arc::new(SignerService::new_test(false));
|
||||
let signer = Arc::new(SignerService::new_test(signing_queue_enabled));
|
||||
let client = Arc::new(TestBlockChainClient::default());
|
||||
let miner = Arc::new(TestMinerService::default());
|
||||
let accounts = Arc::new(AccountProvider::transient_provider());
|
||||
@ -81,15 +81,15 @@ impl Default for SigningTester {
|
||||
}
|
||||
}
|
||||
|
||||
fn eth_signing() -> SigningTester {
|
||||
SigningTester::default()
|
||||
fn eth_signing(signing_queue_enabled: bool) -> SigningTester {
|
||||
SigningTester::new(signing_queue_enabled)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_sign() {
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
|
||||
let account = tester.accounts.insert_account(Secret::from([69u8; 32]), &"abcd".into()).unwrap();
|
||||
tester.accounts.unlock_account_permanently(account, "abcd".into()).unwrap();
|
||||
@ -112,7 +112,7 @@ fn rpc_eth_sign() {
|
||||
#[test]
|
||||
fn should_add_sign_to_queue() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let address = Address::random();
|
||||
assert_eq!(tester.signer.requests().len(), 0);
|
||||
|
||||
@ -150,7 +150,7 @@ fn should_add_sign_to_queue() {
|
||||
#[test]
|
||||
fn should_post_sign_to_queue() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let address = Address::random();
|
||||
assert_eq!(tester.signer.requests().len(), 0);
|
||||
|
||||
@ -174,7 +174,7 @@ fn should_post_sign_to_queue() {
|
||||
#[test]
|
||||
fn should_check_status_of_request() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let address = Address::random();
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@ -203,7 +203,7 @@ fn should_check_status_of_request() {
|
||||
#[test]
|
||||
fn should_check_status_of_request_when_its_resolved() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let address = Address::random();
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@ -234,10 +234,56 @@ fn should_check_status_of_request_when_its_resolved() {
|
||||
assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eth_sign_locked_account() {
|
||||
let secret = "8a283037bb19c4fed7b1c569e40c7dcff366165eb869110a1b11532963eb9cb2".parse().unwrap();
|
||||
let tester = eth_signing(false);
|
||||
let address = tester.accounts.insert_account(secret, &"".into()).unwrap();
|
||||
|
||||
let req_send_trans = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_sendTransaction",
|
||||
"params": [{
|
||||
"from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"",
|
||||
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||
"gas": "0x30000",
|
||||
"gasPrice": "0x1",
|
||||
"value": "0x9184e72a"
|
||||
}],
|
||||
"id": 16
|
||||
}"#;
|
||||
|
||||
// expected error response
|
||||
let error_res = r#"{
|
||||
"jsonrpc":"2.0",
|
||||
"error":
|
||||
{
|
||||
"code":-32020,
|
||||
"message":"Your account is locked and the signing queue is disabled.
|
||||
You can either Unlock the account via CLI, personal_unlockAccount or
|
||||
enable the signing queue to use Trusted Signer."
|
||||
},
|
||||
"id":16
|
||||
}"#;
|
||||
// dispatch the transaction, without unlocking the account.
|
||||
assert_eq!(
|
||||
error_res.replace("\t", "").replace("\n", ""),
|
||||
tester.io.handle_request_sync(&req_send_trans).unwrap()
|
||||
);
|
||||
// unlock the account
|
||||
tester.accounts.unlock_account_permanently(address, "".into()).unwrap();
|
||||
|
||||
// try again, this time account is unlocked.
|
||||
assert_eq!(
|
||||
r#"{"jsonrpc":"2.0","result":"0x70df76392fba654351714803d99a90be1d58d165352e0008e376427284314c88","id":16}"#,
|
||||
tester.io.handle_request_sync(&req_send_trans).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_sign_if_account_is_unlocked() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let data = vec![5u8];
|
||||
let acc = tester.accounts.insert_account(Secret::from([69u8; 32]), &"test".into()).unwrap();
|
||||
tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap();
|
||||
@ -260,7 +306,7 @@ fn should_sign_if_account_is_unlocked() {
|
||||
#[test]
|
||||
fn should_add_transaction_to_queue() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let address = Address::random();
|
||||
assert_eq!(tester.signer.requests().len(), 0);
|
||||
|
||||
@ -301,7 +347,7 @@ fn should_add_transaction_to_queue() {
|
||||
#[test]
|
||||
fn should_add_sign_transaction_to_the_queue() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let address = tester.accounts.new_account(&"test".into()).unwrap();
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 0);
|
||||
@ -380,7 +426,7 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
#[test]
|
||||
fn should_dispatch_transaction_if_account_is_unlock() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let acc = tester.accounts.new_account(&"test".into()).unwrap();
|
||||
tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap();
|
||||
|
||||
@ -417,7 +463,7 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
||||
#[test]
|
||||
fn should_decrypt_message_if_account_is_unlocked() {
|
||||
// given
|
||||
let mut tester = eth_signing();
|
||||
let mut tester = eth_signing(true);
|
||||
let parity = parity::Dependencies::new();
|
||||
tester.io.extend_with(parity.client(None).to_delegate());
|
||||
let (address, public) = tester.accounts.new_account_and_public(&"test".into()).unwrap();
|
||||
@ -449,7 +495,7 @@ fn should_decrypt_message_if_account_is_unlocked() {
|
||||
#[test]
|
||||
fn should_add_decryption_to_the_queue() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let acc = Random.generate().unwrap();
|
||||
assert_eq!(tester.signer.requests().len(), 0);
|
||||
|
||||
@ -486,7 +532,7 @@ fn should_add_decryption_to_the_queue() {
|
||||
#[test]
|
||||
fn should_compose_transaction() {
|
||||
// given
|
||||
let tester = eth_signing();
|
||||
let tester = eth_signing(true);
|
||||
let acc = Random.generate().unwrap();
|
||||
assert_eq!(tester.signer.requests().len(), 0);
|
||||
let from = format!("{:x}", acc.address());
|
||||
|
@ -229,6 +229,18 @@ impl From<helpers::ConfirmationPayload> for ConfirmationPayload {
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfirmationPayload {
|
||||
pub fn sender(&self) -> Option<&H160> {
|
||||
match *self {
|
||||
ConfirmationPayload::SendTransaction(ref request) => request.from.as_ref(),
|
||||
ConfirmationPayload::SignTransaction(ref request) => request.from.as_ref(),
|
||||
ConfirmationPayload::EthSignMessage(ref request) => Some(&request.address),
|
||||
ConfirmationPayload::EIP191SignMessage(ref request) => Some(&request.address),
|
||||
ConfirmationPayload::Decrypt(ref request) => Some(&request.address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible modifications to the confirmed transaction sent by `Trusted Signer`
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
Loading…
Reference in New Issue
Block a user