Skip to content

Commit

Permalink
feat(core): add contract acceptance utxo features (#4145)
Browse files Browse the repository at this point in the history
Description
---
- Adds `ContractAcceptance` struct to the side-chain output features
- Implements consensus encoding/decoding for `ContractAcceptance`
- Updates related gRPC types and conversions

Motivation and Context
---
Create structs for contract acceptance in the side-chain features.

How Has This Been Tested?
---
- New unit test for consensus encoding/decoding of the `ContractAcceptance`
- Existing unit/integration test pass
  • Loading branch information
mrnaveira authored May 30, 2022
1 parent 2b1a69a commit 2636cb5
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 2 deletions.
6 changes: 6 additions & 0 deletions applications/tari_app_grpc/proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ message SideChainFeatures {
bytes contract_id = 1;
ContractDefinition definition = 2;
ContractConstitution constitution = 3;
ContractAcceptance acceptance = 4;
}

message ContractConstitution {
Expand Down Expand Up @@ -328,6 +329,11 @@ message FunctionRef {
uint32 function_id = 2;
}

message ContractAcceptance {
bytes validator_node_public_key = 1;
Signature signature = 2;
}

// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// cut-through means that blocks and transactions have the same structure. The inputs, outputs and kernels should
// be sorted by their Blake2b-256bit digest hash
Expand Down
35 changes: 35 additions & 0 deletions applications/tari_app_grpc/src/conversions/sidechain_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use tari_core::transactions::transaction_components::{
CommitteeMembers,
ConstitutionChangeFlags,
ConstitutionChangeRules,
ContractAcceptance,
ContractAcceptanceRequirements,
ContractConstitution,
ContractDefinition,
Expand All @@ -49,6 +50,7 @@ impl From<SideChainFeatures> for grpc::SideChainFeatures {
contract_id: value.contract_id.to_vec(),
definition: value.definition.map(Into::into),
constitution: value.constitution.map(Into::into),
acceptance: value.acceptance.map(Into::into),
}
}
}
Expand All @@ -59,11 +61,13 @@ impl TryFrom<grpc::SideChainFeatures> for SideChainFeatures {
fn try_from(features: grpc::SideChainFeatures) -> Result<Self, Self::Error> {
let definition = features.definition.map(ContractDefinition::try_from).transpose()?;
let constitution = features.constitution.map(ContractConstitution::try_from).transpose()?;
let acceptance = features.acceptance.map(ContractAcceptance::try_from).transpose()?;

Ok(Self {
contract_id: features.contract_id.try_into().map_err(|_| "Invalid contract_id")?,
definition,
constitution,
acceptance,
})
}
}
Expand Down Expand Up @@ -395,3 +399,34 @@ impl TryFrom<grpc::CommitteeMembers> for CommitteeMembers {
Ok(members)
}
}

//---------------------------------- ContractAcceptance --------------------------------------------//

impl From<ContractAcceptance> for grpc::ContractAcceptance {
fn from(value: ContractAcceptance) -> Self {
Self {
validator_node_public_key: value.validator_node_public_key.as_bytes().to_vec(),
signature: Some(value.signature.into()),
}
}
}

impl TryFrom<grpc::ContractAcceptance> for ContractAcceptance {
type Error = String;

fn try_from(value: grpc::ContractAcceptance) -> Result<Self, Self::Error> {
let validator_node_public_key =
PublicKey::from_bytes(value.validator_node_public_key.as_bytes()).map_err(|err| format!("{:?}", err))?;

let signature = value
.signature
.ok_or_else(|| "signature not provided".to_string())?
.try_into()
.map_err(|_| "signaturecould not be converted".to_string())?;

Ok(Self {
validator_node_public_key,
signature,
})
}
}
9 changes: 9 additions & 0 deletions applications/tari_app_grpc/src/conversions/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,12 @@ impl TryFrom<grpc::Signature> for Signature {
Ok(Self::new(public_nonce, signature))
}
}

