Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #566: serialize commit to hex #574

Merged
merged 2 commits into from
Jan 29, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
174 changes: 151 additions & 23 deletions api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,25 @@ use std::sync::Arc;
use core::{core, ser};
use core::core::hash::Hashed;
use core::core::SumCommit;
use core::core::SwitchCommitHash;
use chain;
use p2p;
use util;
use util::secp::pedersen;
use util::secp::constants::MAX_PROOF_SIZE;
use serde;
use serde::ser::SerializeStruct;
use serde::de::MapAccess;
use std::fmt;
use serde_json;

macro_rules! no_dup {
($field: ident) => {
if $field.is_some() {
return Err(serde::de::Error::duplicate_field("$field"));
}
};
}

/// The state of the current fork tip
#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -163,19 +177,19 @@ impl Utxo {
}

// As above, except formatted a bit better for human viewing
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Clone)]
pub struct OutputPrintable {
/// The type of output Coinbase|Transaction
pub output_type: OutputType,
/// The homomorphic commitment representing the output's amount
/// (as hex string)
pub commit: String,
pub commit: pedersen::Commitment,
/// switch commit hash
pub switch_commit_hash: String,
pub switch_commit_hash: SwitchCommitHash,
/// Whether the output has been spent
pub spent: bool,
/// Rangeproof (as hex string)
pub proof: Option<String>,
pub proof: Option<pedersen::RangeProof>,
/// Rangeproof hash (as hex string)
pub proof_hash: String,
}
Expand All @@ -197,44 +211,143 @@ impl OutputPrintable {
let spent = chain.is_unspent(&out_id).is_err();

let proof = if include_proof {
Some(util::to_hex(output.proof.bytes().to_vec()))
Some(output.proof)
} else {
None
};

OutputPrintable {
output_type: output_type,
commit: util::to_hex(output.commit.0.to_vec()),
switch_commit_hash: output.switch_commit_hash.to_hex(),
spent: spent,
proof: proof,
output_type,
commit: output.commit,

This comment was marked as spam.

switch_commit_hash: output.switch_commit_hash,
spent,
proof,
proof_hash: util::to_hex(output.proof.hash().to_vec()),
}
}

// Convert the hex string back into a switch_commit_hash instance
pub fn switch_commit_hash(&self) -> Result<core::SwitchCommitHash, ser::Error> {
core::SwitchCommitHash::from_hex(&self.switch_commit_hash)
Ok(self.switch_commit_hash.clone())
}

pub fn commit(&self) -> Result<pedersen::Commitment, ser::Error> {
let vec = util::from_hex(self.commit.clone())
.map_err(|_| ser::Error::HexError(format!("output commit hex_error")))?;
Ok(pedersen::Commitment::from_vec(vec))
Ok(self.commit.clone())
}

pub fn range_proof(&self) -> Result<pedersen::RangeProof, ser::Error> {
if let Some(ref proof) = self.proof {
let vec = util::from_hex(proof.clone())
.map_err(|_| ser::Error::HexError(format!("output range_proof hex_error")))?;
let mut bytes = [0; MAX_PROOF_SIZE];
for i in 0..vec.len() {
bytes[i] = vec[i];
self.proof.clone().ok_or_else(|| ser::Error::HexError(format!("output range_proof missing")))
}
}

impl serde::ser::Serialize for OutputPrintable {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
S: serde::ser::Serializer {
let mut state = serializer.serialize_struct("OutputPrintable", 6)?;
state.serialize_field("output_type", &self.output_type)?;
state.serialize_field("commit", &util::to_hex(self.commit.0.to_vec()))?;
state.serialize_field("switch_commit_hash", &self.switch_commit_hash.to_hex())?;
state.serialize_field("spent", &self.spent)?;
state.serialize_field("proof", &self.proof)?;
state.serialize_field("proof_hash", &self.proof_hash)?;
state.end()
}
}

impl<'de> serde::de::Deserialize<'de> for OutputPrintable {

This comment was marked as spam.

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where
D: serde::de::Deserializer<'de> {
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "snake_case")]
enum Field {
OutputType,
Commit,
SwitchCommitHash,
Spent,
Proof,
ProofHash
}

struct OutputPrintableVisitor;

impl<'de> serde::de::Visitor<'de> for OutputPrintableVisitor {
type Value = OutputPrintable;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a print able Output")
}

fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> where
A: MapAccess<'de>, {
let mut output_type = None;
let mut commit = None;
let mut switch_commit_hash = None;
let mut spent = None;
let mut proof = None;
let mut proof_hash = None;

while let Some(key) = map.next_key()? {
match key {
Field::OutputType => {
no_dup!(output_type);
output_type = Some(map.next_value()?)
},
Field::Commit => {
no_dup!(commit);

let val: String = map.next_value()?;
let vec = util::from_hex(val.clone())
.map_err(serde::de::Error::custom)?;
commit = Some(pedersen::Commitment::from_vec(vec));
},
Field::SwitchCommitHash => {
no_dup!(switch_commit_hash);

let val: &str = map.next_value()?;
let hash = core::SwitchCommitHash::from_hex(val.clone())
.map_err(serde::de::Error::custom)?;
switch_commit_hash = Some(hash)
},
Field::Spent => {
no_dup!(spent);
spent = Some(map.next_value()?)
},
Field::Proof => {
no_dup!(proof);

let val: Option<String> = map.next_value()?;

if val.is_some() {
let vec = util::from_hex(val.unwrap().clone())
.map_err(serde::de::Error::custom)?;
let mut bytes = [0; MAX_PROOF_SIZE];
for i in 0..vec.len() {
bytes[i] = vec[i];
}

proof = Some(pedersen::RangeProof { proof: bytes, plen: vec.len() })
}
},
Field::ProofHash => {
no_dup!(proof_hash);
proof_hash = Some(map.next_value()?)
}
}
}

Ok(OutputPrintable {
output_type: output_type.unwrap(),
commit: commit.unwrap(),
switch_commit_hash: switch_commit_hash.unwrap(),
spent: spent.unwrap(),
proof: proof,
proof_hash: proof_hash.unwrap()
})
}
Ok(pedersen::RangeProof { proof: bytes, plen: vec.len() })
} else {
Err(ser::Error::HexError(format!("output range_proof missing")))
}

const FIELDS: &'static [&'static str] = &["output_type", "commit", "switch_commit_hash", "spent", "proof", "proof_hash"];
deserializer.deserialize_struct("OutputPrintable", FIELDS, OutputPrintableVisitor)
}
}

Expand Down Expand Up @@ -429,3 +542,18 @@ pub struct PoolInfo {
/// Total size of pool + orphans
pub total_size: usize,
}

#[test]
fn serialize_printable_commitment() {
let hex_output = "{\
\"output_type\":\"Coinbase\",\
\"commit\":\"083eafae5d61a85ab07b12e1a51b3918d8e6de11fc6cde641d54af53608aa77b9f\",\
\"switch_commit_hash\":\"85daaf11011dc11e52af84ebe78e2f2d19cbdc76000000000000000000000000\",\

This comment was marked as spam.

\"spent\":false,\
\"proof\":null,\
\"proof_hash\":\"ed6ba96009b86173bade6a9227ed60422916593fa32dd6d78b25b7a4eeef4946\"\
}";
let deserialized: OutputPrintable = serde_json::from_str(&hex_output).unwrap();
let serialized = serde_json::to_string(&deserialized).unwrap();
assert_eq!(serialized, hex_output);
}
5 changes: 1 addition & 4 deletions wallet/src/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,7 @@ fn refresh_missing_block_hashes(config: &WalletConfig, keychain: &Keychain) -> R
Ok(blocks) => {
for block in blocks {
for out in block.outputs {
if let Ok(c) = util::from_hex(String::from(out.commit)) {
let commit = pedersen::Commitment::from_vec(c);
api_blocks.insert(commit, block.header.clone());
}
api_blocks.insert(out.commit, block.header.clone());
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions wallet/src/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

use keychain::{Keychain, Identifier};
use util::{LOGGER, from_hex};
use util::{LOGGER, to_hex};
use util::secp::pedersen;
use api;
use core::global;
Expand Down Expand Up @@ -175,13 +175,13 @@ fn find_utxos_with_key(
);

// add it to result set here
let commit_id = from_hex(output.commit.clone()).unwrap();
let commit_id = output.commit.0;

let res = retrieve_amount_and_coinbase_status(
config,
keychain,
key_id.clone(),
&output.commit,
&to_hex(output.commit.0.to_vec()),
block_outputs.header.height,
);

Expand Down