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

Add CommitmentInput and BlockIssuanceCreditInput #981

56 changes: 56 additions & 0 deletions sdk/src/types/block/context_input/block_issuance_credit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use derive_more::{Display, From};

use crate::types::block::output::AccountId;

/// A Block Issuance Credit Input provides the VM with context for the value of
/// the BIC vector of a specific slot.
DaughterOfMars marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Clone, Copy, Debug, Display, Eq, PartialEq, Hash, Ord, PartialOrd, From, packable::Packable)]
pub struct BlockIssuanceCreditContextInput(AccountId);

impl BlockIssuanceCreditContextInput {
/// The context input kind of a [`BlockIssuanceCreditContextInput`].
pub const KIND: u8 = 1;

/// Creates a new [`BlockIssuanceCreditContextInput`].
pub fn new(account_id: AccountId) -> Self {
Self(account_id)
}

/// Returns the account id of the [`BlockIssuanceCreditContextInput`].
pub fn account_id(&self) -> AccountId {
self.0
}
}

pub(crate) mod dto {
use serde::{Deserialize, Serialize};

use super::*;

/// A Block Issuance Credit Input provides the VM with context for the value of
/// the BIC vector of a specific slot.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct BlockIssuanceCreditContextInputDto {
#[serde(rename = "type")]
pub kind: u8,
pub account_id: AccountId,
}

impl From<&BlockIssuanceCreditContextInput> for BlockIssuanceCreditContextInputDto {
fn from(value: &BlockIssuanceCreditContextInput) -> Self {
Self {
kind: BlockIssuanceCreditContextInput::KIND,
account_id: value.account_id(),
}
}
}

impl From<BlockIssuanceCreditContextInputDto> for BlockIssuanceCreditContextInput {
fn from(value: BlockIssuanceCreditContextInputDto) -> Self {
Self::new(value.account_id)
kwek20 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
54 changes: 54 additions & 0 deletions sdk/src/types/block/context_input/commitment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use derive_more::{Display, From};

use crate::types::block::slot::SlotCommitmentId;

/// A Commitment Context indicates that the input references a commitment to a certain slot.
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Clone, Copy, Display, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, From, packable::Packable)]
pub struct CommitmentContextInput(SlotCommitmentId);

impl CommitmentContextInput {
/// The context input kind of a [`CommitmentContextInput`].
pub const KIND: u8 = 0;

/// Creates a new [`CommitmentContextInput`].
pub fn new(commitment_id: SlotCommitmentId) -> Self {
Self(commitment_id)
}

/// Returns the commitment id of the [`CommitmentContextInput`].
pub fn commitment_id(&self) -> SlotCommitmentId {
self.0
}
}

pub(crate) mod dto {
use serde::{Deserialize, Serialize};

use super::*;

/// A Commitment Context indicates that the input references a commitment to a certain slot.
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct CommitmentContextInputDto {
#[serde(rename = "type")]
pub kind: u8,
pub commitment_id: SlotCommitmentId,
}

impl From<&CommitmentContextInput> for CommitmentContextInputDto {
fn from(value: &CommitmentContextInput) -> Self {
Self {
kind: CommitmentContextInput::KIND,
commitment_id: value.commitment_id(),
}
}
}

impl From<CommitmentContextInputDto> for CommitmentContextInput {
fn from(value: CommitmentContextInputDto) -> Self {
Self::new(value.commitment_id)
}
}
}
101 changes: 94 additions & 7 deletions sdk/src/types/block/context_input/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

mod block_issuance_credit;
mod commitment;
mod reward;

use derive_more::From;
use derive_more::{Display, From};

pub use self::reward::RewardContextInput;
pub use self::{
block_issuance_credit::BlockIssuanceCreditContextInput, commitment::CommitmentContextInput,
reward::RewardContextInput,
};
use crate::types::block::Error;

/// A Context Input provides additional contextual information for the execution of a transaction, such as for different
/// functionality related to accounts, commitments, or Mana rewards. A Context Input does not need to be unlocked.
#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, From, packable::Packable)]
#[derive(Clone, Eq, Display, PartialEq, Hash, Ord, PartialOrd, From, packable::Packable)]
abdulmth marked this conversation as resolved.
Show resolved Hide resolved
#[packable(unpack_error = Error)]
#[packable(tag_type = u8, with_error = Error::InvalidContextInputKind)]
pub enum ContextInput {
/// A [`CommitmentContextInput`].
#[packable(tag = CommitmentContextInput::KIND)]
Commitment(CommitmentContextInput),
/// A [`BlockIssuanceCreditContextInput`].
#[packable(tag = BlockIssuanceCreditContextInput::KIND)]
BlockIssuanceCredit(BlockIssuanceCreditContextInput),
/// A [`RewardContextInput`].
#[packable(tag = RewardContextInput::KIND)]
Reward(RewardContextInput),
// TODO: Commitment Input https://github.com/iotaledger/iota-sdk/issues/901 and Block Issuance Credit Input https://github.com/iotaledger/iota-sdk/issues/906
}