impl From<Signature> for grpc::Signature {
fn from(sig: Signature) -> Self {
Self {
public_nonce: sig.get_public_nonce().to_vec(),
signature: sig.get_signature().to_vec(),
}
}
}
6 changes: 6 additions & 0 deletions base_layer/core/src/proto/transaction.proto
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ message SideChainFeatures {
bytes contract_id = 1;
ContractDefinition definition = 2;
ContractConstitution constitution = 3;
ContractAcceptance acceptance = 4;
}

message ContractConstitution {
Expand Down Expand Up @@ -200,6 +201,11 @@ message FunctionRef {
uint32 function_id = 2;
}

message ContractAcceptance {
bytes validator_node_public_key = 1;
Signature signature = 2;
}

// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// cut-through means that blocks and transactions have the same structure. The inputs, outputs and kernels should
// be sorted by their Blake2b-256bit digest hash
Expand Down
34 changes: 34 additions & 0 deletions base_layer/core/src/proto/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use crate::{
CommitteeMembers,
ConstitutionChangeFlags,
ConstitutionChangeRules,
ContractAcceptance,
ContractAcceptanceRequirements,
ContractConstitution,
ContractDefinition,
Expand Down Expand Up @@ -350,6 +351,7 @@ impl From<SideChainFeatures> for proto::types::SideChainFeatures {
contract_id: value.contract_id.to_vec(),
definition: value.definition.map(Into::into),
constitution: value.constitution.map(Into::into),
acceptance: value.acceptance.map(Into::into),
}
}
}
Expand All @@ -360,11 +362,13 @@ impl TryFrom<proto::types::SideChainFeatures> for SideChainFeatures {
fn try_from(features: proto::types::SideChainFeatures) -> Result<Self, Self::Error> {
let definition = features.definition.map(ContractDefinition::try_from).transpose()?;
let constitution = features.constitution.map(ContractConstitution::try_from).transpose()?;
let acceptance = features.acceptance.map(ContractAcceptance::try_from).transpose()?;

Ok(Self {
contract_id: features.contract_id.try_into().map_err(|_| "Invalid contract_id")?,
definition,
constitution,
acceptance,
})
}
}
Expand Down Expand Up @@ -439,6 +443,36 @@ impl TryFrom<proto::types::ContractAcceptanceRequirements> for ContractAcceptanc
}
}

//---------------------------------- ContractAcceptance --------------------------------------------//

impl From<ContractAcceptance> for proto::types::ContractAcceptance {
fn from(value: ContractAcceptance) -> Self {
Self {
validator_node_public_key: value.validator_node_public_key.as_bytes().to_vec(),
signature: Some(value.signature.into()),
}
}
}

impl TryFrom<proto::types::ContractAcceptance> for ContractAcceptance {
type Error = String;

fn try_from(value: proto::types::ContractAcceptance) -> Result<Self, Self::Error> {
let validator_node_public_key =
PublicKey::from_bytes(value.validator_node_public_key.as_bytes()).map_err(|err| format!("{:?}", err))?;
let signature = value
.signature
.ok_or_else(|| "signature not provided".to_string())?
.try_into()
.map_err(|err: ByteArrayError| err.to_string())?;

Ok(Self {
validator_node_public_key,
signature,
})
}
}

//---------------------------------- SideChainConsensus --------------------------------------------//
impl From<SideChainConsensus> for proto::types::SideChainConsensus {
fn from(value: SideChainConsensus) -> Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ impl Display for OutputFeatures {
mod test {
use std::{convert::TryInto, io::ErrorKind, iter};

use tari_common_types::types::Signature;

use super::*;
use crate::{
consensus::check_consensus_encoding_correctness,
Expand All @@ -457,6 +459,7 @@ mod test {
SideChainConsensus,
},
vec_into_fixed_string,
ContractAcceptance,
ContractConstitution,
ContractDefinition,
ContractSpecification,
Expand Down Expand Up @@ -528,6 +531,10 @@ mod test {
],
},
}),
acceptance: Some(ContractAcceptance {
validator_node_public_key: PublicKey::default(),
signature: Signature::default(),
}),
}),
// Deprecated
parent_public_key: Some(PublicKey::default()),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2022. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::io::{Error, Read, Write};

