use crate::core_types::{Coin, Msg};
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use serde::{Deserialize, Serialize};
use std::ops::Add;
#[derive(Deserialize, Serialize, Debug)]
pub struct MsgAggregateExchangeRatePreVote2 {
pub(crate) hash: String,
pub(crate) feeder: String,
pub(crate) validator: String,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct MsgAggregateExchangeRatePreVote {
#[serde(rename = "type")]
stype: String,
value: MsgAggregateExchangeRatePreVote2,
}
impl Msg for MsgAggregateExchangeRatePreVote {}
impl MsgAggregateExchangeRatePreVote {
pub fn create(
hash: String,
feeder: String,
validator: String,
) -> MsgAggregateExchangeRatePreVote {
let msg = MsgAggregateExchangeRatePreVote2 {
hash,
feeder,
validator,
};
MsgAggregateExchangeRatePreVote {
stype: String::from("oracle/MsgAggregateExchangeRatePrevote"),
value: msg,
}
}
}
#[derive(Deserialize, Serialize, Debug)]
pub struct MsgAggregateExchangeRateVote2 {
pub(crate) salt: String,
pub(crate) exchange_rates: Vec<Coin>,
pub(crate) feeder: String,
pub(crate) validator: String,
}
impl MsgAggregateExchangeRateVote2 {
fn generate_hash(&self) -> String {
let coins = self
.exchange_rates
.iter()
.map(|f| f.to_string())
.collect::<Vec<String>>()
.join(",");
generate_hash(&self.salt, coins, &self.validator)
}
}
fn generate_hash<'a>(salt: &'a str, exchange_string: String, validator: &'a str) -> String {
let mut sha = Sha256::new();
let mut to_hash: String = String::new();
to_hash = to_hash.add(salt);
to_hash = to_hash.add(":");
to_hash = to_hash.add(&exchange_string);
to_hash = to_hash.add(":");
to_hash = to_hash.add(validator);
sha.input_str(&to_hash);
let full_hash = sha.result_str();
full_hash.split_at(40).0.parse().unwrap()
}
#[derive(Deserialize, Serialize, Debug)]
pub struct MsgAggregateExchangeRateVote {
#[serde(rename = "type")]
stype: String,
value: MsgAggregateExchangeRateVote2,
}
impl MsgAggregateExchangeRateVote {
pub fn create(
salt: String,
exchange_rates: Vec<Coin>,
feeder: String,
validator: String,
) -> MsgAggregateExchangeRateVote {
let mut new_rates: Vec<Coin> = Vec::with_capacity(exchange_rates.len());
for rate in exchange_rates {
new_rates.push(rate);
}
new_rates.sort_by(|a, b| a.denom.cmp(&b.denom));
let msg = MsgAggregateExchangeRateVote2 {
salt,
exchange_rates: new_rates,
feeder,
validator,
};
MsgAggregateExchangeRateVote {
stype: String::from("oracle/MsgAggregateExchangeRateVote"),
value: msg,
}
}
fn generate_hash(&self) -> String {
self.value.generate_hash()
}
pub fn gen_pre_vote(&self) -> MsgAggregateExchangeRatePreVote {
MsgAggregateExchangeRatePreVote::create(
String::from(self.generate_hash()),
self.value.feeder.clone(),
self.value.validator.clone(),
)
}
}
#[cfg(test)]
mod tst {
use super::*;
use crate::errors::Result;
#[test]
pub fn test_agg() -> Result<()> {
let exchange_rate_str = "22.540203133218404887uaud,21.645596278923282692ucad,15.966787551658593971uchf,113.167767068332957759ucny,14.449845494375560683ueur,12.582839885411827405ugbp,135.474594500430895984uhkd,1300.213822842493250029uinr,1900.8256376511075722ujpy,20351.150811544637337767ukrw,49749.106615326838874584umnt,12.154984433357638529usdr,23.143090361112943758usgd,0.0uthb,17.444833658754882816uusd";
let exchange_rates = Coin::parse_coins(exchange_rate_str)?;
let salt = String::from("df59");
let feeder = String::from("terra1824vxwh43h9d3qczj4jvc3qphlf2evfp9w0ph9");
let validator = String::from("terravaloper1usws7c2c6cs7nuc8vma9qzaky5pkgvm2ujy8ny");
let hash = "36681b69da96623a6ae12c2a51448b7426fdd64e";
let coins = exchange_rates
.iter()
.map(|f| f.to_string())
.collect::<Vec<String>>()
.join(",");
assert_eq!(coins, exchange_rate_str);
assert_eq!(
generate_hash(&salt, exchange_rate_str.parse().unwrap(), &validator),
hash
);
let vote_1 = MsgAggregateExchangeRateVote::create(salt, exchange_rates, feeder, validator);
assert_eq!(vote_1.generate_hash(), hash);
let pre_vote = vote_1.gen_pre_vote();
assert_eq!(pre_vote.stype, "oracle/MsgAggregateExchangeRatePrevote");
Ok(())
}
#[test]
pub fn tst_hash() -> Result<()> {
let exchange_rates= "22.540203133218404887uaud,21.645596278923282692ucad,15.966787551658593971uchf,113.167767068332957759ucny,14.449845494375560683ueur,12.582839885411827405ugbp,135.474594500430895984uhkd,1300.213822842493250029uinr,1900.8256376511075722ujpy,20351.150811544637337767ukrw,49749.106615326838874584umnt,12.154984433357638529usdr,23.143090361112943758usgd,0.0uthb,17.444833658754882816uusd";
let salt = "df59";
let validator = "terravaloper1usws7c2c6cs7nuc8vma9qzaky5pkgvm2ujy8ny";
let hash = "36681b69da96623a6ae12c2a51448b7426fdd64e";
assert_eq!(
hash,
generate_hash(salt, exchange_rates.parse().unwrap(), validator)
);
let exchange_rates2="22.548222362821767308uaud,21.653297230216244188ucad,15.972468127589880034uchf,113.208029274598674692ucny,14.454986380997906048ueur,12.58731653903855345ugbp,135.522792907175522923uhkd,1300.676405771192471765uinr,1901.501902950678788445ujpy,20358.286256112132944846ukrw,49766.806079087327983387umnt,12.159308866922868479usdr,23.151324082621141584usgd,0.0uthb,17.451040085807700841uusd";
let salt2 = "6dd4";
let validator2 = "terravaloper1usws7c2c6cs7nuc8vma9qzaky5pkgvm2ujy8ny";
let hash2 = "54a849b1b3b510f5f0b7c5405ed2cc74cd283251";
assert_eq!(
hash2,
generate_hash(salt2, exchange_rates2.parse().unwrap(), validator2)
);
Ok(())
}
}