RPC Middleware & Get/Set dapp-specific accounts

This commit is contained in:
Tomasz Drwięga 2016-11-22 11:56:27 +01:00
parent 21b2b4ac27
commit cd6f565f69
34 changed files with 655 additions and 224 deletions

92
Cargo.lock generated
View File

@ -27,7 +27,6 @@ dependencies = [
"fdlimit 0.1.0",
"hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -341,8 +340,8 @@ dependencies = [
"ethcore-util 1.5.0",
"fetch 0.1.0",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)",
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -503,9 +502,9 @@ dependencies = [
"ethstore 0.1.0",
"ethsync 1.5.0",
"fetch 0.1.0",
"json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)",
"jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@ -526,7 +525,7 @@ dependencies = [
"ethcore-io 1.5.0",
"ethcore-rpc 1.5.0",
"ethcore-util 1.5.0",
"jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-ui 1.4.0",
@ -545,8 +544,8 @@ dependencies = [
"ethcore-ipc-codegen 1.4.0",
"ethcore-ipc-nano 1.4.0",
"ethcore-util 1.5.0",
"json-tcp-server 0.1.0 (git+https://github.com/ethcore/json-tcp-server)",
"jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
@ -831,39 +830,10 @@ name = "itoa"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "json-ipc-server"
version = "0.2.4"
source = "git+https://github.com/ethcore/json-ipc-server.git#4642cd03ec1d23db89df80d22d5a88e7364ab885"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "json-tcp-server"
version = "0.1.0"
source = "git+https://github.com/ethcore/json-tcp-server#c2858522274ae56042472bb5d22845a1b85e5338"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-core"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
version = "4.0.0"
source = "git+https://github.com/ethcore/jsonrpc.git#59919f9f0a2ebb675670b72430803605d868904c"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -875,14 +845,44 @@ dependencies = [
[[package]]
name = "jsonrpc-http-server"
version = "6.1.1"
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#cd6d4cb37d672cc3057aecd0692876f9e85f3ba5"
source = "git+https://github.com/ethcore/jsonrpc.git#59919f9f0a2ebb675670b72430803605d868904c"
dependencies = [
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-ipc-server"
version = "0.2.4"
source = "git+https://github.com/ethcore/jsonrpc.git#59919f9f0a2ebb675670b72430803605d868904c"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-tcp-server"
version = "0.1.0"
source = "git+https://github.com/ethcore/jsonrpc.git#59919f9f0a2ebb675670b72430803605d868904c"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -2032,10 +2032,10 @@ dependencies = [
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
"checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76"
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
"checksum json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)" = "<none>"
"checksum json-tcp-server 0.1.0 (git+https://github.com/ethcore/json-tcp-server)" = "<none>"
"checksum jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5094610b07f28f3edaf3947b732dadb31dbba4941d4d0c1c7a8350208f4414"
"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc-http-server.git)" = "<none>"
"checksum jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"

View File

@ -30,7 +30,6 @@ serde = "0.8.0"
serde_json = "0.8.0"
hyper = { version = "0.9", default-features = false }
ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" }
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
fdlimit = { path = "util/fdlimit" }
ethcore = { path = "ethcore" }
ethcore-util = { path = "util" }

View File

@ -12,8 +12,8 @@ build = "build.rs"
rand = "0.3.14"
log = "0.3"
env_logger = "0.3"
jsonrpc-core = "3.0"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
unicase = "1.3"
url = "1.0"

View File

@ -16,13 +16,14 @@
use std::sync::{Arc, Mutex};
use hyper;
use jsonrpc_core::IoHandler;
use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin};
use jsonrpc_core::{IoHandler, ResponseHandler, Request, Response};
use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin, RpcHandler};
use endpoint::{Endpoint, EndpointPath, Handler};
pub fn rpc(handler: Arc<IoHandler>, panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>) -> Box<Endpoint> {
Box::new(RpcEndpoint {
handler: handler,
handler: Arc::new(RpcMiddleware::new(handler)),
panic_handler: panic_handler,
cors_domain: None,
// NOTE [ToDr] We don't need to do any hosts validation here. It's already done in router.
@ -31,7 +32,7 @@ pub fn rpc(handler: Arc<IoHandler>, panic_handler: Arc<Mutex<Option<Box<Fn() ->
}
struct RpcEndpoint {
handler: Arc<IoHandler>,
handler: Arc<RpcMiddleware>,
panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>,
cors_domain: Option<Vec<AccessControlAllowOrigin>>,
allowed_hosts: Option<Vec<String>>,
@ -49,3 +50,88 @@ impl Endpoint for RpcEndpoint {
))
}
}
const MIDDLEWARE_METHOD: &'static str = "eth_accounts";
struct RpcMiddleware {
handler: Arc<IoHandler>,
}
impl RpcMiddleware {
fn new(handler: Arc<IoHandler>) -> Self {
RpcMiddleware {
handler: handler,
}
}
/// Appends additional parameter for specific calls.
fn augment_request(&self, request: &mut Request, meta: Option<Meta>) {
use jsonrpc_core::{Call, Params, to_value};
fn augment_call(call: &mut Call, meta: Option<&Meta>) {
match (call, meta) {
(&mut Call::MethodCall(ref mut method_call), Some(meta)) if &method_call.method == MIDDLEWARE_METHOD => {
let session = to_value(&meta.app_id);
let params = match method_call.params {
Some(Params::Array(ref vec)) if vec.len() == 0 => Some(Params::Array(vec![session])),
// invalid params otherwise
_ => None,
};
method_call.params = params;
},
_ => {}
}
}
match *request {
Request::Single(ref mut call) => augment_call(call, meta.as_ref()),
Request::Batch(ref mut vec) => {
for mut call in vec {
augment_call(call, meta.as_ref())
}
},
}
}
}
#[derive(Debug)]
struct Meta {
app_id: String,
}
impl RpcHandler for RpcMiddleware {
type Metadata = Meta;
fn read_metadata(&self, request: &hyper::server::Request<hyper::net::HttpStream>) -> Option<Self::Metadata> {
let meta = request.headers().get::<hyper::header::Referer>()
.and_then(|referer| hyper::Url::parse(referer).ok())
.and_then(|url| {
url.path_segments()
.and_then(|mut split| split.next())
.map(|app_id| Meta {
app_id: app_id.to_owned(),
})
});
println!("{:?}, {:?}", meta, request.headers());
meta
}
fn handle_request<H>(&self, request_str: &str, response_handler: H, meta: Option<Self::Metadata>) where
H: ResponseHandler<Option<String>, Option<String>> + 'static
{
let handler = IoHandler::convert_handler(response_handler);
let request = IoHandler::read_request(request_str);
trace!(target: "rpc", "Request metadata: {:?}", meta);
match request {
Ok(mut request) => {
self.augment_request(&mut request, meta);
self.handler.request_handler().handle_request(request, handler, None)
},
Err(error) => handler.send(Some(Response::from(error))),
}
}
}

View File

@ -16,9 +16,12 @@
//! Account management.
use std::{fs, fmt};
mod stores;
use self::stores::{AddressBook, DappsSettingsStore};
use std::fmt;
use std::collections::HashMap;
use std::path::PathBuf;
use std::time::{Instant, Duration};
use util::{Mutex, RwLock};
use ethstore::{SecretStore, Error as SSError, SafeAccount, EthStore};
@ -91,84 +94,16 @@ impl KeyDirectory for NullDir {
}
}
/// Disk-backed map from Address to String. Uses JSON.
struct AddressBook {
path: PathBuf,
cache: HashMap<Address, AccountMeta>,
transient: bool,
}
impl AddressBook {
pub fn new(path: String) -> Self {
trace!(target: "addressbook", "new({})", path);
let mut path: PathBuf = path.into();
path.push("address_book.json");
trace!(target: "addressbook", "path={:?}", path);
let mut r = AddressBook {
path: path,
cache: HashMap::new(),
transient: false,
};
r.revert();
r
}
pub fn transient() -> Self {
let mut book = AddressBook::new(Default::default());
book.transient = true;
book
}
pub fn get(&self) -> HashMap<Address, AccountMeta> {
self.cache.clone()
}
pub fn set_name(&mut self, a: Address, name: String) {
let mut x = self.cache.get(&a)
.cloned()
.unwrap_or_else(|| AccountMeta {name: Default::default(), meta: "{}".to_owned(), uuid: None});
x.name = name;
self.cache.insert(a, x);
self.save();
}
pub fn set_meta(&mut self, a: Address, meta: String) {
let mut x = self.cache.get(&a)
.cloned()
.unwrap_or_else(|| AccountMeta {name: "Anonymous".to_owned(), meta: Default::default(), uuid: None});
x.meta = meta;
self.cache.insert(a, x);
self.save();
}
fn revert(&mut self) {
if self.transient { return; }
trace!(target: "addressbook", "revert");
let _ = fs::File::open(self.path.clone())
.map_err(|e| trace!(target: "addressbook", "Couldn't open address book: {}", e))
.and_then(|f| AccountMeta::read_address_map(&f)
.map_err(|e| warn!(target: "addressbook", "Couldn't read address book: {}", e))
.and_then(|m| { self.cache = m; Ok(()) })
);
}
fn save(&mut self) {
if self.transient { return; }
trace!(target: "addressbook", "save");
let _ = fs::File::create(self.path.clone())
.map_err(|e| warn!(target: "addressbook", "Couldn't open address book for writing: {}", e))
.and_then(|mut f| AccountMeta::write_address_map(&self.cache, &mut f)
.map_err(|e| warn!(target: "addressbook", "Couldn't write to address book: {}", e))
);
}
}
/// Dapp identifier
pub type DappId = String;
/// Account management.
/// Responsible for unlocking accounts.
pub struct AccountProvider {
unlocked: Mutex<HashMap<Address, AccountData>>,
sstore: Box<SecretStore>,
address_book: Mutex<AddressBook>,
address_book: RwLock<AddressBook>,
dapps_settings: RwLock<DappsSettingsStore>,
}
impl AccountProvider {
@ -176,7 +111,8 @@ impl AccountProvider {
pub fn new(sstore: Box<SecretStore>) -> Self {
AccountProvider {
unlocked: Mutex::new(HashMap::new()),
address_book: Mutex::new(AddressBook::new(sstore.local_path().into())),
address_book: RwLock::new(AddressBook::new(sstore.local_path().into())),
dapps_settings: RwLock::new(DappsSettingsStore::new(sstore.local_path().into())),
sstore: sstore,
}
}
@ -185,7 +121,8 @@ impl AccountProvider {
pub fn transient_provider() -> Self {
AccountProvider {
unlocked: Mutex::new(HashMap::new()),
address_book: Mutex::new(AddressBook::transient()),
address_book: RwLock::new(AddressBook::transient()),
dapps_settings: RwLock::new(DappsSettingsStore::transient()),
sstore: Box::new(EthStore::open(Box::new(NullDir::default()))
.expect("NullDir load always succeeds; qed"))
}
@ -230,19 +167,31 @@ impl AccountProvider {
Ok(accounts)
}
/// Gets addresses visile for dapp.
pub fn dapps_addresses(&self, dapp: DappId) -> Result<Vec<Address>, Error> {
let accounts = self.dapps_settings.read().get();
Ok(accounts.get(&dapp).map(|settings| settings.accounts.clone()).unwrap_or_else(Vec::new))
}
/// Sets addresses visile for dapp.
pub fn set_dapps_addresses(&self, dapp: DappId, addresses: Vec<Address>) -> Result<(), Error> {
self.dapps_settings.write().set_accounts(dapp, addresses);
Ok(())
}
/// Returns each address along with metadata.
pub fn addresses_info(&self) -> Result<HashMap<Address, AccountMeta>, Error> {
Ok(self.address_book.lock().get())
Ok(self.address_book.read().get())
}
/// Returns each address along with metadata.
pub fn set_address_name(&self, account: Address, name: String) -> Result<(), Error> {
Ok(self.address_book.lock().set_name(account, name))
Ok(self.address_book.write().set_name(account, name))
}
/// Returns each address along with metadata.
pub fn set_address_meta(&self, account: Address, meta: String) -> Result<(), Error> {
Ok(self.address_book.lock().set_meta(account, meta))
Ok(self.address_book.write().set_meta(account, meta))
}
/// Returns each account along with name and meta.
@ -373,23 +322,9 @@ impl AccountProvider {
#[cfg(test)]
mod tests {
use super::{AccountProvider, AddressBook, Unlock};
use std::collections::HashMap;
use super::{AccountProvider, Unlock};
use std::time::Instant;
use ethjson::misc::AccountMeta;
use ethstore::ethkey::{Generator, Random};
use devtools::RandomTempPath;
#[test]
fn should_save_and_reload_address_book() {
let temp = RandomTempPath::create_dir();
let path = temp.as_str().to_owned();
let mut b = AddressBook::new(path.clone());
b.set_name(1.into(), "One".to_owned());
b.set_meta(1.into(), "{1:1}".to_owned());
let b = AddressBook::new(path);
assert_eq!(b.get(), hash_map![1.into() => AccountMeta{name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None}]);
}
#[test]
fn unlock_account_temp() {
@ -427,4 +362,17 @@ mod tests {
ap.unlocked.lock().get_mut(&kp.address()).unwrap().unlock = Unlock::Timed(Instant::now());
assert!(ap.sign(kp.address(), None, Default::default()).is_err());
}
#[test]
fn should_set_dapps_addresses() {
// given
let ap = AccountProvider::transient_provider();
let app = "app1".to_owned();
// when
ap.set_dapps_addresses(app.clone(), vec![1.into(), 2.into()]).unwrap();
// then
assert_eq!(ap.dapps_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]);
}
}

View File

@ -0,0 +1,247 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Address Book and Dapps Settings Store
use std::{fs, fmt, hash, ops};
use std::collections::HashMap;
use std::path::PathBuf;
use ethstore::ethkey::Address;
use ethjson::misc::{AccountMeta, DappsSettings as JsonSettings};
use account_provider::DappId;
/// Disk-backed map from Address to String. Uses JSON.
pub struct AddressBook {
cache: DiskMap<Address, AccountMeta>,
}
impl AddressBook {
/// Creates new address book at given directory.
pub fn new(path: String) -> Self {
let mut r = AddressBook {
cache: DiskMap::new(path, "address_book.json".into())
};
r.cache.revert(AccountMeta::read_address_map);
r
}
/// Creates transient address book (no changes are saved to disk).
pub fn transient() -> Self {
AddressBook {
cache: DiskMap::transient()
}
}
/// Get the address book.
pub fn get(&self) -> HashMap<Address, AccountMeta> {
self.cache.clone()
}
fn save(&self) {
self.cache.save(AccountMeta::write_address_map)
}
/// Sets new name for given address.
pub fn set_name(&mut self, a: Address, name: String) {
{
let mut x = self.cache.entry(a)
.or_insert_with(|| AccountMeta {name: Default::default(), meta: "{}".to_owned(), uuid: None});
x.name = name;
}
self.save();
}
/// Sets new meta for given address.
pub fn set_meta(&mut self, a: Address, meta: String) {
{
let mut x = self.cache.entry(a)
.or_insert_with(|| AccountMeta {name: "Anonymous".to_owned(), meta: Default::default(), uuid: None});
x.meta = meta;
}
self.save();
}
}
/// Dapps user settings
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct DappsSettings {
/// A list of visible accounts
pub accounts: Vec<Address>,
}
impl From<JsonSettings> for DappsSettings {
fn from(s: JsonSettings) -> Self {
DappsSettings {
accounts: s.accounts.into_iter().map(Into::into).collect(),
}
}
}
impl From<DappsSettings> for JsonSettings {
fn from(s: DappsSettings) -> Self {
JsonSettings {
accounts: s.accounts.into_iter().map(Into::into).collect(),
}
}
}
/// Disk-backed map from DappId to Settings. Uses JSON.
pub struct DappsSettingsStore {
cache: DiskMap<DappId, DappsSettings>,
}
impl DappsSettingsStore {
/// Creates new store at given directory path.
pub fn new(path: String) -> Self {
let mut r = DappsSettingsStore {
cache: DiskMap::new(path, "dapps_accounts.json".into())
};
r.cache.revert(JsonSettings::read_dapps_settings);
r
}
/// Creates transient store (no changes are saved to disk).
pub fn transient() -> Self {
DappsSettingsStore {
cache: DiskMap::transient()
}
}
/// Get copy of the dapps settings
pub fn get(&self) -> HashMap<DappId, DappsSettings> {
self.cache.clone()
}
fn save(&self) {
self.cache.save(JsonSettings::write_dapps_settings)
}
pub fn set_accounts(&mut self, id: DappId, accounts: Vec<Address>) {
{
let mut settings = self.cache.entry(id).or_insert_with(DappsSettings::default);
settings.accounts = accounts;
}
self.save();
}
}
/// Disk-serializable HashMap
#[derive(Debug)]
struct DiskMap<K: hash::Hash + Eq, V> {
path: PathBuf,
cache: HashMap<K, V>,
transient: bool,
}
impl<K: hash::Hash + Eq, V> ops::Deref for DiskMap<K, V> {
type Target = HashMap<K, V>;
fn deref(&self) -> &Self::Target {
&self.cache
}
}
impl<K: hash::Hash + Eq, V> ops::DerefMut for DiskMap<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cache
}
}
impl<K: hash::Hash + Eq, V> DiskMap<K, V> {
pub fn new(path: String, file_name: String) -> Self {
trace!(target: "diskmap", "new({})", path);
let mut path: PathBuf = path.into();
path.push(file_name);
trace!(target: "diskmap", "path={:?}", path);
DiskMap {
path: path,
cache: HashMap::new(),
transient: false,
}
}
pub fn transient() -> Self {
let mut map = DiskMap::new(Default::default(), "diskmap.json".into());
map.transient = true;
map
}
fn revert<F, E>(&mut self, read: F) where
F: Fn(fs::File) -> Result<HashMap<K, V>, E>,
E: fmt::Display,
{
if self.transient { return; }
trace!(target: "diskmap", "revert {:?}", self.path);
let _ = fs::File::open(self.path.clone())
.map_err(|e| trace!(target: "diskmap", "Couldn't open disk map: {}", e))
.and_then(|f| read(f).map_err(|e| warn!(target: "diskmap", "Couldn't read disk map: {}", e)))
.and_then(|m| {
self.cache = m;
Ok(())
});
}
fn save<F, E>(&self, write: F) where
F: Fn(&HashMap<K, V>, &mut fs::File) -> Result<(), E>,
E: fmt::Display,
{
if self.transient { return; }
trace!(target: "diskmap", "save {:?}", self.path);
let _ = fs::File::create(self.path.clone())
.map_err(|e| warn!(target: "diskmap", "Couldn't open disk map for writing: {}", e))
.and_then(|mut f| {
write(&self.cache, &mut f).map_err(|e| warn!(target: "diskmap", "Couldn't write to disk map: {}", e))
});
}
}
#[cfg(test)]
mod tests {
use super::{AddressBook, DappsSettingsStore, DappsSettings};
use std::collections::HashMap;
use ethjson::misc::AccountMeta;
use devtools::RandomTempPath;
#[test]
fn should_save_and_reload_address_book() {
let temp = RandomTempPath::create_dir();
let path = temp.as_str().to_owned();
let mut b = AddressBook::new(path.clone());
b.set_name(1.into(), "One".to_owned());
b.set_meta(1.into(), "{1:1}".to_owned());
let b = AddressBook::new(path);
assert_eq!(b.get(), hash_map![1.into() => AccountMeta{name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None}]);
}
#[test]
fn should_save_and_reload_dapps_settings() {
// given
let temp = RandomTempPath::create_dir();
let path = temp.as_str().to_owned();
let mut b = DappsSettingsStore::new(path.clone());
// when
b.set_accounts("dappOne".into(), vec![1.into(), 2.into()]);
// then
let b = DappsSettingsStore::new(path);
assert_eq!(b.get(), hash_map![
"dappOne".into() => DappsSettings {
accounts: vec![1.into(), 2.into()],
}
]);
}
}

View File

@ -51,7 +51,7 @@ impl AccountMeta {
)
}
/// Write a hash map of Address -> AccountMeta.
/// Write a hash map of Address -> AccountMeta.
pub fn write_address_map<W>(m: &HashMap<util::Address, AccountMeta>, writer: &mut W) -> Result<(), serde_json::Error> where W: Write {
serde_json::to_writer(writer, &m.iter().map(|(a, m)| (a.clone().into(), m)).collect::<HashMap<hash::Address, _>>())
}

View File

@ -0,0 +1,51 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Dapps settings de/serialization.
use std::io;
use std::collections::HashMap;
use serde_json;
use hash;
type DappId = String;
/// Settings for specific dapp.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct DappsSettings {
/// A list of accounts this Dapp can see.
pub accounts: Vec<hash::Address>,
}
impl DappsSettings {
/// Read a hash map of DappId -> DappsSettings
pub fn read_dapps_settings<R, S>(reader: R) -> Result<HashMap<DappId, S>, serde_json::Error> where
R: io::Read,
S: From<DappsSettings> + Clone,
{
serde_json::from_reader(reader).map(|ok: HashMap<DappId, DappsSettings>|
ok.into_iter().map(|(a, m)| (a.into(), m.into())).collect()
)
}
/// Write a hash map of DappId -> DappsSettings
pub fn write_dapps_settings<W, S>(m: &HashMap<DappId, S>, writer: &mut W) -> Result<(), serde_json::Error> where
W: io::Write,
S: Into<DappsSettings> + Clone,
{
serde_json::to_writer(writer, &m.iter().map(|(a, m)| (a.clone().into(), m.clone().into())).collect::<HashMap<DappId, DappsSettings>>())
}
}

View File

@ -17,5 +17,7 @@
//! Misc deserialization.
mod account_meta;
mod dapps_settings;
pub use self::dapps_settings::DappsSettings;
pub use self::account_meta::AccountMeta;

View File

@ -44,8 +44,6 @@ extern crate serde_json;
extern crate rlp;
extern crate ethcore_hash_fetch as hash_fetch;
extern crate json_ipc_server as jsonipc;
extern crate ethcore_ipc_hypervisor as hypervisor;
extern crate ethcore_rpc;

View File

@ -19,14 +19,12 @@ use std::sync::Arc;
use std::net::SocketAddr;
use std::io;
use io::PanicHandler;
use ethcore_rpc::{RpcServerError, RpcServer as Server};
use jsonipc;
use ethcore_rpc::{RpcServerError, RpcServer as Server, IpcServerError};
use rpc_apis;
use rpc_apis::ApiSet;
use helpers::parity_ipc_path;
pub use jsonipc::Server as IpcServer;
pub use ethcore_rpc::Server as HttpServer;
pub use ethcore_rpc::{IpcServer, Server as HttpServer};
#[derive(Debug, PartialEq)]
pub struct HttpConfiguration {
@ -126,7 +124,7 @@ pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Result<Option<Ipc
pub fn setup_ipc_rpc_server(dependencies: &Dependencies, addr: &str, apis: ApiSet) -> Result<IpcServer, String> {
let server = try!(setup_rpc_server(apis, dependencies));
match server.start_ipc(addr) {
Err(jsonipc::Error::Io(io_error)) => Err(format!("RPC io error: {}", io_error)),
Err(IpcServerError::Io(io_error)) => Err(format!("RPC io error: {}", io_error)),
Err(any_error) => Err(format!("Rpc error: {:?}", any_error)),
Ok(server) => Ok(server)
}

View File

@ -12,8 +12,9 @@ build = "build.rs"
log = "0.3"
serde = "0.8"
serde_json = "0.8"
jsonrpc-core = "3.0"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-ipc-server = { git = "https://github.com/ethcore/jsonrpc.git" }
ethcore-io = { path = "../util/io" }
ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" }
@ -30,7 +31,6 @@ rustc-serialize = "0.3"
transient-hashmap = "0.1"
serde_macros = { version = "0.8.0", optional = true }
clippy = { version = "0.0.96", optional = true}
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
ethcore-ipc = { path = "../ipc/rpc" }
time = "0.1"

View File

@ -32,7 +32,7 @@ extern crate ethcrypto as crypto;
extern crate ethstore;
extern crate ethsync;
extern crate transient_hashmap;
extern crate json_ipc_server as ipc;
extern crate jsonrpc_ipc_server as ipc;
extern crate ethcore_ipc;
extern crate time;
extern crate rlp;
@ -51,8 +51,9 @@ extern crate ethcore_devtools as devtools;
use std::sync::Arc;
use std::net::SocketAddr;
use io::PanicHandler;
use self::jsonrpc_core::{IoHandler, IoDelegate};
use jsonrpc_core::{IoHandler, IoDelegate};
pub use ipc::{Server as IpcServer, Error as IpcServerError};
pub use jsonrpc_http_server::{ServerBuilder, Server, RpcServerError};
pub mod v1;
pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings};
@ -66,7 +67,7 @@ pub trait Extendable {
/// Http server.
pub struct RpcServer {
handler: Arc<jsonrpc_core::io::IoHandler>,
handler: Arc<IoHandler>,
}
impl Extendable for RpcServer {

View File

@ -20,7 +20,6 @@ extern crate ethash;
use std::io::{Write};
use std::process::{Command, Stdio};
use std::collections::BTreeSet;
use std::thread;
use std::time::{Instant, Duration};
use std::sync::{Arc, Weak};
@ -46,7 +45,7 @@ use self::ethash::SeedHashCompute;
use v1::traits::Eth;
use v1::types::{
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work, DappId,
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
};
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
@ -335,15 +334,15 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
Ok(RpcU256::from(default_gas_price(&*client, &*miner)))
}
fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
fn accounts(&self, id: Trailing<DappId>) -> Result<Vec<RpcH160>, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e)));
let addresses = try!(store.addresses_info().map_err(|e| errors::internal("Could not fetch accounts.", e)));
let dapp = id.0;
let set: BTreeSet<Address> = accounts.into_iter().chain(addresses.keys().cloned()).collect();
Ok(set.into_iter().map(Into::into).collect())
let store = take_weak!(self.accounts);
let accounts = try!(store.dapps_addresses(dapp.into()).map_err(|e| errors::internal("Could not fetch accounts.", e)));
Ok(accounts.into_iter().map(Into::into).collect())
}
fn block_number(&self) -> Result<RpcU256, Error> {

View File

@ -25,7 +25,7 @@ use ethcore::client::MiningBlockChainClient;
use jsonrpc_core::{Value, Error, to_value};
use v1::traits::ParityAccounts;
use v1::types::{H160 as RpcH160, H256 as RpcH256};
use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId};
use v1::helpers::errors;
/// Account management (personal) rpc implementation.
@ -143,6 +143,15 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
Ok(false)
}
fn set_dapps_addresses(&self, dapp: DappId, addresses: Vec<RpcH160>) -> Result<bool, Error> {
let store = take_weak!(self.accounts);
let addresses = addresses.into_iter().map(Into::into).collect();
store.set_dapps_addresses(dapp.into(), addresses)
.map_err(|e| errors::account("Couldn't set dapps addresses.", e))
.map(|_| true)
}
fn import_geth_accounts(&self, addresses: Vec<RpcH160>) -> Result<Vec<RpcH160>, Error> {
let store = take_weak!(self.accounts);

View File

@ -30,7 +30,7 @@ use devtools::RandomTempPath;
use util::Hashable;
use io::IoChannel;
use util::{U256, H256, Uint, Address};
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use ethjson::blockchain::BlockChain;
use v1::impls::{EthClient, SigningUnsafeClient};

View File

@ -31,7 +31,7 @@ use ethcore::transaction::{Transaction, Action};
use ethcore::miner::{ExternalMiner, MinerService};
use ethsync::SyncState;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Eth, EthClient, EthClientOptions, EthFilter, EthFilterClient, EthSigning, SigningUnsafeClient};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestSnapshotService};
@ -357,15 +357,15 @@ fn rpc_eth_accounts() {
let address = tester.accounts_provider.new_account("").unwrap();
let address2 = Address::default();
tester.accounts_provider.set_address_name(address2, "Test Account".into()).unwrap();
// even with some account it should return empty list (no dapp detected)
let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned()
+ &format!("0x{:?}", address2)
+ r#"",""#
+ &format!("0x{:?}", address)
+ r#""],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":[],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// when we add visible address it should return that.
tester.accounts_provider.set_dapps_addresses("app1".into(), vec![10.into()]).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": ["app1"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x000000000000000000000000000000000000000a"],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Net, NetClient};
use v1::tests::helpers::{Config, TestSyncProvider};

