Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Add experimental RPCs flag #9928

Merged
merged 4 commits into from
Nov 16, 2018
Merged
Show file tree
Hide file tree
Changes from 3 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
7 changes: 7 additions & 0 deletions parity/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,10 @@ usage! {
"--jsonrpc-no-keep-alive",
"Disable HTTP/1.1 keep alive header. Disabling keep alive will prevent re-using the same TCP connection to fire multiple requests, recommended when using one request per connection.",

FLAG flag_jsonrpc_experimental: (bool) = false, or |c: &Config| c.rpc.as_ref()?.experimental_rpcs.clone(),
"--jsonrpc-experimental",
"Enable experimental RPCs. Enable to have access to methods from unfinalised EIPs in all namespaces",

ARG arg_jsonrpc_port: (u16) = 8545u16, or |c: &Config| c.rpc.as_ref()?.port.clone(),
"--jsonrpc-port=[PORT]",
"Specify the port portion of the HTTP JSON-RPC API server.",
Expand Down Expand Up @@ -1224,6 +1228,7 @@ struct Rpc {
processing_threads: Option<usize>,
max_payload: Option<usize>,
keep_alive: Option<bool>,
experimental_rpcs: Option<bool>,
}

#[derive(Default, Debug, PartialEq, Deserialize)]
Expand Down Expand Up @@ -1682,6 +1687,7 @@ mod tests {
// RPC
flag_no_jsonrpc: false,
flag_jsonrpc_no_keep_alive: false,
flag_jsonrpc_experimental: false,
arg_jsonrpc_port: 8545u16,
arg_jsonrpc_interface: "local".into(),
arg_jsonrpc_cors: "null".into(),
Expand Down Expand Up @@ -1965,6 +1971,7 @@ mod tests {
processing_threads: None,
max_payload: None,
keep_alive: None,
experimental_rpcs: None,
}),
ipc: Some(Ipc {
disable: None,
Expand Down
3 changes: 3 additions & 0 deletions parity/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ impl Configuration {
let compaction = self.args.arg_db_compaction.parse()?;
let warp_sync = !self.args.flag_no_warp;
let geth_compatibility = self.args.flag_geth;
let experimental_rpcs = self.args.flag_jsonrpc_experimental;
let ipfs_conf = self.ipfs_config();
let secretstore_conf = self.secretstore_config()?;
let format = self.format()?;
Expand Down Expand Up @@ -377,6 +378,7 @@ impl Configuration {
warp_sync: warp_sync,
warp_barrier: self.args.arg_warp_barrier,
geth_compatibility: geth_compatibility,
experimental_rpcs,
net_settings: self.network_settings()?,
ipfs_conf: ipfs_conf,
secretstore_conf: secretstore_conf,
Expand Down Expand Up @@ -1424,6 +1426,7 @@ mod tests {
compaction: Default::default(),
vm_type: Default::default(),
geth_compatibility: false,
experimental_rpcs: false,
net_settings: Default::default(),
ipfs_conf: Default::default(),
secretstore_conf: Default::default(),
Expand Down
6 changes: 4 additions & 2 deletions parity/rpc_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ pub struct FullDependencies {
pub net_service: Arc<ManageNetwork>,
pub updater: Arc<Updater>,
pub geth_compatibility: bool,
pub experimental_rpcs: bool,
pub ws_address: Option<Host>,
pub fetch: FetchClient,
pub executor: Executor,
Expand Down Expand Up @@ -317,7 +318,7 @@ impl FullDependencies {
}
},
Api::Personal => {
handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility).to_delegate());
handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility, self.experimental_rpcs).to_delegate());
},
Api::Signer => {
handler.extend_with(SignerClient::new(&self.secret_store, dispatcher.clone(), &self.signer_service, self.executor.clone()).to_delegate());
Expand Down Expand Up @@ -439,6 +440,7 @@ pub struct LightDependencies<T> {
pub ws_address: Option<Host>,
pub fetch: FetchClient,
pub geth_compatibility: bool,
pub experimental_rpcs: bool,
pub executor: Executor,
pub whisper_rpc: Option<::whisper::RpcFactory>,
pub private_tx_service: Option<Arc<PrivateTransactionManager>>,
Expand Down Expand Up @@ -532,7 +534,7 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
handler.extend_with(EthPubSub::to_delegate(client));
},
Api::Personal => {
handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility).to_delegate());
handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility, self.experimental_rpcs).to_delegate());
},
Api::Signer => {
handler.extend_with(SignerClient::new(&self.secret_store, dispatcher.clone(), &self.signer_service, self.executor.clone()).to_delegate());
Expand Down
3 changes: 3 additions & 0 deletions parity/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub struct RunCmd {
pub compaction: DatabaseCompactionProfile,
pub vm_type: VMType,
pub geth_compatibility: bool,
pub experimental_rpcs: bool,
pub net_settings: NetworkSettings,
pub ipfs_conf: ipfs::Configuration,
pub secretstore_conf: secretstore::Configuration,
Expand Down Expand Up @@ -312,6 +313,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
ws_address: cmd.ws_conf.address(),
fetch: fetch,
geth_compatibility: cmd.geth_compatibility,
experimental_rpcs: cmd.experimental_rpcs,
executor: runtime.executor(),
whisper_rpc: whisper_factory,
private_tx_service: None, //TODO: add this to client.
Expand Down Expand Up @@ -712,6 +714,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
net_service: manage_network.clone(),
updater: updater.clone(),
geth_compatibility: cmd.geth_compatibility,
experimental_rpcs: cmd.experimental_rpcs,
ws_address: cmd.ws_conf.address(),
fetch: fetch.clone(),
executor: runtime.executor(),
Expand Down
13 changes: 13 additions & 0 deletions rpc/src/v1/helpers/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ mod codes {
pub const NO_LIGHT_PEERS: i64 = -32065;
pub const NO_PEERS: i64 = -32066;
pub const DEPRECATED: i64 = -32070;
pub const EXPERIMENTAL_RPC: i64 = -32071;
}

pub fn unimplemented(details: Option<String>) -> Error {
Expand Down Expand Up @@ -513,3 +514,15 @@ pub fn status_error(has_peers: bool) -> Error {
}
}

/// Returns a descriptive error in case experimental RPCs are not enabled.
pub fn require_experimental(allow_experimental_rpcs: bool, eip: &str) -> Result<(), Error> {
if allow_experimental_rpcs {
Ok(())
} else {
Err(Error {
code: ErrorCode::ServerError(codes::EXPERIMENTAL_RPC),
message: format!("This method is not part of the official RPC API yet (EIP-{}). Run with `--jsonrpc-experimental` to enable it.", eip),
data: Some(Value::String(format!("See EIP: https://eips.ethereum.org/EIPS/eip-{}", eip))),
})
}
}
13 changes: 12 additions & 1 deletion rpc/src/v1/impls/personal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,22 @@ pub struct PersonalClient<D: Dispatcher> {
accounts: Arc<AccountProvider>,
dispatcher: D,
allow_perm_unlock: bool,
allow_experimental_rpcs: bool,
}

impl<D: Dispatcher> PersonalClient<D> {
/// Creates new PersonalClient
pub fn new(accounts: &Arc<AccountProvider>, dispatcher: D, allow_perm_unlock: bool) -> Self {
pub fn new(
accounts: &Arc<AccountProvider>,
dispatcher: D,
allow_perm_unlock: bool,
allow_experimental_rpcs: bool,
) -> Self {
PersonalClient {
accounts: accounts.clone(),
dispatcher,
allow_perm_unlock,
allow_experimental_rpcs,
}
}
}
Expand Down Expand Up @@ -154,6 +161,8 @@ impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
}

fn sign_191(&self, version: EIP191Version, data: Value, account: RpcH160, password: String) -> BoxFuture<RpcH520> {
try_bf!(errors::require_experimental(self.allow_experimental_rpcs, "191"));

let data = try_bf!(eip191::hash_message(version, data));
let dispatcher = self.dispatcher.clone();
let accounts = self.accounts.clone();
Expand All @@ -174,6 +183,8 @@ impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
}

fn sign_typed_data(&self, typed_data: EIP712, account: RpcH160, password: String) -> BoxFuture<RpcH520> {
try_bf!(errors::require_experimental(self.allow_experimental_rpcs, "712"));

let data = match hash_structured_data(typed_data) {
Ok(d) => d,
Err(err) => return Box::new(future::err(errors::invalid_call_data(err.kind()))),
Expand Down
118 changes: 117 additions & 1 deletion rpc/src/v1/tests/mocked/personal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,24 @@ fn miner_service() -> Arc<TestMinerService> {
}

fn setup() -> PersonalTester {
setup_with(Config {
allow_experimental_rpcs: true
})
}

struct Config {
pub allow_experimental_rpcs: bool,
}

fn setup_with(c: Config) -> PersonalTester {
let runtime = Runtime::with_thread_count(1);
let accounts = accounts_provider();
let client = blockchain_client();
let miner = miner_service();
let reservations = Arc::new(Mutex::new(nonce::Reservations::new(runtime.executor())));

let dispatcher = FullDispatcher::new(client, miner.clone(), reservations, 50);
let personal = PersonalClient::new(&accounts, dispatcher, false);
let personal = PersonalClient::new(&accounts, dispatcher, false, c.allow_experimental_rpcs);

let mut io = IoHandler::default();
io.extend_with(personal.to_delegate());
Expand Down Expand Up @@ -418,3 +428,109 @@ fn sign_eip191_structured_data() {
let response = tester.io.handle_request_sync(&request).unwrap();
assert_eq!(response, expected)
}

#[test]
fn sign_structured_data() {
let tester = setup();
let secret: Secret = keccak("cow").into();
let address = tester.accounts.insert_account(secret, &"lol".into()).unwrap();
let request = r#"{
"jsonrpc": "2.0",
"method": "personal_signTypedData",
"params": [
{
"primaryType": "Mail",
"domain": {
"name": "Ether Mail",
"version": "1",
"chainId": "0x1",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
},
"message": {
"from": {
"name": "Cow",
"wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
},
"to": {
"name": "Bob",
"wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
},
"contents": "Hello, Bob!"
},
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Person": [
{ "name": "name", "type": "string" },
{ "name": "wallet", "type": "address" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "Person" },
{ "name": "contents", "type": "string" }
]
}
},
""#.to_owned() + &format!("0x{:x}", address) + r#"",
"lol"
],
"id": 1
}"#;
let expected = r#"{"jsonrpc":"2.0","result":"0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c","id":1}"#;
let response = tester.io.handle_request_sync(&request).unwrap();
assert_eq!(response, expected)
}

#[test]
fn should_disable_experimental_apis() {
// given
let tester = setup_with(Config {
allow_experimental_rpcs: false,
});

// when
let request = r#"{
"jsonrpc": "2.0",
"method": "personal_sign191",
"params": [
"0x01",
{},
"0x1234567891234567891234567891234567891234",
"lol"
],
"id": 1
}"#;
let r1 = tester.io.handle_request_sync(&request).unwrap();
let request = r#"{
"jsonrpc": "2.0",
"method": "personal_signTypedData",
"params": [
{
"types": {},
"message": {},
"domain": {
"name": "",
"version": "1",
"chainId": "0x1",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
},
"primaryType": ""
},
"0x1234567891234567891234567891234678912344",
"lol"
],
"id": 1
}"#;
let r2 = tester.io.handle_request_sync(&request).unwrap();

// then
let expected = r#"{"jsonrpc":"2.0","error":{"code":-32071,"message":"This method is not part of the official RPC API yet (EIP-191). Run with `--jsonrpc-experimental` to enable it.","data":"See EIP: https://eips.ethereum.org/EIPS/eip-191"},"id":1}"#;
assert_eq!(r1, expected);

let expected = r#"{"jsonrpc":"2.0","error":{"code":-32071,"message":"This method is not part of the official RPC API yet (EIP-712). Run with `--jsonrpc-experimental` to enable it.","data":"See EIP: https://eips.ethereum.org/EIPS/eip-712"},"id":1}"#;
assert_eq!(r2, expected);
}