use neptune_consensus::transaction::announcement::Announcement;
use neptune_consensus::transaction::transaction_kernel::TransactionKernel;
use neptune_consensus::transaction::transaction_kernel::TransactionKernelProxy;
use neptune_mutator_set::addition_record::AdditionRecord;
use neptune_mutator_set::removal_record::RemovalRecord;
use neptune_mutator_set::removal_record::absolute_index_set::AbsoluteIndexSet;
use neptune_mutator_set::removal_record::chunk::Chunk;
use neptune_mutator_set::removal_record::chunk_dictionary::ChunkDictionary;
use neptune_primitives::timestamp::Timestamp;
use serde::Deserialize;
use serde::Serialize;
use tasm_lib::prelude::Digest;
use crate::model::common::RpcBFieldElements;
use crate::model::common::RpcNativeCurrencyAmount;
use crate::model::wallet::mutator_set::RpcMmrMembershipProof;
pub type RpcAbsoluteIndexSet = AbsoluteIndexSet;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct RpcChunkDictionaryElement {
pub chunk_index: u64,
pub authentication_path: RpcMmrMembershipProof,
pub chunk: Vec<u32>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct RpcChunkDictionary(Vec<RpcChunkDictionaryElement>);
impl From<ChunkDictionary> for RpcChunkDictionary {
fn from(value: ChunkDictionary) -> Self {
Self(
value
.into_inner()
.into_iter()
.map(
|(chunk_index, (membership_proof, chunk))| RpcChunkDictionaryElement {
chunk_index,
authentication_path: membership_proof.into(),
chunk: chunk.relative_indices,
},
)
.collect(),
)
}
}
impl From<RpcChunkDictionary> for ChunkDictionary {
fn from(value: RpcChunkDictionary) -> Self {
let dictionary = value
.0
.into_iter()
.map(|elem| {
(
elem.chunk_index,
(
elem.authentication_path.into(),
Chunk {
relative_indices: elem.chunk,
},
),
)
})
.collect();
ChunkDictionary::new(dictionary)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct RpcRemovalRecord {
pub absolute_indices: RpcAbsoluteIndexSet,
pub target_chunks: RpcChunkDictionary,
}
impl From<RemovalRecord> for RpcRemovalRecord {
fn from(record: RemovalRecord) -> Self {
Self {
absolute_indices: record.absolute_indices,
target_chunks: record.target_chunks.into(),
}
}
}
impl From<RpcRemovalRecord> for RemovalRecord {
fn from(record: RpcRemovalRecord) -> Self {
Self {
absolute_indices: record.absolute_indices,
target_chunks: record.target_chunks.into(),
}
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct RpcAdditionRecord(pub Digest);
impl From<AdditionRecord> for RpcAdditionRecord {
fn from(record: AdditionRecord) -> Self {
Self(record.canonical_commitment)
}
}
impl From<RpcAdditionRecord> for AdditionRecord {
fn from(record: RpcAdditionRecord) -> Self {
Self {
canonical_commitment: record.0,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct RpcAnnouncement(RpcBFieldElements);
impl From<Announcement> for RpcAnnouncement {
fn from(announcement: Announcement) -> Self {
Self(announcement.message.into())
}
}
impl From<RpcAnnouncement> for Announcement {
fn from(announcement: RpcAnnouncement) -> Self {
Announcement {
message: announcement.0.into(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RpcTransactionKernel {
pub inputs: Vec<RpcRemovalRecord>,
pub outputs: Vec<RpcAdditionRecord>,
pub announcements: Vec<RpcAnnouncement>,
pub fee: RpcNativeCurrencyAmount,
pub coinbase: Option<RpcNativeCurrencyAmount>,
pub timestamp: Timestamp,
pub mutator_set_hash: Digest,
pub merge_bit: bool,
}
impl PartialEq for RpcTransactionKernel {
fn eq(&self, o: &Self) -> bool {
self.inputs == o.inputs
&& self.outputs == o.outputs
&& self.announcements == o.announcements
&& self.fee == o.fee
&& self.coinbase == o.coinbase
&& self.timestamp == o.timestamp
&& self.mutator_set_hash == o.mutator_set_hash
&& self.merge_bit == o.merge_bit
}
}
impl From<&TransactionKernel> for RpcTransactionKernel {
fn from(kernel: &TransactionKernel) -> Self {
Self {
inputs: kernel.inputs.clone().into_iter().map(Into::into).collect(),
outputs: kernel.outputs.iter().copied().map(Into::into).collect(),
announcements: kernel
.announcements
.clone()
.into_iter()
.map(Into::into)
.collect(),
fee: kernel.fee.into(),
coinbase: kernel.coinbase.map(|c| c.into()),
timestamp: kernel.timestamp,
mutator_set_hash: kernel.mutator_set_hash,
merge_bit: kernel.merge_bit,
}
}
}
impl From<RpcTransactionKernel> for TransactionKernel {
fn from(kernel: RpcTransactionKernel) -> Self {
let kernel_proxy = TransactionKernelProxy {
inputs: kernel.inputs.into_iter().map(Into::into).collect(),
outputs: kernel.outputs.into_iter().map(Into::into).collect(),
announcements: kernel.announcements.into_iter().map(Into::into).collect(),
fee: kernel.fee.into(),
coinbase: kernel.coinbase.map(Into::into),
timestamp: kernel.timestamp,
mutator_set_hash: kernel.mutator_set_hash,
merge_bit: kernel.merge_bit,
};
kernel_proxy.into_kernel()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RpcTransactionKernelId(pub Digest);
#[cfg(test)]
mod tests {
use proptest::prop_assert_eq;
use super::*;
#[test_strategy::proptest]
fn rpcchunk_dictionary_preserved_under_conversion(
#[strategy(proptest_arbitrary_interop::arb::<ChunkDictionary>())]
chunk_dictionary: ChunkDictionary,
) {
let rpc: RpcChunkDictionary = chunk_dictionary.clone().into();
prop_assert_eq!(chunk_dictionary, rpc.into());
}
#[test_strategy::proptest]
fn tx_kernel_hash_preserved_under_conversion(
#[strategy(proptest_arbitrary_interop::arb::<TransactionKernel>())]
kernel: TransactionKernel,
) {
let rpc: RpcTransactionKernel = (&kernel).into();
prop_assert_eq!(kernel, rpc.into());
}
}