use serde::{Deserialize, Serialize};
use tari_common_types::types::{PublicKey, Signature};

use crate::consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized};

#[derive(Debug, Clone, Hash, PartialEq, Deserialize, Serialize, Eq)]
pub struct ContractAcceptance {
pub validator_node_public_key: PublicKey,
pub signature: Signature,
}

impl ConsensusEncoding for ContractAcceptance {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.validator_node_public_key.consensus_encode(writer)?;
self.signature.consensus_encode(writer)?;

Ok(())
}
}

impl ConsensusEncodingSized for ContractAcceptance {}

impl ConsensusDecoding for ContractAcceptance {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, Error> {
Ok(Self {
validator_node_public_key: PublicKey::consensus_decode(reader)?,
signature: Signature::consensus_decode(reader)?,
})
}
}

#[cfg(test)]
mod tests {
use tari_common_types::types::PublicKey;

use super::*;
use crate::consensus::check_consensus_encoding_correctness;

#[test]
fn it_encodes_and_decodes_correctly() {
let subject = ContractAcceptance {
validator_node_public_key: PublicKey::default(),
signature: Signature::default(),
};

check_consensus_encoding_correctness(subject).unwrap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

mod contract_acceptance;
pub use contract_acceptance::ContractAcceptance;

mod contract_constitution;
pub use contract_constitution::{
CheckpointParameters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use std::io::{Error, Read, Write};
use serde::{Deserialize, Serialize};
use tari_common_types::types::FixedHash;

use super::ContractDefinition;
use super::{ContractAcceptance, ContractDefinition};
use crate::{
consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized},
transactions::transaction_components::ContractConstitution,
Expand All @@ -36,6 +36,7 @@ pub struct SideChainFeatures {
pub contract_id: FixedHash,
pub definition: Option<ContractDefinition>,
pub constitution: Option<ContractConstitution>,
pub acceptance: Option<ContractAcceptance>,
}

impl SideChainFeatures {
Expand All @@ -53,6 +54,7 @@ impl ConsensusEncoding for SideChainFeatures {
self.contract_id.consensus_encode(writer)?;
self.definition.consensus_encode(writer)?;
self.constitution.consensus_encode(writer)?;
self.acceptance.consensus_encode(writer)?;
Ok(())
}
}
Expand All @@ -65,6 +67,7 @@ impl ConsensusDecoding for SideChainFeatures {
contract_id: FixedHash::consensus_decode(reader)?,
definition: ConsensusDecoding::consensus_decode(reader)?,
constitution: ConsensusDecoding::consensus_decode(reader)?,
acceptance: ConsensusDecoding::consensus_decode(reader)?,
})
}
}
Expand All @@ -80,6 +83,7 @@ impl SideChainFeaturesBuilder {
contract_id,
definition: None,
constitution: None,
acceptance: None,
},
}
}
Expand All @@ -94,6 +98,11 @@ impl SideChainFeaturesBuilder {
self
}

pub fn with_contract_acceptance(mut self, contract_acceptance: ContractAcceptance) -> Self {
self.features.acceptance = Some(contract_acceptance);
self
}

pub fn finish(self) -> SideChainFeatures {
self.features
}
Expand All @@ -103,7 +112,7 @@ impl SideChainFeaturesBuilder {
mod tests {
use std::convert::TryInto;

use tari_common_types::types::PublicKey;
use tari_common_types::types::{PublicKey, Signature};

use super::*;
use crate::{
Expand Down Expand Up @@ -177,6 +186,10 @@ mod tests {
],
},
}),
acceptance: Some(ContractAcceptance {
validator_node_public_key: PublicKey::default(),
signature: Signature::default(),
}),
};

check_consensus_encoding_correctness(subject).unwrap();
Expand Down

0 comments on commit 2636cb5

Please sign in to comment.