Skip to content

Commit

Permalink
Merge pull request #51 from commerceblock/feature/responseModel
Browse files Browse the repository at this point in the history
Improve Response model
  • Loading branch information
Nikos Kostoulas authored Nov 12, 2019
2 parents af66b81 + 2d03391 commit bf41c18
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 93 deletions.
29 changes: 11 additions & 18 deletions scripts/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# First connection to a local Ocean node is made, the request data for a
# txid is found via getrequest RPC and fee size is calculated.
# Then getrequestresponses RPC is called to get challenge responses which can be
# Then getrequestresponse RPC is called to get challenge responses which can be
# used to determine rewards for guardnodes.

#!/usr/bin/env python3
Expand Down Expand Up @@ -82,9 +82,9 @@ def calculate_fees(rpc, start_height, end_height):
return fee

addr_prefix = 235
txid = "78f954d07de5badbc1526a60fe0ea639216f17f490a3bf41e48840453eca243f"
url = 'https://userApi:passwordApi@coordinator-api.testnet.commerceblock.com:10006'
rpc = connect("ocean", "oceanpass", "localhost", "7043")
txid = "6e993034df3203c0867c98f420f85b5ffecd7cb8580e2b6f2d33764e1cbfb074"
url = 'http://userApi:passwordApi@localhost:3333'
rpc = connect("user1", "password1", "localhost", "5555")

payload = '{{"jsonrpc": "2.0", "method": "getrequest", "params": {{"txid": "{}"}}, "id": 1}}'.format(txid)
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
Expand All @@ -98,11 +98,8 @@ def calculate_fees(rpc, start_height, end_height):
print("")

print("Calculating total fees...")
# For requests that are serving the service chain the fee start/end heights
# can be picked up from the request information. For requests in client chains
# these heights need to be found manually and inserted below to calculate fees
fee_start_height = request['start_blockheight']
fee_end_height = request['end_blockheight']
fee_start_height = request['start_blockheight_clientchain']
fee_end_height = request['end_blockheight_clientchain']
fee = calculate_fees(rpc, fee_start_height, fee_end_height)
fee_percentage = request['fee_percentage']
fee_out = fee*fee_percentage/100
Expand All @@ -120,21 +117,17 @@ def calculate_fees(rpc, start_height, end_height):
fee_per_guard = float(fee_out/len(bids))
print("")

payload = '{{"jsonrpc": "2.0", "method": "getrequestresponses", "params": {{"txid": "{}"}}, "id": 1}}'.format(txid)
payload = '{{"jsonrpc": "2.0", "method": "getrequestresponse", "params": {{"txid": "{}"}}, "id": 1}}'.format(txid)
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
r = requests.post(url, data=payload, headers=headers)

result = json.loads(json.loads(r.content)['result'])
challenge_resps = result["responses"]
num_of_challenges = len(challenge_resps)
challenge_resps = result["response"]
num_of_challenges = challenge_resps["num_challenges"]
print("Number of challenges: {}".format(num_of_challenges))
resps = {}
for challenge_resp in challenge_resps:
for bid_resp in challenge_resp:
if bid_resp in resps:
resps[bid_resp] += (1/num_of_challenges)
else:
resps[bid_resp] = (1/num_of_challenges)
for (bid, resp_num) in challenge_resps["bid_responses"].items():
resps[bid] = resp_num / num_of_challenges

