use super::ser::{EpeeRead, EpeeWrite, Reader, write_var_bytes, write_vec};
use super::sig::{ZcAssetSurjectionProof, ZcBalanceProof, ZcOutsRangeProof, ZcSig};
use super::tx::{TxInGen, TxInToKey, TxInZcInput, TxOutZarcanum};
use super::types::{AccountPublicAddr, RefById, Value256};
use super::varint::append_varint;
use crate::error::Result;
pub mod tag {
pub const GEN: u8 = 0;
pub const TO_KEY: u8 = 1;
pub const COMMENT: u8 = 7;
pub const CRYPTO_CHECKSUM: u8 = 10;
pub const DERIVATION_HINT: u8 = 11;
pub const SERVICE_ATTACHMENT: u8 = 12;
pub const UNLOCK_TIME: u8 = 14;
pub const EXPIRATION_TIME: u8 = 15;
pub const TX_FLAGS: u8 = 16;
pub const SIGNED_PARTS: u8 = 17;
pub const EXTRA_ATTACHMENT_INFO: u8 = 18;
pub const USER_DATA: u8 = 19;
pub const EXTRA_PADDING: u8 = 21;
pub const PUB_KEY: u8 = 22;
pub const ETC_TX_FLAGS16: u8 = 23;
pub const DERIVE_XOR: u8 = 24;
pub const REF_BY_ID: u8 = 25;
pub const UINT64: u8 = 26;
pub const ETC_TX_TIME: u8 = 27;
pub const UINT32: u8 = 28;
pub const PAYER: u8 = 31;
pub const RECEIVER: u8 = 32;
pub const TXIN_ZC_INPUT: u8 = 37;
pub const TX_OUT_ZARCANUM: u8 = 38;
pub const ZARCANUM_TX_DATA_V1: u8 = 39;
pub const ZC_SIG: u8 = 43;
pub const ZC_ASSET_SURJECTION_PROOF: u8 = 46;
pub const ZC_OUTS_RANGE_PROOF: u8 = 47;
pub const ZC_BALANCE_PROOF: u8 = 48;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExtraUserData {
pub buff: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExtraPadding {
pub buff: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExtraAttachmentInfo {
pub sz: u64,
pub hsh: Value256,
pub cnt: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SignedParts {
pub n_outs: u64,
pub n_extras: u64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TxComment {
pub comment: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TxCryptoChecksum {
pub encrypted_key_derivation: Value256,
pub derivation_hash: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TxServiceAttachment {
pub service_id: String,
pub instruction: String,
pub body: Vec<u8>,
pub security: Vec<Value256>,
pub flags: u8,
}
pub const TX_SERVICE_ATTACHMENT_ENCRYPT_BODY: u8 = 1 << 0;
pub const TX_SERVICE_ATTACHMENT_DEFLATE_BODY: u8 = 1 << 1;
pub const TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE: u8 = 1 << 2;
pub const TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF: u8 = 1 << 3;
pub const PAYMENT_ID_SERVICE_ID: &str = "P";
#[derive(Clone, Debug)]
pub enum Variant {
Gen(TxInGen),
ToKey(TxInToKey),
Comment(TxComment),
CryptoChecksum(TxCryptoChecksum),
DerivationHint(Vec<u8>),
ServiceAttachment(TxServiceAttachment),
UnlockTime(u64),
ExpirationTime(u64),
TxFlags(u64),
SignedParts(SignedParts),
ExtraAttachmentInfo(ExtraAttachmentInfo),
UserData(ExtraUserData),
ExtraPadding(ExtraPadding),
PubKey(Value256),
EtcTxFlags16(u16),
DeriveXor(u16),
RefById(RefById),
Uint64(u64),
EtcTxTime(u64),
Uint32(u32),
Payer(AccountPublicAddr),
Receiver(AccountPublicAddr),
TxInZcInput(TxInZcInput),
TxOutZarcanum(TxOutZarcanum),
ZarcanumTxDataV1 {
fee: u64,
},
ZcSig(ZcSig),
ZcAssetSurjectionProof(ZcAssetSurjectionProof),
ZcOutsRangeProof(ZcOutsRangeProof),
ZcBalanceProof(ZcBalanceProof),
}
impl Variant {
pub fn tag(&self) -> u8 {
match self {
Variant::Gen(_) => tag::GEN,
Variant::ToKey(_) => tag::TO_KEY,
Variant::Comment(_) => tag::COMMENT,
Variant::CryptoChecksum(_) => tag::CRYPTO_CHECKSUM,
Variant::DerivationHint(_) => tag::DERIVATION_HINT,
Variant::ServiceAttachment(_) => tag::SERVICE_ATTACHMENT,
Variant::UnlockTime(_) => tag::UNLOCK_TIME,
Variant::ExpirationTime(_) => tag::EXPIRATION_TIME,
Variant::TxFlags(_) => tag::TX_FLAGS,
Variant::SignedParts(_) => tag::SIGNED_PARTS,
Variant::ExtraAttachmentInfo(_) => tag::EXTRA_ATTACHMENT_INFO,
Variant::UserData(_) => tag::USER_DATA,
Variant::ExtraPadding(_) => tag::EXTRA_PADDING,
Variant::PubKey(_) => tag::PUB_KEY,
Variant::EtcTxFlags16(_) => tag::ETC_TX_FLAGS16,
Variant::DeriveXor(_) => tag::DERIVE_XOR,
Variant::RefById(_) => tag::REF_BY_ID,
Variant::Uint64(_) => tag::UINT64,
Variant::EtcTxTime(_) => tag::ETC_TX_TIME,
Variant::Uint32(_) => tag::UINT32,
Variant::Payer(_) => tag::PAYER,
Variant::Receiver(_) => tag::RECEIVER,
Variant::TxInZcInput(_) => tag::TXIN_ZC_INPUT,
Variant::TxOutZarcanum(_) => tag::TX_OUT_ZARCANUM,
Variant::ZarcanumTxDataV1 { .. } => tag::ZARCANUM_TX_DATA_V1,
Variant::ZcSig(_) => tag::ZC_SIG,
Variant::ZcAssetSurjectionProof(_) => tag::ZC_ASSET_SURJECTION_PROOF,
Variant::ZcOutsRangeProof(_) => tag::ZC_OUTS_RANGE_PROOF,
Variant::ZcBalanceProof(_) => tag::ZC_BALANCE_PROOF,
}
}
pub fn type_name(&self) -> &'static str {
match self {
Variant::Gen(_) => "gen",
Variant::ToKey(_) => "key",
Variant::Comment(_) => "comment",
Variant::CryptoChecksum(_) => "checksum",
Variant::DerivationHint(_) => "derivation_hint",
Variant::ServiceAttachment(_) => "attachment",
Variant::UnlockTime(_) => "unlock_time",
Variant::ExpirationTime(_) => "expiration_time",
Variant::TxFlags(_) => "flags",
Variant::SignedParts(_) => "signed_outs",
Variant::ExtraAttachmentInfo(_) => "extra_attach_info",
Variant::UserData(_) => "user_data",
Variant::ExtraPadding(_) => "extra_padding",
Variant::PubKey(_) => "pub_key",
Variant::EtcTxFlags16(_) => "etc_tx_flags16",
Variant::DeriveXor(_) => "derive_xor",
Variant::RefById(_) => "ref_by_id",
Variant::Uint64(_) => "uint64_t",
Variant::EtcTxTime(_) => "etc_tx_time",
Variant::Uint32(_) => "uint32_t",
Variant::Payer(_) => "payer2",
Variant::Receiver(_) => "receiver2",
Variant::TxInZcInput(_) => "txin_zc_input",
Variant::TxOutZarcanum(_) => "tx_out_zarcanum",
Variant::ZarcanumTxDataV1 { .. } => "zarcanum_tx_data_v1",
Variant::ZcSig(_) => "ZC_sig",
Variant::ZcAssetSurjectionProof(_) => "zc_asset_surjection_proof",
Variant::ZcOutsRangeProof(_) => "zc_outs_range_proof",
Variant::ZcBalanceProof(_) => "zc_balance_proof",
}
}
pub fn as_tx_out_zarcanum(&self) -> Option<&TxOutZarcanum> {
match self {
Variant::TxOutZarcanum(v) => Some(v),
_ => None,
}
}
pub fn as_txin_zc_input(&self) -> Option<&TxInZcInput> {
match self {
Variant::TxInZcInput(v) => Some(v),
_ => None,
}
}
pub fn as_service_attachment(&self) -> Option<&TxServiceAttachment> {
match self {
Variant::ServiceAttachment(v) => Some(v),
_ => None,
}
}
pub fn as_uint64(&self) -> Option<u64> {
match self {
Variant::Uint64(v) => Some(*v),
_ => None,
}
}
}
impl EpeeWrite for Variant {
fn write_epee(&self, out: &mut Vec<u8>) {
out.push(self.tag());
match self {
Variant::Gen(v) => v.write_epee(out),
Variant::ToKey(v) => v.write_epee(out),
Variant::Comment(v) => write_var_bytes(&v.comment, out),
Variant::CryptoChecksum(v) => {
v.encrypted_key_derivation.write_epee(out);
v.derivation_hash.write_epee(out);
}
Variant::DerivationHint(v) => write_var_bytes(v, out),
Variant::ServiceAttachment(v) => {
write_var_bytes(v.service_id.as_bytes(), out);
write_var_bytes(v.instruction.as_bytes(), out);
write_var_bytes(&v.body, out);
write_vec(&v.security, out);
out.push(v.flags);
}
Variant::UnlockTime(v)
| Variant::ExpirationTime(v)
| Variant::TxFlags(v)
| Variant::EtcTxTime(v) => append_varint(out, *v),
Variant::SignedParts(v) => {
append_varint(out, v.n_outs);
append_varint(out, v.n_extras);
}
Variant::ExtraAttachmentInfo(v) => {
append_varint(out, v.sz);
v.hsh.write_epee(out);
append_varint(out, v.cnt);
}
Variant::UserData(v) => write_var_bytes(&v.buff, out),
Variant::ExtraPadding(v) => write_var_bytes(&v.buff, out),
Variant::PubKey(v) => v.write_epee(out),
Variant::EtcTxFlags16(v) | Variant::DeriveXor(v) => v.write_epee(out),
Variant::RefById(v) => v.write_epee(out),
Variant::Uint64(v) => v.write_epee(out),
Variant::Uint32(v) => v.write_epee(out),
Variant::Payer(v) | Variant::Receiver(v) => v.write_epee(out),
Variant::TxInZcInput(v) => v.write_epee(out),
Variant::TxOutZarcanum(v) => v.write_epee(out),
Variant::ZarcanumTxDataV1 { fee } => fee.write_epee(out),
Variant::ZcSig(v) => v.write_epee(out),
Variant::ZcAssetSurjectionProof(v) => v.write_epee(out),
Variant::ZcOutsRangeProof(v) => v.write_epee(out),
Variant::ZcBalanceProof(v) => v.write_epee(out),
}
}
}
impl EpeeRead for Variant {
fn read_epee(r: &mut Reader<'_>) -> Result<Self> {
let t = r.read_byte()?;
Ok(match t {
tag::GEN => Variant::Gen(TxInGen::read_epee(r)?),
tag::TO_KEY => Variant::ToKey(TxInToKey::read_epee(r)?),
tag::COMMENT => Variant::Comment(TxComment {
comment: r.read_var_bytes()?,
}),
tag::CRYPTO_CHECKSUM => Variant::CryptoChecksum(TxCryptoChecksum {
encrypted_key_derivation: Value256::read_epee(r)?,
derivation_hash: u32::read_epee(r)?,
}),
tag::DERIVATION_HINT => Variant::DerivationHint(r.read_var_bytes()?),
tag::SERVICE_ATTACHMENT => Variant::ServiceAttachment(TxServiceAttachment {
service_id: r.read_var_string()?,
instruction: r.read_var_string()?,
body: r.read_var_bytes()?,
security: r.read_vec()?,
flags: r.read_byte()?,
}),
tag::UNLOCK_TIME => Variant::UnlockTime(r.read_varint()?),
tag::EXPIRATION_TIME => Variant::ExpirationTime(r.read_varint()?),
tag::TX_FLAGS => Variant::TxFlags(r.read_varint()?),
tag::SIGNED_PARTS => Variant::SignedParts(SignedParts {
n_outs: r.read_varint()?,
n_extras: r.read_varint()?,
}),
tag::EXTRA_ATTACHMENT_INFO => Variant::ExtraAttachmentInfo(ExtraAttachmentInfo {
sz: r.read_varint()?,
hsh: Value256::read_epee(r)?,
cnt: r.read_varint()?,
}),
tag::USER_DATA => Variant::UserData(ExtraUserData {
buff: r.read_var_bytes()?,
}),
tag::EXTRA_PADDING => Variant::ExtraPadding(ExtraPadding {
buff: r.read_var_bytes()?,
}),
tag::PUB_KEY => Variant::PubKey(Value256::read_epee(r)?),
tag::ETC_TX_FLAGS16 => Variant::EtcTxFlags16(u16::read_epee(r)?),
tag::DERIVE_XOR => Variant::DeriveXor(u16::read_epee(r)?),
tag::REF_BY_ID => Variant::RefById(RefById::read_epee(r)?),
tag::UINT64 => Variant::Uint64(u64::read_epee(r)?),
tag::ETC_TX_TIME => Variant::EtcTxTime(r.read_varint()?),
tag::UINT32 => Variant::Uint32(u32::read_epee(r)?),
tag::PAYER => Variant::Payer(AccountPublicAddr::read_epee(r)?),
tag::RECEIVER => Variant::Receiver(AccountPublicAddr::read_epee(r)?),
tag::TXIN_ZC_INPUT => Variant::TxInZcInput(TxInZcInput::read_epee(r)?),
tag::TX_OUT_ZARCANUM => Variant::TxOutZarcanum(TxOutZarcanum::read_epee(r)?),
tag::ZARCANUM_TX_DATA_V1 => Variant::ZarcanumTxDataV1 {
fee: u64::read_epee(r)?,
},
tag::ZC_SIG => Variant::ZcSig(ZcSig::read_epee(r)?),
tag::ZC_ASSET_SURJECTION_PROOF => {
Variant::ZcAssetSurjectionProof(ZcAssetSurjectionProof::read_epee(r)?)
}
tag::ZC_OUTS_RANGE_PROOF => Variant::ZcOutsRangeProof(ZcOutsRangeProof::read_epee(r)?),
tag::ZC_BALANCE_PROOF => Variant::ZcBalanceProof(ZcBalanceProof::read_epee(r)?),
other => return Err(crate::err!("unsupported variant tag {other}")),
})
}
}