Skip to content

Commit

Permalink
drp xtndd
Browse files Browse the repository at this point in the history
  • Loading branch information
vsubhuman committed Nov 10, 2024
1 parent c55738a commit 28e49bd
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 7 deletions.
123 changes: 116 additions & 7 deletions rust/src/protocol_types/governance/drep.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::prelude::v1::Ok;
use crate::*;
use bech32::ToBase32;

Expand Down Expand Up @@ -29,6 +30,93 @@ pub enum DRepKind {
AlwaysNoConfidence,
}

#[wasm_bindgen]
#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub enum DRepExtendedId {
Key(Ed25519KeyHash),
Script(ScriptHash),
}

const DREP_CIP129_PREFIX_KEY: u8 = 34;
const DREP_CIP129_PREFIX_SCRIPT: u8 = 35;

#[wasm_bindgen]
impl DRepExtendedId {

pub fn from_bytes(data: &Vec<u8>) -> Result<DRepExtendedId, JsError> {
if data.len() != 29 {
return Err(JsError::from_str("Malformed DRep Extended ID (incorrect len)"));
}
let prefix = data.get(0)
.ok_or(JsError::from_str("Malformed DRep (unexpected failure to get bytes prefix)"))?;
match prefix {
&DREP_CIP129_PREFIX_KEY => return Ok(
DRepExtendedId::Key(
Ed25519KeyHash::from_bytes(data[1..].to_vec())
.map_err(|_| JsError::from_str("Malformed DRep KeyHash"))?,
)
),
&DREP_CIP129_PREFIX_SCRIPT => return Ok(
DRepExtendedId::Script(
ScriptHash::from_bytes(data[1..].to_vec())
.map_err(|_| JsError::from_str("Malformed DRep ScriptHash"))?,
)
),
_ => return Err(JsError::from_str("Malformed DRep Extended ID (incorrect prefix byte)"))
}
}

pub fn from_hex(hex_str: &str) -> Result<DRepExtendedId, JsError> {
DRepExtendedId::from_bytes(
&hex::decode(hex_str)
.map_err(|e| JsError::from_str(&e.to_string()))?
)
}

pub fn from_bech32(bech32_str: &str) -> Result<DRepExtendedId, JsError> {
let (hrp, u5data) =
bech32::decode(bech32_str).map_err(|e| JsError::from_str(&e.to_string()))?;
if hrp != "drep" {
return Err(JsError::from_str("Malformed DRep Extended ID (incorrect prefix)"));
}
let data: Vec<u8> = bech32::FromBase32::from_base32(&u5data)
.map_err(|e: bech32::Error| JsError::from_str(&format!("Malformed DRep base32: {}", &e.to_string())))?;
DRepExtendedId::from_bytes(&data)
}

pub fn to_hex(&self) -> String {
hex::encode(self.to_bytes())
}

pub fn to_bytes(&self) -> Vec<u8> {
let (prefix, data) = match self {
DRepExtendedId::Key(keyhash) => (DREP_CIP129_PREFIX_KEY, keyhash.to_bytes()),
DRepExtendedId::Script(scripthash) => (DREP_CIP129_PREFIX_SCRIPT, scripthash.to_bytes()),
};
let mut res = vec![prefix];
res.extend(data);
res
}

pub fn to_bech32(&self) -> Result<String, JsError> {
bech32::encode("drep", self.to_bytes().to_base32()).map_err(|e| JsError::from_str(&format! {"{:?}", e}))
}

pub fn kind(&self) -> DRepKind {
match self {
DRepExtendedId::Key(_) => DRepKind::KeyHash,
DRepExtendedId::Script(_) => DRepKind::ScriptHash,
}
}

pub fn to_drep(&self) -> DRep {
match self {
DRepExtendedId::Key(key) => DRep(DRepEnum::KeyHash(key.clone())),
DRepExtendedId::Script(script) => DRep(DRepEnum::ScriptHash(script.clone())),
}
}
}

#[derive(
Clone,
Debug,
Expand Down Expand Up @@ -95,9 +183,17 @@ impl DRep {
}
}