View File

@ -23,7 +23,7 @@ use ethcore::client::{TestBlockChainClient};
use ethcore::miner::LocalTransactionStatus;
use ethstore::ethkey::{Generator, Random};
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Parity, ParityClient};
use v1::helpers::{SignerService, NetworkSettings};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};

View File

@ -19,7 +19,7 @@ use std::sync::Arc;
use ethcore::account_provider::AccountProvider;
use ethcore::client::TestBlockChainClient;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{ParityAccounts, ParityAccountsClient};
struct ParityAccountsTester {
@ -116,3 +116,18 @@ fn should_be_able_to_set_meta() {
assert_eq!(res, Some(response));
}
#[test]
fn rpc_parity_set_dapps_accounts() {
// given
let tester = setup();
assert_eq!(tester.accounts.dapps_addresses("app1".into()).unwrap(), vec![]);
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappsAddresses","params":["app1",["0x000000000000000000000000000000000000000a"]], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// then
assert_eq!(tester.accounts.dapps_addresses("app1".into()).unwrap(), vec![10.into()]);
}

View File

@ -23,7 +23,7 @@ use ethcore::miner::MinerService;
use ethcore::client::TestBlockChainClient;
use ethsync::ManageNetwork;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{ParitySet, ParitySetClient};
use v1::tests::helpers::{TestMinerService, TestFetch};
use super::manage_network::TestManageNetwork;

View File

@ -16,7 +16,7 @@
use std::sync::Arc;
use std::str::FromStr;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use util::{U256, Uint, Address};
use ethcore::account_provider::AccountProvider;
use v1::{PersonalClient, Personal};

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeMap;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Rpc, RpcClient};