impl core::fmt::Debug for ContextInput {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Commitment(input) => input.fmt(f),
Self::BlockIssuanceCredit(input) => input.fmt(f),
Self::Reward(input) => input.fmt(f),
}
}
Expand All @@ -32,40 +44,80 @@ impl ContextInput {
/// Returns the context input kind of a `ContextInput`.
pub fn kind(&self) -> u8 {
match self {
Self::Commitment(_) => CommitmentContextInput::KIND,
Self::BlockIssuanceCredit(_) => BlockIssuanceCreditContextInput::KIND,
Self::Reward(_) => RewardContextInput::KIND,
}
}

/// Checks whether the context input is a [`CommitmentContextInput`].
pub fn is_commitment(&self) -> bool {
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
matches!(self, Self::Commitment(_))
}

/// Checks whether the context input is a [`BlockIssuanceCreditContextInput`].
pub fn is_block_issuance_credit(&self) -> bool {
matches!(self, Self::BlockIssuanceCredit(_))
}
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved

/// Checks whether the context input is a [`RewardContextInput`].
pub fn is_reward(&self) -> bool {
matches!(self, Self::Reward(_))
}

/// Gets the input as an actual [`CommitmentContextInput`].
/// PANIC: do not call on a non-commitment context input.
pub fn as_commitment(&self) -> &CommitmentContextInput {
if let Self::Commitment(input) = self {
input
} else {
panic!("context input is not of type commitment: {:?}", self);
thibault-martinez marked this conversation as resolved.
Show resolved Hide resolved
}
}
/// Gets the input as an actual [`BlockIssuanceCreditContextInput`].
/// PANIC: do not call on a non-block-issuance-credit context input.
pub fn as_block_issuance_credit(&self) -> &BlockIssuanceCreditContextInput {
if let Self::BlockIssuanceCredit(input) = self {
input
} else {
panic!("context input is not of type block issuance credit: {:?}", self);
}
}

/// Gets the input as an actual [`RewardContextInput`].
/// PANIC: do not call on a non-reward context input.
pub fn as_reward(&self) -> &RewardContextInput {
let Self::Reward(input) = self;
input
if let Self::Reward(input) = self {
input
} else {
panic!("context input is not of type reward: {:?}", self);
}
}
}

pub mod dto {
use serde::{Deserialize, Serialize};

pub use super::reward::dto::RewardContextInputDto;
use super::*;
use super::{
block_issuance_credit::dto::BlockIssuanceCreditContextInputDto, commitment::dto::CommitmentContextInputDto, *,
};
use crate::types::block::Error;

/// Describes all the different context input types.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, From)]
#[serde(untagged)]
pub enum ContextInputDto {
Commitment(CommitmentContextInputDto),
BlockIssuanceCredit(BlockIssuanceCreditContextInputDto),
Reward(RewardContextInputDto),
}

impl From<&ContextInput> for ContextInputDto {
fn from(value: &ContextInput) -> Self {
match value {
ContextInput::Commitment(u) => Self::Commitment(u.into()),
ContextInput::BlockIssuanceCredit(u) => Self::BlockIssuanceCredit(u.into()),
ContextInput::Reward(u) => Self::Reward(u.into()),
}
}
Expand All @@ -76,8 +128,43 @@ pub mod dto {

fn try_from(value: ContextInputDto) -> Result<Self, Self::Error> {
match value {
ContextInputDto::Commitment(u) => Ok(Self::Commitment(u.try_into()?)),
ContextInputDto::BlockIssuanceCredit(u) => Ok(Self::BlockIssuanceCredit(u.try_into()?)),
ContextInputDto::Reward(u) => Ok(Self::Reward(u.try_into()?)),
}
}
}
}

#[cfg(test)]
mod tests {
use core::str::FromStr;

use super::{CommitmentContextInput, ContextInput, RewardContextInput};
use crate::types::block::{
context_input::BlockIssuanceCreditContextInput, output::AccountId, slot::SlotCommitmentId,
};

#[test]
fn test_context_input() {
let reward = ContextInput::Reward(RewardContextInput::new(10));
assert!(reward.is_reward());
let reward: &RewardContextInput = reward.as_reward();
assert_eq!(reward.to_string(), "10");

let slot_commitment_id_str =
"0xedf5f572c58ddf4b4f9567d82bf96689cc68b730df796d822b4b9fb643f5efda4f9567d82bf96689";
let slot_commitment_id = SlotCommitmentId::from_str(slot_commitment_id_str).unwrap();
let commitment = ContextInput::Commitment(CommitmentContextInput::new(slot_commitment_id));
assert!(commitment.is_commitment());
let commitment: &CommitmentContextInput = commitment.as_commitment();
assert_eq!(commitment.to_string(), slot_commitment_id_str);

let account_id_str = "0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649";
let account_id = AccountId::from_str(account_id_str).unwrap();
let block_issuance_credit = ContextInput::BlockIssuanceCredit(BlockIssuanceCreditContextInput::new(account_id));
assert!(block_issuance_credit.is_block_issuance_credit());
let block_issuance_credit: &BlockIssuanceCreditContextInput = block_issuance_credit.as_block_issuance_credit();
assert_eq!(block_issuance_credit.to_string(), account_id_str);
}
}
Loading