Skip to content

Commit

Permalink
Merge branch 'development' into st-val-merge2
Browse files Browse the repository at this point in the history
  • Loading branch information
stringhandler committed Jul 1, 2022
2 parents c17d0b9 + 7b76141 commit bca7c45
Show file tree
Hide file tree
Showing 30 changed files with 677 additions and 310 deletions.
5 changes: 3 additions & 2 deletions applications/tari_app_grpc/proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,9 @@ message CommitteeMembers {
}

message ContractCheckpoint {
bytes merkle_root = 1;
CommitteeSignatures signatures = 2;
uint64 checkpoint_number = 1;
bytes merkle_root = 2;
CommitteeSignatures signatures = 3;
}

message CheckpointParameters {
Expand Down
5 changes: 3 additions & 2 deletions applications/tari_app_grpc/proto/wallet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,9 @@ message CreateInitialAssetCheckpointResponse {
}

message CreateFollowOnAssetCheckpointRequest {
bytes contract_id = 1;
bytes merkle_root = 2;
uint64 checkpoint_number = 1;
bytes contract_id = 2;
bytes merkle_root = 3;
}

message CreateFollowOnAssetCheckpointResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ impl TryFrom<grpc::ContractConstitution> for ContractConstitution {
impl From<ContractCheckpoint> for grpc::ContractCheckpoint {
fn from(value: ContractCheckpoint) -> Self {
Self {
checkpoint_number: value.checkpoint_number,
merkle_root: value.merkle_root.to_vec(),
signatures: Some(value.signatures.into()),
}
Expand All @@ -320,6 +321,7 @@ impl TryFrom<grpc::ContractCheckpoint> for ContractCheckpoint {
let merkle_root = value.merkle_root.try_into().map_err(|_| "Invalid merkle root")?;
let signatures = value.signatures.map(TryInto::try_into).transpose()?.unwrap_or_default();
Ok(Self {
checkpoint_number: value.checkpoint_number,
merkle_root,
signatures,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -858,13 +858,15 @@ impl wallet_server::Wallet for WalletGrpcServer {
.try_into()
.map_err(|e| Status::invalid_argument(format!("Contract ID was not valid :{}", e)))?;

let checkpoint_number = message.checkpoint_number;

let merkle_root = message
.merkle_root
.try_into()
.map_err(|_| Status::invalid_argument("Incorrect merkle root length"))?;

let (tx_id, transaction) = asset_manager
.create_follow_on_asset_checkpoint(contract_id, merkle_root)
.create_follow_on_asset_checkpoint(contract_id, checkpoint_number, merkle_root)
.await
.map_err(|e| Status::internal(e.to_string()))?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ impl WalletClient for GrpcWalletClient {
&mut self,
contract_id: &FixedHash,
state_root: &StateRoot,
is_initial: bool,
checkpoint_number: u64,
) -> Result<(), DigitalAssetError> {
let inner = self.connection().await?;

if is_initial {
if checkpoint_number == 0 {
let request = CreateInitialAssetCheckpointRequest {
contract_id: contract_id.to_vec(),
merkle_root: state_root.as_bytes().to_vec(),
Expand All @@ -85,6 +85,7 @@ impl WalletClient for GrpcWalletClient {
.map_err(|e| DigitalAssetError::FatalError(format!("Could not create checkpoint:{}", e)))?;
} else {
let request = CreateFollowOnAssetCheckpointRequest {
checkpoint_number,
contract_id: contract_id.to_vec(),
merkle_root: state_root.as_bytes().to_vec(),
};
Expand Down
5 changes: 3 additions & 2 deletions base_layer/core/src/proto/transaction.proto
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,9 @@ message SideChainFeatures {
}

message ContractCheckpoint {
bytes merkle_root = 1;
CommitteeSignatures signatures = 2;
uint64 checkpoint_number = 1;
bytes merkle_root = 2;
CommitteeSignatures signatures = 3;
}

message ContractConstitution {
Expand Down
2 changes: 2 additions & 0 deletions base_layer/core/src/proto/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ impl TryFrom<proto::types::ContractConstitution> for ContractConstitution {
impl From<ContractCheckpoint> for proto::types::ContractCheckpoint {
fn from(value: ContractCheckpoint) -> Self {
Self {
checkpoint_number: value.checkpoint_number,
merkle_root: value.merkle_root.to_vec(),
signatures: Some(value.signatures.into()),
}
Expand All @@ -477,6 +478,7 @@ impl TryFrom<proto::types::ContractCheckpoint> for ContractCheckpoint {
let merkle_root = value.merkle_root.try_into().map_err(|_| "Invalid merkle root")?;
let signatures = value.signatures.map(TryInto::try_into).transpose()?.unwrap_or_default();
Ok(Self {
checkpoint_number: value.checkpoint_number,
merkle_root,
signatures,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ use crate::{
AssetOutputFeatures,
CommitteeDefinitionFeatures,
CommitteeMembers,
CommitteeSignatures,
ContractCheckpoint,
MintNonFungibleFeatures,
OutputType,
Expand Down Expand Up @@ -247,16 +246,9 @@ impl OutputFeatures {
}
}

pub fn for_checkpoint(
contract_id: FixedHash,
merkle_root: FixedHash,
signatures: CommitteeSignatures,
) -> OutputFeatures {
pub fn for_contract_checkpoint(contract_id: FixedHash, checkpoint: ContractCheckpoint) -> OutputFeatures {
let features = SideChainFeatures::builder(contract_id)
.with_contract_checkpoint(ContractCheckpoint {
merkle_root,
signatures,
})
.with_contract_checkpoint(checkpoint)
.finish();

Self {
Expand Down Expand Up @@ -540,11 +532,7 @@ impl Display for OutputFeatures {

#[cfg(test)]
mod test {
use std::{
convert::{TryFrom, TryInto},
io::ErrorKind,
iter,
};
use std::{convert::TryInto, io::ErrorKind, iter};

use tari_common_types::types::Signature;

Expand Down Expand Up @@ -666,6 +654,7 @@ mod test {
activation_window: 0_u64,
}),
checkpoint: Some(ContractCheckpoint {
checkpoint_number: u64::MAX,
merkle_root: FixedHash::zero(),
signatures: vec![Signature::default(); 512].try_into().unwrap(),
}),
Expand Down Expand Up @@ -801,22 +790,17 @@ mod test {
fn test_for_checkpoint() {
let contract_id = FixedHash::hash_bytes("CONTRACT");
let hash = FixedHash::hash_bytes("MERKLE");
let signatures = CommitteeSignatures::try_from(vec![Signature::default()]).unwrap();
assert_eq!(
OutputFeatures {
output_type: OutputType::ContractCheckpoint,
sidechain_features: Some(
SideChainFeatures::builder(contract_id)
.with_contract_checkpoint(ContractCheckpoint {
merkle_root: hash,
signatures: signatures.clone()
})
.finish()
),
..Default::default()
},
OutputFeatures::for_checkpoint(contract_id, hash, signatures)
);
let checkpoint = ContractCheckpoint {
checkpoint_number: 123,
merkle_root: hash,
signatures: vec![Signature::default()].try_into().unwrap(),
};

let features = OutputFeatures::for_contract_checkpoint(contract_id, checkpoint.clone());
let sidechain_features = features.sidechain_features.as_ref().unwrap();
assert_eq!(features.output_type, OutputType::ContractCheckpoint);
assert_eq!(sidechain_features.contract_id, contract_id);
assert_eq!(*sidechain_features.checkpoint.as_ref().unwrap(), checkpoint);
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ use crate::{

#[derive(Debug, Clone, Hash, PartialEq, Deserialize, Serialize, Eq)]
pub struct ContractCheckpoint {
pub checkpoint_number: u64,
pub merkle_root: FixedHash,
pub signatures: CommitteeSignatures,
}

impl ConsensusEncoding for ContractCheckpoint {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.checkpoint_number.consensus_encode(writer)?;
self.merkle_root.consensus_encode(writer)?;
self.signatures.consensus_encode(writer)?;
Ok(())
Expand All @@ -49,6 +51,7 @@ impl ConsensusEncodingSized for ContractCheckpoint {}
impl ConsensusDecoding for ContractCheckpoint {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, Error> {
Ok(Self {
checkpoint_number: u64::consensus_decode(reader)?,
merkle_root: ConsensusDecoding::consensus_decode(reader)?,
signatures: ConsensusDecoding::consensus_decode(reader)?,
})
Expand All @@ -67,6 +70,7 @@ mod tests {
#[test]
fn it_encodes_and_decodes_correctly() {
let subject = ContractCheckpoint {
checkpoint_number: u64::MAX,
merkle_root: FixedHash::zero(),
signatures: vec![Signature::default(); 512].try_into().unwrap(),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ mod tests {
activation_window: 0_u64,
}),
checkpoint: Some(ContractCheckpoint {
checkpoint_number: u64::MAX,
merkle_root: FixedHash::zero(),
signatures: vec![Signature::default(); 512].try_into().unwrap(),
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use crate::{
SideChainFeatures,
TransactionOutput,
},
validation::ValidationError,
validation::{dan_validators::DanLayerValidationError, ValidationError},
};

/// This validator checks that the provided output corresponds to a valid Contract Acceptance in the DAN layer
Expand Down Expand Up @@ -68,12 +68,12 @@ pub fn validate_acceptance<B: BlockchainBackend>(
}

/// Retrieves a contract acceptance object from the sidechain features, returns an error if not present
fn get_contract_acceptance(sidechain_feature: &SideChainFeatures) -> Result<&ContractAcceptance, ValidationError> {
fn get_contract_acceptance(
sidechain_feature: &SideChainFeatures,
) -> Result<&ContractAcceptance, DanLayerValidationError> {
match sidechain_feature.acceptance.as_ref() {
Some(acceptance) => Ok(acceptance),
None => Err(ValidationError::DanLayerError(
"Contract acceptance features not found".to_string(),
)),
None => Err(DanLayerValidationError::ContractAcceptanceNotFound),
}
}

Expand All @@ -89,14 +89,14 @@ fn validate_uniqueness<B: BlockchainBackend>(
.filter_map(|feature| feature.acceptance)
.find(|feature| feature.validator_node_public_key == *validator_node_public_key)
{
Some(_) => {
let msg = format!(
"Duplicated contract acceptance for contract_id ({:?}) and validator_node_public_key ({:?})",
contract_id.to_hex(),
validator_node_public_key,
);
Err(ValidationError::DanLayerError(msg))
},
Some(_) => Err(ValidationError::DanLayerError(DanLayerValidationError::DuplicateUtxo {
contract_id,
output_type: OutputType::ContractValidatorAcceptance,
details: format!(
"Validator ({}) sent duplicate acceptance UTXO",
validator_node_public_key.to_hex(),
),
})),
None => Ok(()),
}
}
Expand All @@ -105,17 +105,12 @@ fn validate_uniqueness<B: BlockchainBackend>(
fn validate_public_key(
constitution: &ContractConstitution,
validator_node_public_key: &PublicKey,
) -> Result<(), ValidationError> {
let is_validator_in_committee = constitution
.validator_committee
.members()
.contains(validator_node_public_key);
) -> Result<(), DanLayerValidationError> {
let is_validator_in_committee = constitution.validator_committee.contains(validator_node_public_key);
if !is_validator_in_committee {
let msg = format!(
"Validator node public key is not in committee ({:?})",
validator_node_public_key
);
return Err(ValidationError::DanLayerError(msg));
return Err(DanLayerValidationError::ValidatorNotInCommittee {
public_key: validator_node_public_key.to_hex(),
});
}

Ok(())
Expand All @@ -133,11 +128,9 @@ fn validate_acceptance_window<B: BlockchainBackend>(

let window_has_expired = current_height > max_allowed_absolute_height;
if window_has_expired {
let msg = format!(
"Acceptance window has expired for contract_id ({})",
contract_id.to_hex()
);
return Err(ValidationError::DanLayerError(msg));
return Err(ValidationError::DanLayerError(
DanLayerValidationError::AcceptanceWindowHasExpired { contract_id },
));
}

Ok(())
Expand All @@ -151,13 +144,9 @@ pub fn fetch_constitution_height<B: BlockchainBackend>(
// Only one constitution should be stored for a particular contract_id
match utxos.first() {
Some(utxo) => Ok(utxo.mined_height),
None => {
let msg = format!(
"Could not find constitution UTXO for contract_id ({})",
contract_id.to_hex(),
);
Err(ValidationError::DanLayerError(msg))
},
None => Err(ValidationError::DanLayerError(
DanLayerValidationError::ContractConstitutionNotFound { contract_id },
)),
}
}

Expand Down Expand Up @@ -247,7 +236,7 @@ mod test {
let (tx, _) = schema_to_transaction(&schema);

// try to validate the duplicated acceptance transaction and check that we get the error
assert_dan_validator_fail(&blockchain, &tx, "Duplicated contract acceptance");
assert_dan_validator_fail(&blockchain, &tx, "sent duplicate acceptance UTXO");
}

#[test]
Expand Down
Loading

0 comments on commit bca7c45

Please sign in to comment.