View File

@ -23,7 +23,7 @@ use ethcore::client::TestBlockChainClient;
use ethcore::transaction::{Transaction, Action};
use rlp::encode;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{SignerClient, Signer};
use v1::tests::helpers::TestMinerService;
use v1::helpers::{SigningQueue, SignerService, FilledTransactionRequest, ConfirmationPayload};

View File

@ -15,10 +15,10 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::str::FromStr;
use std::sync::Arc;
use std::sync::{mpsc, Arc};
use rlp;
use jsonrpc_core::{IoHandler, Success};
use jsonrpc_core::{IoHandler, Success, GenericIoHandler};
use v1::impls::SigningQueueClient;
use v1::traits::{EthSigning, ParitySigning, Parity};
use v1::helpers::{SignerService, SigningQueue};
@ -87,13 +87,16 @@ fn should_add_sign_to_queue() {
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","id":1}"#;
// then
let async_result = tester.io.handle_request(&request).unwrap();
let (tx, rx) = mpsc::channel();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(0.into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}
#[test]
@ -227,13 +230,16 @@ fn should_add_transaction_to_queue() {
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000","id":1}"#;
// then
let async_result = tester.io.handle_request(&request).unwrap();
let (tx, rx) = mpsc::channel();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SendTransaction(0.into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}
#[test]
@ -289,14 +295,17 @@ fn should_add_sign_transaction_to_the_queue() {
r#"}},"id":1}"#;
// then
let (tx, rx) = mpsc::channel();
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
let async_result = tester.io.handle_request(&request).unwrap();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction(t.into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}
#[test]
@ -387,11 +396,14 @@ fn should_add_decryption_to_the_queue() {
let response = r#"{"jsonrpc":"2.0","result":"0x0102","id":1}"#;
// then
let async_result = tester.io.handle_request(&request).unwrap();
let (tx, rx) = mpsc::channel();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use util::version;
use v1::{Web3, Web3Client};

View File

@ -17,7 +17,7 @@
//! Eth rpc interface.
use jsonrpc_core::Error;
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index, DappId};
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
use v1::types::{H64, H160, H256, U256};
@ -52,7 +52,7 @@ build_rpc_trait! {
/// Returns accounts list.
#[rpc(name = "eth_accounts")]
fn accounts(&self) -> Result<Vec<H160>, Error>;
fn accounts(&self, Trailing<DappId>) -> Result<Vec<H160>, Error>;
/// Returns highest block number.
#[rpc(name = "eth_blockNumber")]

View File

@ -19,7 +19,7 @@ use std::collections::BTreeMap;
use jsonrpc_core::{Value, Error};
use v1::helpers::auto_args::Wrap;
use v1::types::{H160, H256};
use v1::types::{H160, H256, DappId};
build_rpc_trait! {
/// Personal Parity rpc interface.
@ -61,10 +61,14 @@ build_rpc_trait! {
#[rpc(name = "parity_setAccountMeta")]
fn set_account_meta(&self, H160, String) -> Result<bool, Error>;
/// Returns accounts information.
/// Sets account visibility
#[rpc(name = "parity_setAccountVisiblity")]
fn set_account_visibility(&self, H160, H256, bool) -> Result<bool, Error>;
/// Sets accounts exposed for particular dapp.
#[rpc(name = "parity_setDappsAddresses")]
fn set_dapps_addresses(&self, DappId, Vec<H160>) -> Result<bool, Error>;
/// Imports a number of Geth accounts, with the list provided as the argument.
#[rpc(name = "parity_importGethAccounts")]
fn import_geth_accounts(&self, Vec<H160>) -> Result<Vec<H160>, Error>;

View File

@ -0,0 +1,60 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Dapp Id type
/// Dapplication Internal Id
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct DappId(pub String);
impl Into<String> for DappId {
fn into(self) -> String {
self.0
}
}
#[cfg(test)]
mod tests {
use serde_json;
use super::DappId;
#[test]
fn should_serialize_dapp_id() {
// given
let id = DappId("testapp".into());
// when
let res = serde_json::to_string(&id).unwrap();
// then
assert_eq!(res, r#""testapp""#);
}
#[test]
fn should_deserialize_dapp_id() {
// given
let id = r#""testapp""#;
// when
let res: DappId = serde_json::from_str(id).unwrap();
// then
assert_eq!(res, DappId("testapp".into()));
}
}

View File

@ -19,6 +19,7 @@ mod block;
mod block_number;
mod call_request;
mod confirmations;
mod dapp_id;
mod filter;
mod hash;
mod index;
@ -39,6 +40,7 @@ pub use self::block::{RichBlock, Block, BlockTransactions};
pub use self::block_number::BlockNumber;
pub use self::call_request::CallRequest;
pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, ConfirmationResponse, TransactionModification, SignRequest, DecryptRequest, Either};
pub use self::dapp_id::DappId;
pub use self::filter::{Filter, FilterChanges};
pub use self::hash::{H64, H160, H256, H512, H520, H2048};
pub use self::index::Index;

View File

@ -12,7 +12,7 @@ rustc_version = "0.1"
[dependencies]
rand = "0.3.14"
jsonrpc-core = "3.0"
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
log = "0.3"
env_logger = "0.3"
parity-dapps-glue = { version = "1.4", optional = true }

View File

@ -21,8 +21,8 @@ use authcode_store::AuthCodes;
use std::path::{PathBuf, Path};
use std::sync::Arc;
use std::str::FromStr;
use jsonrpc_core::IoHandler;
use util::{H256, Mutex, version};
use jsonrpc_core::{IoHandler, GenericIoHandler};
use util::{H256, version};
#[cfg(feature = "parity-ui")]
mod ui {
@ -130,7 +130,7 @@ fn add_headers(mut response: ws::Response, mime: &str) -> ws::Response {
}
pub struct Session {
out: Arc<Mutex<ws::Sender>>,
out: ws::Sender,
skip_origin_validation: bool,
self_origin: String,
authcodes_path: PathBuf,
@ -208,15 +208,15 @@ impl ws::Handler for Session {
fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
let req = try!(msg.as_text());
if let Some(async) = self.handler.handle_request(req) {
let out = self.out.clone();
async.on_result(move |result| {
let res = out.lock().send(result);
let out = self.out.clone();
self.handler.handle_request(req, move |response| {
if let Some(result) = response {
let res = out.send(result);
if let Err(e) = res {
warn!(target: "signer", "Error while sending response: {:?}", e);
}
});
}
}
});
Ok(())
}
}
@ -246,7 +246,7 @@ impl ws::Factory for Factory {
fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler {
Session {
out: Arc::new(Mutex::new(sender)),
out: sender,
handler: self.handler.clone(),
skip_origin_validation: self.skip_origin_validation,
self_origin: self.self_origin.clone(),

View File

@ -11,8 +11,8 @@ ethcore-ipc-codegen = { path = "../ipc/codegen" }
[dependencies]
log = "0.3"
json-tcp-server = { git = "https://github.com/ethcore/json-tcp-server" }
jsonrpc-core = "3.0"
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-tcp-server = { git = "https://github.com/ethcore/jsonrpc.git" }
mio = { git = "https://github.com/ethcore/mio", branch = "v0.5.x" }
ethcore-util = { path = "../util" }
ethcore-devtools = { path = "../devtools" }

View File

@ -16,7 +16,7 @@
//! Stratum protocol implementation for parity ethereum/bitcoin clients
extern crate json_tcp_server;
extern crate jsonrpc_tcp_server;
extern crate jsonrpc_core;
#[macro_use] extern crate log;
extern crate ethcore_util as util;
@ -44,7 +44,7 @@ pub use traits::{
RemoteWorkHandler, RemoteJobDispatcher,
};
use json_tcp_server::Server as JsonRpcServer;
use jsonrpc_tcp_server::Server as JsonRpcServer;
use jsonrpc_core::{IoHandler, Params, IoDelegate, to_value, from_params};
use std::sync::Arc;