penumbra_sdk_sct/
source.rs1use anyhow::anyhow;
2use penumbra_sdk_proto::{core::component::sct::v1 as pb, DomainType};
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
6#[serde(try_from = "pb::CommitmentSource", into = "pb::CommitmentSource")]
7pub enum CommitmentSource {
8 Genesis,
10 Transaction {
12 id: Option<[u8; 32]>,
17 },
18 FundingStreamReward { epoch_index: u64 },
20 CommunityPoolOutput,
22 Ics20Transfer {
24 packet_seq: u64,
26 channel_id: String,
28 sender: String,
30 },
31}
32
33impl DomainType for CommitmentSource {
34 type Proto = pb::CommitmentSource;
35}
36
37impl CommitmentSource {
38 pub fn transaction() -> Self {
40 CommitmentSource::Transaction { id: None }
41 }
42
43 pub fn stripped(&self) -> Self {
45 match self {
46 CommitmentSource::Transaction { .. } => CommitmentSource::Transaction { id: None },
47 x => x.clone(),
48 }
49 }
50
51 pub fn id(&self) -> Option<[u8; 32]> {
53 match self {
54 CommitmentSource::Transaction { id: Some(id) } => Some(*id),
55 _ => None,
56 }
57 }
58}
59
60impl From<CommitmentSource> for pb::CommitmentSource {
61 fn from(value: CommitmentSource) -> Self {
62 use pb::commitment_source::{self as pbcs, Source};
63
64 Self {
65 source: Some(match value {
66 CommitmentSource::Genesis => Source::Genesis(pbcs::Genesis {}),
67 CommitmentSource::Transaction { id } => Source::Transaction(pbcs::Transaction {
68 id: id.map(|bytes| bytes.to_vec()).unwrap_or_default(),
69 }),
70 CommitmentSource::FundingStreamReward { epoch_index } => {
71 Source::FundingStreamReward(pbcs::FundingStreamReward { epoch_index })
72 }
73 CommitmentSource::CommunityPoolOutput => {
74 Source::CommunityPoolOutput(pbcs::CommunityPoolOutput {})
75 }
76 CommitmentSource::Ics20Transfer {
77 packet_seq,
78 channel_id,
79 sender,
80 } => Source::Ics20Transfer(pbcs::Ics20Transfer {
81 packet_seq,
82 channel_id,
83 sender,
84 }),
85 }),
86 }
87 }
88}
89
90impl TryFrom<pb::CommitmentSource> for CommitmentSource {
91 type Error = anyhow::Error;
92
93 fn try_from(value: pb::CommitmentSource) -> Result<Self, Self::Error> {
94 use pb::commitment_source::Source;
95 let source = value.source.ok_or_else(|| anyhow!("missing source"))?;
96
97 Ok(match source {
98 Source::Genesis(_) => Self::Genesis,
99 Source::CommunityPoolOutput(_) => Self::CommunityPoolOutput,
100 Source::FundingStreamReward(x) => Self::FundingStreamReward {
101 epoch_index: x.epoch_index,
102 },
103 Source::Transaction(x) => {
104 if x.id.is_empty() {
105 Self::Transaction { id: None }
106 } else {
107 Self::Transaction {
108 id: Some(x.id.try_into().map_err(|id: Vec<u8>| {
109 anyhow!("expected 32-byte id array, got {} bytes", id.len())
110 })?),
111 }
112 }
113 }
114 Source::Ics20Transfer(x) => Self::Ics20Transfer {
115 packet_seq: x.packet_seq,
116 channel_id: x.channel_id,
117 sender: x.sender,
118 },
119 })
120 }
121}