Render byte slices as hex more often in `Debug` impls
This is more generally useful for debugging purposes than the default `Debug` impl for `&[u8]`. We also provide an alternate `Debug` impl for `legacy::Script` that parses and renders known opcodes. Note that we only parse a subset of the full opcode set.
This commit is contained in:
parent
57a3914e3a
commit
c8e2d81f58
|
@ -19,6 +19,8 @@
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
// TODO: #![deny(missing_docs)]
|
// TODO: #![deny(missing_docs)]
|
||||||
|
|
||||||
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
@ -72,9 +74,28 @@ impl AsRef<[u8]> for OutgoingCipherKey {
|
||||||
/// Newtype representing the byte encoding of an [`EphemeralPublicKey`].
|
/// Newtype representing the byte encoding of an [`EphemeralPublicKey`].
|
||||||
///
|
///
|
||||||
/// [`EphemeralPublicKey`]: Domain::EphemeralPublicKey
|
/// [`EphemeralPublicKey`]: Domain::EphemeralPublicKey
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct EphemeralKeyBytes(pub [u8; 32]);
|
pub struct EphemeralKeyBytes(pub [u8; 32]);
|
||||||
|
|
||||||
|
impl fmt::Debug for EphemeralKeyBytes {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
struct HexFmt<'b>(&'b [u8]);
|
||||||
|
impl<'b> fmt::Debug for HexFmt<'b> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_char('"')?;
|
||||||
|
for b in self.0 {
|
||||||
|
f.write_fmt(format_args!("{:02x}", b))?;
|
||||||
|
}
|
||||||
|
f.write_char('"')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_tuple("EphemeralKeyBytes")
|
||||||
|
.field(&HexFmt(&self.0))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<[u8]> for EphemeralKeyBytes {
|
impl AsRef<[u8]> for EphemeralKeyBytes {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
&self.0
|
&self.0
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Support for legacy transparent addresses and scripts.
|
//! Support for legacy transparent addresses and scripts.
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::ops::Shl;
|
use std::ops::Shl;
|
||||||
|
|
||||||
|
@ -10,6 +12,7 @@ use zcash_encoding::Vector;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
|
|
||||||
/// Minimal subset of script opcodes.
|
/// Minimal subset of script opcodes.
|
||||||
|
#[derive(Debug)]
|
||||||
enum OpCode {
|
enum OpCode {
|
||||||
// push value
|
// push value
|
||||||
PushData1 = 0x4c,
|
PushData1 = 0x4c,
|
||||||
|
@ -28,10 +31,64 @@ enum OpCode {
|
||||||
CheckSig = 0xac,
|
CheckSig = 0xac,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OpCode {
|
||||||
|
fn parse(b: u8) -> Option<Self> {
|
||||||
|
match b {
|
||||||
|
0x4c => Some(OpCode::PushData1),
|
||||||
|
0x4d => Some(OpCode::PushData2),
|
||||||
|
0x4e => Some(OpCode::PushData4),
|
||||||
|
0x76 => Some(OpCode::Dup),
|
||||||
|
0x87 => Some(OpCode::Equal),
|
||||||
|
0x88 => Some(OpCode::EqualVerify),
|
||||||
|
0xa9 => Some(OpCode::Hash160),
|
||||||
|
0xac => Some(OpCode::CheckSig),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A serialized script, used inside transparent inputs and outputs of a transaction.
|
/// A serialized script, used inside transparent inputs and outputs of a transaction.
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Default, PartialEq, Eq)]
|
||||||
pub struct Script(pub Vec<u8>);
|
pub struct Script(pub Vec<u8>);
|
||||||
|
|
||||||
|
impl fmt::Debug for Script {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
struct ScriptPrinter<'s>(&'s [u8]);
|
||||||
|
impl<'s> fmt::Debug for ScriptPrinter<'s> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut l = f.debug_list();
|
||||||
|
let mut unknown: Option<String> = None;
|
||||||
|
for b in self.0 {
|
||||||
|
if let Some(opcode) = OpCode::parse(*b) {
|
||||||
|
if let Some(s) = unknown.take() {
|
||||||
|
l.entry(&s);
|
||||||
|
}
|
||||||
|
l.entry(&opcode);
|
||||||
|
} else {
|
||||||
|
let encoded = format!("{:02x}", b);
|
||||||
|
if let Some(s) = &mut unknown {
|
||||||
|
s.push_str(&encoded);
|
||||||
|
} else {
|
||||||
|
unknown = Some(encoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.alternate() {
|
||||||
|
f.debug_tuple("Script")
|
||||||
|
.field(&ScriptPrinter(&self.0))
|
||||||
|
.finish()
|
||||||
|
} else {
|
||||||
|
f.debug_tuple("Script")
|
||||||
|
.field(&hex::encode(&self.0))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Script {
|
impl Script {
|
||||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
let script = Vector::read(&mut reader, |r| r.read_u8())?;
|
let script = Vector::read(&mut reader, |r| r.read_u8())?;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::array::TryFromSliceError;
|
use std::array::TryFromSliceError;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use subtle::{Choice, ConstantTimeEq};
|
use subtle::{Choice, ConstantTimeEq};
|
||||||
|
|
||||||
|
@ -9,9 +10,17 @@ use crate::sapling::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Typesafe wrapper for nullifier values.
|
/// Typesafe wrapper for nullifier values.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct Nullifier(pub [u8; 32]);
|
pub struct Nullifier(pub [u8; 32]);
|
||||||
|
|
||||||
|
impl fmt::Debug for Nullifier {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("Nullifier")
|
||||||
|
.field(&hex::encode(self.0))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Nullifier {
|
impl Nullifier {
|
||||||
pub fn from_slice(bytes: &[u8]) -> Result<Nullifier, TryFromSliceError> {
|
pub fn from_slice(bytes: &[u8]) -> Result<Nullifier, TryFromSliceError> {
|
||||||
bytes.try_into().map(Nullifier)
|
bytes.try_into().map(Nullifier)
|
||||||
|
|
|
@ -7,6 +7,8 @@ use ff::{Field, PrimeField};
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
use jubjub::{AffinePoint, ExtendedPoint, SubgroupPoint};
|
use jubjub::{AffinePoint, ExtendedPoint, SubgroupPoint};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::ops::{AddAssign, MulAssign, Neg};
|
use std::ops::{AddAssign, MulAssign, Neg};
|
||||||
|
|
||||||
|
@ -28,12 +30,21 @@ fn h_star(a: &[u8], b: &[u8]) -> jubjub::Fr {
|
||||||
hash_to_scalar(b"Zcash_RedJubjubH", a, b)
|
hash_to_scalar(b"Zcash_RedJubjubH", a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Signature {
|
pub struct Signature {
|
||||||
rbar: [u8; 32],
|
rbar: [u8; 32],
|
||||||
sbar: [u8; 32],
|
sbar: [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Signature {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Signature")
|
||||||
|
.field("rbar", &hex::encode(self.rbar))
|
||||||
|
.field("sbar", &hex::encode(self.sbar))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PrivateKey(pub jubjub::Fr);
|
pub struct PrivateKey(pub jubjub::Fr);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
Loading…
Reference in New Issue