print("Results")
for bid, key in bids.items():
Expand Down
50 changes: 36 additions & 14 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use jsonrpc_http_server::jsonrpc_core::{Error, ErrorCode, IoHandler, Params, Val
use jsonrpc_http_server::{hyper::header, AccessControlAllowOrigin, DomainsValidation, Response, ServerBuilder};
use serde::{Deserialize, Serialize};

use crate::challenger::ChallengeResponseIds;
use crate::config::ApiConfig;
use crate::request::{BidSet, Request as ServiceRequest};
use crate::response::Response as ChallengeResponse;
use crate::storage::Storage;

#[derive(Deserialize, Debug)]
Expand Down Expand Up @@ -74,19 +74,27 @@ struct GetRequestResponsesParams {
}

#[derive(Serialize, Debug)]
struct GetRequestResponsesResponse {
responses: Vec<ChallengeResponseIds>,
struct GetRequestResponseResponse {
response: ChallengeResponse,
}

/// Get requests responses RPC call returning all responses for a specific
/// request transaction id hash
fn get_request_responses(params: Params, storage: Arc<dyn Storage>) -> futures::Finished<Value, Error> {
fn get_request_response(params: Params, storage: Arc<dyn Storage>) -> futures::Finished<Value, Error> {
let try_parse = params.parse::<GetRequestResponsesParams>();
match try_parse {
Ok(parse) => {
let responses = storage.get_responses(parse.txid).unwrap();
let res_serialized = serde_json::to_string(&GetRequestResponsesResponse { responses }).unwrap();
return futures::finished(Value::String(res_serialized));
let response_get = storage.get_response(parse.txid).unwrap();
if let Some(response) = response_get {
let res_serialized = serde_json::to_string(&GetRequestResponseResponse { response }).unwrap();
return futures::finished(Value::String(res_serialized));
} else {
return futures::failed(Error {
code: ErrorCode::InvalidParams,
message: "Invalid params: `txid` does not exist.".to_string(),
data: None,
});
}
}
Err(e) => return futures::failed(e),
}
Expand Down Expand Up @@ -119,8 +127,8 @@ pub fn run_api_server<D: Storage + Send + Sync + 'static>(
) -> thread::JoinHandle<()> {
let mut io = IoHandler::default();
let storage_ref = storage.clone();
io.add_method("getrequestresponses", move |params: Params| {
get_request_responses(params, storage_ref.clone())
io.add_method("getrequestresponse", move |params: Params| {
get_request_response(params, storage_ref.clone())
});
let storage_ref = storage.clone();
io.add_method("getrequest", move |params: Params| {
Expand Down Expand Up @@ -161,6 +169,7 @@ mod tests {

use futures::Future;

use crate::challenger::ChallengeResponseIds;
use crate::util::testing::{gen_challenge_state, gen_dummy_hash, MockStorage};

#[test]
Expand Down Expand Up @@ -228,18 +237,28 @@ mod tests {
}

#[test]
fn get_request_responses_test() {
fn get_request_response_test() {
let storage = Arc::new(MockStorage::new());
let dummy_hash = gen_dummy_hash(1);
let dummy_hash_bid = gen_dummy_hash(2);

// no such request
let s = format!(r#"{{"txid": "{}"}}"#, dummy_hash.to_string());
let params: Params = serde_json::from_str(&s).unwrap();
let resp = get_request_response(params, storage.clone());
assert_eq!(
"Invalid params: `txid` does not exist.",
resp.wait().unwrap_err().message
);

let mut dummy_response_set = ChallengeResponseIds::new();
let _ = dummy_response_set.insert(dummy_hash_bid);
let _ = storage.save_response(dummy_hash, &dummy_response_set);

// invalid key
let s = format!(r#"{{"hash": "{}"}}"#, dummy_hash.to_string());
let params: Params = serde_json::from_str(&s).unwrap();
let resp = get_request_responses(params, storage.clone());
let resp = get_request_response(params, storage.clone());
assert_eq!(
"Invalid params: missing field `txid`.",
resp.wait().unwrap_err().message
Expand All @@ -248,7 +267,7 @@ mod tests {
// invalid value
let s = format!(r#"{{"txid": "{}a"}}"#, dummy_hash.to_string());
let params: Params = serde_json::from_str(&s).unwrap();
let resp = get_request_responses(params, storage.clone());
let resp = get_request_response(params, storage.clone());
assert_eq!(
"Invalid params: bad hex string length 65 (expected 64).",
resp.wait().unwrap_err().message
Expand All @@ -257,9 +276,12 @@ mod tests {
// valid key and value
let s = format!(r#"{{"txid": "{}"}}"#, dummy_hash.to_string());
let params: Params = serde_json::from_str(&s).unwrap();
let resp = get_request_responses(params, storage.clone());
let resp = get_request_response(params, storage.clone());
assert_eq!(
format!("{{\"responses\":[[\"{}\"]]}}", dummy_hash_bid.to_string()),
format!(
r#"{{"response":{{"num_challenges":1,"bid_responses":{{"{}":1}}}}}}"#,
dummy_hash_bid.to_string()
),
resp.wait().unwrap()
);
}
Expand Down
21 changes: 13 additions & 8 deletions src/challenger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ mod tests {
use std::sync::mpsc::{channel, Receiver, Sender};

use crate::error::Error;
use crate::response::Response;
use crate::util::testing::{gen_dummy_hash, MockClientChain, MockService, MockStorage};

#[test]
Expand Down Expand Up @@ -398,14 +399,14 @@ mod tests {
storage.clone(),
time::Duration::from_millis(10),
time::Duration::from_millis(10),
3,
50,
time::Duration::from_millis(10),
);

match res {
Ok(_) => {
let resps = storage.get_responses(dummy_request.txid).unwrap();
assert_eq!(1, resps.len());
let resps = storage.get_response(dummy_request.txid).unwrap();
assert_eq!(resps, None);
let bids = storage.get_bids(dummy_request.txid).unwrap();
assert_eq!(challenge_state.bids, bids);
let requests = storage.get_requests().unwrap();
Expand Down Expand Up @@ -440,11 +441,15 @@ mod tests {

match res {
Ok(_) => {
let resps = storage.get_responses(dummy_request.txid).unwrap();
assert_eq!(5, resps.len());
assert_eq!(1, resps[1].len());
assert_eq!(dummy_bid.txid, *resps[1].iter().next().unwrap());
assert_eq!(5, storage.challenge_responses.borrow().len());
let resps = storage.get_response(dummy_request.txid).unwrap();
assert_eq!(
resps.unwrap(),
Response {
num_challenges: 4,
bid_responses: [(dummy_bid.txid, 1)].iter().cloned().collect()
}
);
assert_eq!(1, storage.challenge_responses.borrow().len());
let bids = storage.get_bids(dummy_request.txid).unwrap();
assert_eq!(challenge_state.bids, bids);
let requests = storage.get_requests().unwrap();
Expand Down
6 changes: 3 additions & 3 deletions src/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ pub fn run(config: Config) -> Result<()> {
loop {
if let Some(request_id) = run_request(&config, &service, &clientchain, storage.clone(), genesis_hash)? {
// if challenge request succeeds print responses
println! {"***** Responses *****"}
let resp = storage.get_responses(request_id).unwrap();
println! {"{}", serde_json::to_string_pretty(&resp).unwrap()};
info! {"***** Response *****"}
let resp = storage.get_response(request_id)?.unwrap();
info! {"{}", serde_json::to_string_pretty(&resp).unwrap()};
}
info! {"Sleeping for {} sec...", config.block_time}
thread::sleep(time::Duration::from_secs(config.block_time))
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub mod error;
pub mod listener;
pub mod ocean;
pub mod request;
pub mod response;
pub mod service;
pub mod storage;
/// utilities
Expand Down
39 changes: 39 additions & 0 deletions src/response.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! # Response
//!
//! Response model for service challenge responses
use std::collections::HashMap;

use crate::challenger::ChallengeResponseIds;
use bitcoin_hashes::sha256d;
use serde::Serialize;

/// Response struct that models responses to service challenges
/// by keeping track of the total number of challengers and the
/// number of challenges that each bid owner responded to
#[derive(Debug, Serialize, PartialEq)]
pub struct Response {
/// Total number of challenges
pub num_challenges: u32,
/// Number of responses per bid txid
pub bid_responses: HashMap<sha256d::Hash, u32>,
}

impl Response {
/// Create new Response instance
pub fn new() -> Response {
Response {
num_challenges: 0,
bid_responses: HashMap::new(),
}
}

/// Update Response struct from challenge response ids
pub fn update(&mut self, responses: &ChallengeResponseIds) {
self.num_challenges += 1;
for txid in responses.iter() {
let bid_entry = self.bid_responses.entry(*txid).or_insert(0);
*bid_entry += 1;
}
}
}
Loading

0 comments on commit bf41c18

Please sign in to comment.