pub fn to_bech32(&self) -> Result<String, JsError> {
pub fn to_extended_id(&self) -> Option<DRepExtendedId> {
match &self.0 {
DRepEnum::KeyHash(x) => Some(DRepExtendedId::Key(x.clone())),
DRepEnum::ScriptHash(x) => Some(DRepExtendedId::Script(x.clone())),
_ => None
}
}

fn internal_to_bech32(&self, vkh_prefix: String) -> Result<String, JsError> {
let (hrp, data) = match &self.0 {
DRepEnum::KeyHash(keyhash) => Ok(("drep", keyhash.to_bytes())),
DRepEnum::KeyHash(keyhash) => Ok((vkh_prefix.as_str(), keyhash.to_bytes())),
DRepEnum::ScriptHash(scripthash) => Ok(("drep_script", scripthash.to_bytes())),
DRepEnum::AlwaysAbstain => {
Err(JsError::from_str("Cannot convert AlwaysAbstain to bech32"))
Expand All @@ -109,23 +205,36 @@ impl DRep {
bech32::encode(&hrp, data.to_base32()).map_err(|e| JsError::from_str(&format! {"{:?}", e}))
}

pub fn to_bech32(&self) -> Result<String, JsError> {
self.internal_to_bech32("drep".to_string())
}

pub fn to_bech32_cip129(&self) -> Result<String, JsError> {
self.internal_to_bech32("drep_vkh".to_string())
}

pub fn from_bech32(bech32_str: &str) -> Result<DRep, JsError> {
let (hrp, u5data) =
bech32::decode(bech32_str).map_err(|e| JsError::from_str(&e.to_string()))?;
let data: Vec<u8> = bech32::FromBase32::from_base32(&u5data)
.map_err(|_| JsError::from_str("Malformed DRep"))?;
.map_err(|e: bech32::Error| JsError::from_str(&format!("Malformed DRep base32: {}", &e.to_string())))?;
let kind = match hrp.as_str() {
"drep" => DRepKind::KeyHash,
"drep" => match data.len() {
28 => DRepKind::KeyHash, // pre cip129 compatibility
29 => return DRepExtendedId::from_bech32(bech32_str).and_then(|id| Ok(id.to_drep())),
_ => return Err(JsError::from_str("Malformed DRep (drep1 byte len)"))
},
"drep_vkh" => DRepKind::KeyHash,
"drep_script" => DRepKind::ScriptHash,
_ => return Err(JsError::from_str("Malformed DRep")),
_ => return Err(JsError::from_str("Malformed DRep (bech prefix)")),
};
let drep = match kind {
DRepKind::KeyHash => DRepEnum::KeyHash(
Ed25519KeyHash::from_bytes(data)
.map_err(|_| JsError::from_str("Malformed DRep"))?,
.map_err(|_| JsError::from_str("Malformed DRep KeyHash"))?,
),
DRepKind::ScriptHash => DRepEnum::ScriptHash(
ScriptHash::from_bytes(data).map_err(|_| JsError::from_str("Malformed DRep"))?,
ScriptHash::from_bytes(data).map_err(|_| JsError::from_str("Malformed DRep ScriptHash"))?,
),
DRepKind::AlwaysAbstain => DRepEnum::AlwaysAbstain,
DRepKind::AlwaysNoConfidence => DRepEnum::AlwaysNoConfidence,
Expand Down
53 changes: 53 additions & 0 deletions rust/src/tests/protocol_types/governance/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,56 @@ fn voting_procedures_setters_getters_test() {
assert!(governance_action_ids_2.0.contains(&governance_action_id_2));
assert!(governance_action_ids_2.0.contains(&governance_action_id_3));
}

#[test]
fn drep_bech32_129_parsing_key_test() {
let drep1 = DRep::from_bech32("drep1uz9v5d3vzyp3xwh8y2ceswqxqx4ljecfwd2kwnjysjapzh3avs7").unwrap();
let drep2 = DRep::from_bech32("drep1ytsg4j3k9sgsxye6uu3trxpcqcq6h7t8p9e42e6wgjzt5yggls86y").unwrap();
assert_eq!(drep1.kind(), DRepKind::KeyHash);
assert_eq!(drep2.kind(), DRepKind::KeyHash);
assert_eq!(drep1.to_key_hash().unwrap(), drep2.to_key_hash().unwrap());
}

#[test]
fn drep_bech32_129_parsing_script_test() {
let drep1 = DRep::from_bech32("drep_script1dja6lg0xdt4tfrd7r2svc3ywh5xqrl6w85axjp0gtdu6xw6h2wn").unwrap();
let drep2 = DRep::from_bech32("drep1ydkthtapue4w4dydhcd2pnzy367scq0lfc7n56g9apdhngcaf8d6w").unwrap();
assert_eq!(drep1.kind(), DRepKind::ScriptHash);
assert_eq!(drep2.kind(), DRepKind::ScriptHash);
assert_eq!(drep1.to_script_hash().unwrap(), drep2.to_script_hash().unwrap());

}

#[test]
fn drep_bech32_129_to_bech() {
let drep1 = DRep::from_bech32("drep1uz9v5d3vzyp3xwh8y2ceswqxqx4ljecfwd2kwnjysjapzh3avs7").unwrap();
let drep2 = DRep::from_bech32("drep_script1dja6lg0xdt4tfrd7r2svc3ywh5xqrl6w85axjp0gtdu6xw6h2wn").unwrap();
assert_eq!(drep1.to_bech32().unwrap(), "drep1uz9v5d3vzyp3xwh8y2ceswqxqx4ljecfwd2kwnjysjapzh3avs7");
assert_eq!(drep1.to_bech32_cip129().unwrap(), "drep_vkh1uz9v5d3vzyp3xwh8y2ceswqxqx4ljecfwd2kwnjysjapz3kx3ey");
assert_eq!(drep2.to_bech32().unwrap(), "drep_script1dja6lg0xdt4tfrd7r2svc3ywh5xqrl6w85axjp0gtdu6xw6h2wn");
assert_eq!(drep2.to_bech32_cip129().unwrap(), "drep_script1dja6lg0xdt4tfrd7r2svc3ywh5xqrl6w85axjp0gtdu6xw6h2wn");
}

#[test]
fn drep_bech32_129_extended_id() {
let drep1 = DRep::from_bech32("drep_vkh1uz9v5d3vzyp3xwh8y2ceswqxqx4ljecfwd2kwnjysjapz3kx3ey").unwrap();
let drep2 = DRep::from_bech32("drep_script1dja6lg0xdt4tfrd7r2svc3ywh5xqrl6w85axjp0gtdu6xw6h2wn").unwrap();
assert_eq!(drep1.to_extended_id().unwrap().to_bech32().unwrap(), "drep1ytsg4j3k9sgsxye6uu3trxpcqcq6h7t8p9e42e6wgjzt5yggls86y");
assert_eq!(drep1.to_extended_id().unwrap().to_hex(), "22e08aca362c1103133ae722b198380601abf967097355674e4484ba11");
assert_eq!(drep2.to_extended_id().unwrap().to_bech32().unwrap(), "drep1ydkthtapue4w4dydhcd2pnzy367scq0lfc7n56g9apdhngcaf8d6w");
assert_eq!(drep2.to_extended_id().unwrap().to_hex(), "236cbbafa1e66aeab48dbe1aa0cc448ebd0c01ff4e3d3a6905e85b79a3");
assert_eq!(DRep::new_always_abstain().to_extended_id(), None);
assert_eq!(DRep::new_always_no_confidence().to_extended_id(), None);
}

#[test]
fn drep_bech32_129_extended_id_hex_and_bytes() {
let bech1 = "drep1ytsg4j3k9sgsxye6uu3trxpcqcq6h7t8p9e42e6wgjzt5yggls86y";
let bech2 = "drep1ydkthtapue4w4dydhcd2pnzy367scq0lfc7n56g9apdhngcaf8d6w";
let drep1 = DRepExtendedId::from_bech32(bech1).unwrap();
let drep2 = DRepExtendedId::from_bech32(bech2).unwrap();
assert_eq!(DRepExtendedId::from_bytes(&drep1.to_bytes()).unwrap().to_bech32().unwrap(), bech1);
assert_eq!(DRepExtendedId::from_bytes(&drep2.to_bytes()).unwrap().to_bech32().unwrap(), bech2);
assert_eq!(DRepExtendedId::from_hex(&drep1.to_hex()).unwrap().to_bech32().unwrap(), bech1);
assert_eq!(DRepExtendedId::from_hex(&drep2.to_hex()).unwrap().to_bech32().unwrap(), bech2);
}

0 comments on commit 28e49bd

Please sign in to comment.