From 0f581cafe8bd4f922462757504c772c82d0697c7 Mon Sep 17 00:00:00 2001 From: Stan Bondi Date: Wed, 6 Jul 2022 10:30:56 +0200 Subject: [PATCH] feat(dan_layer)!: generate and add checkpoint signatures (#4261) Description --- - feat(dan_layer): generate and add checkpoint signatures - feat(explorer): update text explorer to include signatures - feat(base_layer/wallet): update wallet command file formats - feat(base_layer/core): wires up committee signatures to grpc with conversions - feat(base_layer/core): adds SignerSignature struct for CommitteeSignatures - feat(base_layer/wallet): include committee signatures for checkpoint GRPC requests Motivation and Context --- DAN committees need to collect signatures to include in checkpoints. This PR adds the initial implementation of that. The signature challenge is: `e = H_1(signer_public_key || public_nonce || H_2(contract_id||commitment||merkle_root||checkpoint_number))` Although constructing a challenge with actual data is a TODO as that involves a bit of a refactor. This PR also adds the `SignerSignature` struct that includes the signing public key along with the Schnorr signature tuple ``. This is so that we know which if the validators signed. There may be an aggregate signature scheme that allows this. How Has This Been Tested? --- Manually, initial checkpoint contains signature. --- applications/tari_app_grpc/proto/types.proto | 7 +- applications/tari_app_grpc/proto/wallet.proto | 3 +- .../src/conversions/sidechain_features.rs | 35 +++++- .../src/conversions/signature.rs | 10 +- .../src-tauri/src/clients/wallet_client.rs | 3 +- .../src/grpc/wallet_grpc_server.rs | 18 +++- .../partials/CommitteeSignatures.hbs | 6 +- .../partials/ContractCheckpoint.hbs | 1 + .../partials/SignerSignature.hbs | 4 + .../proto/dan/common.proto | 10 ++ .../proto/dan/consensus.proto | 7 +- .../src/contract_worker_manager.rs | 6 +- .../src/grpc/services/wallet_client.rs | 13 ++- .../src/p2p/proto/conversions.rs | 65 +++++++++-- .../core/src/base_node/proto/wallet_rpc.rs | 4 +- .../src/consensus/consensus_encoding/vec.rs | 9 ++ base_layer/core/src/proto/transaction.proto | 2 +- base_layer/core/src/proto/transaction.rs | 19 ++-- base_layer/core/src/proto/types.proto | 8 +- base_layer/core/src/proto/types_impls.rs | 45 ++++++-- .../transaction_components/output_features.rs | 7 +- .../side_chain/committee_signatures.rs | 33 ++++-- .../side_chain/contract_checkpoint.rs | 9 +- .../transaction_components/side_chain/mod.rs | 3 + .../side_chain/sidechain_features.rs | 5 +- .../side_chain/signer_signature.rs | 101 ++++++++++++++++++ .../proto/recipient_signed_message.rs | 3 +- .../validation/dan_validators/test_helpers.rs | 3 +- base_layer/wallet/src/assets/asset_manager.rs | 8 +- .../wallet/src/assets/asset_manager_handle.rs | 7 +- .../assets/contract_amendment_file_format.rs | 26 +++-- .../infrastructure/asset_manager_service.rs | 13 ++- .../wallet/src/assets/infrastructure/mod.rs | 5 +- .../core/src/models/checkpoint_challenge.rs | 53 +++++++++ .../core/src/models/hot_stuff_message.rs | 35 ++++-- dan_layer/core/src/models/mod.rs | 8 +- .../core/src/models/quorum_certificate.rs | 20 ++-- .../core/src/services/checkpoint_manager.rs | 20 +++- dan_layer/core/src/services/mocks/mod.rs | 12 ++- .../core/src/services/signing_service.rs | 8 +- dan_layer/core/src/services/wallet_client.rs | 2 + dan_layer/core/src/storage/chain/db_qc.rs | 4 +- .../core/src/workers/consensus_worker.rs | 3 +- .../core/src/workers/states/commit_state.rs | 34 +++++- .../core/src/workers/states/decide_state.rs | 9 ++ .../src/sqlite_chain_backend_adapter.rs | 8 +- .../fixtures/contract_amendment.json | 21 ++-- 47 files changed, 587 insertions(+), 148 deletions(-) create mode 100644 applications/tari_explorer/partials/SignerSignature.hbs create mode 100644 base_layer/core/src/transactions/transaction_components/side_chain/signer_signature.rs create mode 100644 dan_layer/core/src/models/checkpoint_challenge.rs diff --git a/applications/tari_app_grpc/proto/types.proto b/applications/tari_app_grpc/proto/types.proto index 16071bd3ae..773270bf02 100644 --- a/applications/tari_app_grpc/proto/types.proto +++ b/applications/tari_app_grpc/proto/types.proto @@ -313,7 +313,12 @@ message ContractAmendment { } message CommitteeSignatures { - repeated Signature signatures = 1; + repeated SignerSignature signatures = 1; +} + +message SignerSignature { + bytes signer = 1; + Signature signature = 2; } // TODO: DEPRECATED diff --git a/applications/tari_app_grpc/proto/wallet.proto b/applications/tari_app_grpc/proto/wallet.proto index 3fdda3d1c7..4b1ccbbc83 100644 --- a/applications/tari_app_grpc/proto/wallet.proto +++ b/applications/tari_app_grpc/proto/wallet.proto @@ -271,7 +271,7 @@ message RegisterAssetResponse { message CreateInitialAssetCheckpointRequest { bytes contract_id = 1; bytes merkle_root = 2; - repeated bytes committee = 3; + CommitteeSignatures committee_signatures = 3; } message CreateInitialAssetCheckpointResponse { @@ -282,6 +282,7 @@ message CreateFollowOnAssetCheckpointRequest { uint64 checkpoint_number = 1; bytes contract_id = 2; bytes merkle_root = 3; + CommitteeSignatures committee_signatures = 4; } message CreateFollowOnAssetCheckpointResponse { diff --git a/applications/tari_app_grpc/src/conversions/sidechain_features.rs b/applications/tari_app_grpc/src/conversions/sidechain_features.rs index abfa8dc32f..dae9f09acb 100644 --- a/applications/tari_app_grpc/src/conversions/sidechain_features.rs +++ b/applications/tari_app_grpc/src/conversions/sidechain_features.rs @@ -20,9 +20,12 @@ // 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::convert::{TryFrom, TryInto}; +use std::{ + borrow::Borrow, + convert::{TryFrom, TryInto}, +}; -use tari_common_types::types::{FixedHash, PublicKey, Signature}; +use tari_common_types::types::{FixedHash, PublicKey}; use tari_core::transactions::transaction_components::{ vec_into_fixed_string, CheckpointParameters, @@ -44,6 +47,7 @@ use tari_core::transactions::transaction_components::{ RequirementsForConstitutionChange, SideChainConsensus, SideChainFeatures, + SignerSignature, }; use tari_utilities::ByteArray; @@ -489,7 +493,7 @@ impl TryFrom for CommitteeMembers { impl From for grpc::CommitteeSignatures { fn from(value: CommitteeSignatures) -> Self { Self { - signatures: value.signatures().into_iter().map(Into::into).collect(), + signatures: value.signatures().iter().map(Into::into).collect(), } } } @@ -511,7 +515,7 @@ impl TryFrom for CommitteeSignatures { .into_iter() .enumerate() .map(|(i, s)| { - Signature::try_from(s) + SignerSignature::try_from(s) .map_err(|err| format!("committee signature #{} was not a valid signature: {}", i + 1, err)) }) .collect::, _>>()?; @@ -521,6 +525,29 @@ impl TryFrom for CommitteeSignatures { } } +//---------------------------------- SignerSignature --------------------------------------------// +impl> From for grpc::SignerSignature { + fn from(value: B) -> Self { + Self { + signer: value.borrow().signer.to_vec(), + signature: Some(grpc::Signature::from(&value.borrow().signature)), + } + } +} + +impl TryFrom for SignerSignature { + type Error = String; + + fn try_from(value: grpc::SignerSignature) -> Result { + Ok(Self { + signer: PublicKey::from_bytes(&value.signer).map_err(|err| err.to_string())?, + signature: value + .signature + .map(TryInto::try_into) + .ok_or("signature not provided")??, + }) + } +} //---------------------------------- ContractAcceptance --------------------------------------------// impl From for grpc::ContractAcceptance { diff --git a/applications/tari_app_grpc/src/conversions/signature.rs b/applications/tari_app_grpc/src/conversions/signature.rs index c9fb21ceec..e00e881b60 100644 --- a/applications/tari_app_grpc/src/conversions/signature.rs +++ b/applications/tari_app_grpc/src/conversions/signature.rs @@ -20,7 +20,7 @@ // 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::convert::TryFrom; +use std::{borrow::Borrow, convert::TryFrom}; use tari_common_types::types::{PrivateKey, PublicKey, Signature}; use tari_utilities::ByteArray; @@ -39,11 +39,11 @@ impl TryFrom for Signature { } } -impl From for grpc::Signature { - fn from(sig: Signature) -> Self { +impl> From for grpc::Signature { + fn from(sig: T) -> Self { Self { - public_nonce: sig.get_public_nonce().to_vec(), - signature: sig.get_signature().to_vec(), + public_nonce: sig.borrow().get_public_nonce().to_vec(), + signature: sig.borrow().get_signature().to_vec(), } } } diff --git a/applications/tari_collectibles/src-tauri/src/clients/wallet_client.rs b/applications/tari_collectibles/src-tauri/src/clients/wallet_client.rs index 81a07a7545..dec9c3aa34 100644 --- a/applications/tari_collectibles/src-tauri/src/clients/wallet_client.rs +++ b/applications/tari_collectibles/src-tauri/src/clients/wallet_client.rs @@ -117,12 +117,11 @@ impl WalletClient { merkle_root: Vec, ) -> Result { let inner = self.get_inner_mut()?; - let committee = vec![]; let request = grpc::CreateInitialAssetCheckpointRequest { // TODO: contract id contract_id: Vec::from_hex(asset_public_key)?, merkle_root, - committee, + committee_signatures: None, }; let result = inner .create_initial_asset_checkpoint(request) diff --git a/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs b/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs index c72622e803..d8df91db53 100644 --- a/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs +++ b/applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs @@ -831,8 +831,15 @@ impl wallet_server::Wallet for WalletGrpcServer { .try_into() .map_err(|_| Status::invalid_argument("Merkle root has an incorrect length"))?; + let committee_signatures = message + .committee_signatures + .map(TryInto::try_into) + .transpose() + .map_err(|_| Status::invalid_argument("Invalid committee signatures"))? + .unwrap_or_default(); + let (tx_id, transaction) = asset_manager - .create_initial_asset_checkpoint(contract_id, merkle_root) + .create_initial_asset_checkpoint(contract_id, merkle_root, committee_signatures) .await .map_err(|e| Status::internal(e.to_string()))?; @@ -865,8 +872,15 @@ impl wallet_server::Wallet for WalletGrpcServer { .try_into() .map_err(|_| Status::invalid_argument("Incorrect merkle root length"))?; + let committee_signatures = message + .committee_signatures + .map(TryInto::try_into) + .transpose() + .map_err(|_| Status::invalid_argument("Invalid committee signatures"))? + .unwrap_or_default(); + let (tx_id, transaction) = asset_manager - .create_follow_on_asset_checkpoint(contract_id, checkpoint_number, merkle_root) + .create_follow_on_asset_checkpoint(contract_id, checkpoint_number, merkle_root, committee_signatures) .await .map_err(|e| Status::internal(e.to_string()))?; diff --git a/applications/tari_explorer/partials/CommitteeSignatures.hbs b/applications/tari_explorer/partials/CommitteeSignatures.hbs index 80c3c74fff..4187208548 100644 --- a/applications/tari_explorer/partials/CommitteeSignatures.hbs +++ b/applications/tari_explorer/partials/CommitteeSignatures.hbs @@ -1,6 +1,8 @@
-
Signatures
+{{#if signatures}} +
{{signatures.length}} signatures
{{#each signatures as |signature|}} -
{{>Signature signature}}
+
{{>SignerSignature signature}}
{{/each}} +{{/if}}
\ No newline at end of file diff --git a/applications/tari_explorer/partials/ContractCheckpoint.hbs b/applications/tari_explorer/partials/ContractCheckpoint.hbs index cc0dade72d..fdaf1bd492 100644 --- a/applications/tari_explorer/partials/ContractCheckpoint.hbs +++ b/applications/tari_explorer/partials/ContractCheckpoint.hbs @@ -1,4 +1,5 @@
+
Number
{{checkpoint_number}}
Merkle root
{{hex merkle_root}}
Signatures
{{>CommitteeSignatures signatures}}
\ No newline at end of file diff --git a/applications/tari_explorer/partials/SignerSignature.hbs b/applications/tari_explorer/partials/SignerSignature.hbs new file mode 100644 index 0000000000..2d342708f0 --- /dev/null +++ b/applications/tari_explorer/partials/SignerSignature.hbs @@ -0,0 +1,4 @@ +
+
Signer
{{hex signer}}
+
Signature
{{>Signature signature}}
+
\ No newline at end of file diff --git a/applications/tari_validator_node/proto/dan/common.proto b/applications/tari_validator_node/proto/dan/common.proto index 28b030c537..1fe3120754 100644 --- a/applications/tari_validator_node/proto/dan/common.proto +++ b/applications/tari_validator_node/proto/dan/common.proto @@ -27,3 +27,13 @@ message Instruction { message InstructionSet{ repeated Instruction instructions = 1; } + +message SignerSignature { + bytes signer = 1; + Signature signature = 2; +} + +message Signature { + bytes public_nonce = 1; + bytes signature = 2; +} diff --git a/applications/tari_validator_node/proto/dan/consensus.proto b/applications/tari_validator_node/proto/dan/consensus.proto index 59db3405b7..80f243e4df 100644 --- a/applications/tari_validator_node/proto/dan/consensus.proto +++ b/applications/tari_validator_node/proto/dan/consensus.proto @@ -22,16 +22,17 @@ message HotStuffMessage { HotStuffMessageType message_type = 2; QuorumCertificate justify = 3; HotStuffTreeNode node= 4; - Signature partial_sig = 5; + ValidatorSignature partial_sig = 5; bytes node_hash = 6; bytes contract_id = 7; + tari.dan.common.SignerSignature checkpoint_signature = 8; } message QuorumCertificate { HotStuffMessageType message_type = 1; bytes node_hash = 2; uint64 view_number = 3; - Signature signature = 4; + ValidatorSignature signature = 4; } message HotStuffTreeNode { @@ -41,7 +42,7 @@ message HotStuffTreeNode { bytes state_root =4; } -message Signature{ +message ValidatorSignature{ } diff --git a/applications/tari_validator_node/src/contract_worker_manager.rs b/applications/tari_validator_node/src/contract_worker_manager.rs index 4f3558738d..05ed32b4fe 100644 --- a/applications/tari_validator_node/src/contract_worker_manager.rs +++ b/applications/tari_validator_node/src/contract_worker_manager.rs @@ -140,9 +140,7 @@ impl ContractWorkerManager { pub async fn start(mut self) -> Result<(), WorkerManagerError> { self.load_initial_state()?; - if self.config.constitution_auto_accept { - info!("constitution_auto_accept is true"); - } + info!("constitution_auto_accept is {}", self.config.constitution_auto_accept); if !self.config.scan_for_assets { info!( @@ -180,7 +178,7 @@ impl ContractWorkerManager { for contract in active_contracts { let contract_id = FixedHash::try_from(contract.contract_id)?; - println!("Starting contract {}", contract_id.to_hex()); + println!("Starting contract {}", contract_id); let constitution = ContractConstitution::from_binary(&*contract.constitution).map_err(|error| { WorkerManagerError::DataCorruption { diff --git a/applications/tari_validator_node/src/grpc/services/wallet_client.rs b/applications/tari_validator_node/src/grpc/services/wallet_client.rs index fc9d0aa61d..4dd1c45710 100644 --- a/applications/tari_validator_node/src/grpc/services/wallet_client.rs +++ b/applications/tari_validator_node/src/grpc/services/wallet_client.rs @@ -23,6 +23,7 @@ use std::net::SocketAddr; use async_trait::async_trait; +use log::*; use tari_app_grpc::{ tari_rpc as grpc, tari_rpc::{ @@ -33,10 +34,13 @@ use tari_app_grpc::{ }, }; use tari_common_types::types::{FixedHash, PublicKey, Signature}; +use tari_core::transactions::transaction_components::SignerSignature; use tari_crypto::tari_utilities::ByteArray; use tari_dan_core::{services::WalletClient, DigitalAssetError}; use tari_dan_engine::state::models::StateRoot; +const LOG_TARGET: &str = "tari::dan::wallet_grpc"; + type Inner = grpc::wallet_client::WalletClient; #[derive(Clone)] @@ -69,14 +73,20 @@ impl WalletClient for GrpcWalletClient { contract_id: &FixedHash, state_root: &StateRoot, checkpoint_number: u64, + checkpoint_signatures: Vec, ) -> Result<(), DigitalAssetError> { let inner = self.connection().await?; + let committee_signatures = grpc::CommitteeSignatures { + signatures: checkpoint_signatures.into_iter().map(Into::into).collect(), + }; + + info!(target: LOG_TARGET, "✅ Creating checkpoint #{}", checkpoint_number); if checkpoint_number == 0 { let request = CreateInitialAssetCheckpointRequest { contract_id: contract_id.to_vec(), merkle_root: state_root.as_bytes().to_vec(), - committee: vec![], + committee_signatures: Some(committee_signatures), }; let _res = inner @@ -88,6 +98,7 @@ impl WalletClient for GrpcWalletClient { checkpoint_number, contract_id: contract_id.to_vec(), merkle_root: state_root.as_bytes().to_vec(), + committee_signatures: Some(committee_signatures), }; let _res = inner diff --git a/applications/tari_validator_node/src/p2p/proto/conversions.rs b/applications/tari_validator_node/src/p2p/proto/conversions.rs index cd54cdc858..eba5926576 100644 --- a/applications/tari_validator_node/src/p2p/proto/conversions.rs +++ b/applications/tari_validator_node/src/p2p/proto/conversions.rs @@ -20,9 +20,13 @@ // 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::convert::{TryFrom, TryInto}; +use std::{ + borrow::Borrow, + convert::{TryFrom, TryInto}, +}; -use tari_common_types::types::PublicKey; +use tari_common_types::types::{PrivateKey, PublicKey, Signature}; +use tari_core::transactions::transaction_components::SignerSignature; use tari_crypto::tari_utilities::ByteArray; use tari_dan_common_types::TemplateId; use tari_dan_core::models::{ @@ -34,9 +38,9 @@ use tari_dan_core::models::{ Node, QuorumCertificate, SideChainBlock, - Signature, TariDanPayload, TreeNodeHash, + ValidatorSignature, ViewId, }; use tari_dan_engine::{ @@ -63,6 +67,7 @@ impl From> for proto::consensus::HotStuffMessage .unwrap_or_else(TreeNodeHash::zero) .as_bytes() .to_vec(), + checkpoint_signature: source.checkpoint_signature().map(Into::into), contract_id: source.contract_id().to_vec(), } } @@ -90,8 +95,8 @@ impl From for proto::consensus::QuorumCertificate { } } -impl From for proto::consensus::Signature { - fn from(_s: Signature) -> Self { +impl From for proto::consensus::ValidatorSignature { + fn from(_s: ValidatorSignature) -> Self { Self {} } } @@ -139,6 +144,7 @@ impl TryFrom for HotStuffMessage for HotStuffTreeNode for Signature { +impl TryFrom for ValidatorSignature { type Error = String; - fn try_from(_value: proto::consensus::Signature) -> Result { + fn try_from(_value: proto::consensus::ValidatorSignature) -> Result { Ok(Self {}) } } @@ -366,3 +372,48 @@ impl TryFrom for StateOpLogEntry { .into()) } } + +//---------------------------------- SignerSignature --------------------------------------------// +impl> From for proto::common::SignerSignature { + fn from(signature: B) -> Self { + Self { + signer: signature.borrow().signer().to_vec(), + signature: Some(signature.borrow().signature().into()), + } + } +} + +impl TryFrom for SignerSignature { + type Error = String; + + fn try_from(value: proto::common::SignerSignature) -> Result { + Ok(Self { + signer: PublicKey::from_bytes(&value.signer).map_err(|err| err.to_string())?, + signature: value + .signature + .map(TryInto::try_into) + .ok_or("signature not provided")??, + }) + } +} + +//---------------------------------- Signature --------------------------------------------// +impl TryFrom for Signature { + type Error = String; + + fn try_from(sig: proto::common::Signature) -> Result { + let public_nonce = PublicKey::from_bytes(&sig.public_nonce).map_err(|e| e.to_string())?; + let signature = PrivateKey::from_bytes(&sig.signature).map_err(|e| e.to_string())?; + + Ok(Self::new(public_nonce, signature)) + } +} + +impl> From for proto::common::Signature { + fn from(sig: T) -> Self { + Self { + public_nonce: sig.borrow().get_public_nonce().to_vec(), + signature: sig.borrow().get_signature().to_vec(), + } + } +} diff --git a/base_layer/core/src/base_node/proto/wallet_rpc.rs b/base_layer/core/src/base_node/proto/wallet_rpc.rs index b2d7797e44..b8ae8d66fc 100644 --- a/base_layer/core/src/base_node/proto/wallet_rpc.rs +++ b/base_layer/core/src/base_node/proto/wallet_rpc.rs @@ -27,7 +27,6 @@ use std::{ use serde::{Deserialize, Serialize}; use tari_common_types::types::{BlockHash, Signature}; -use tari_utilities::ByteArrayError; use crate::proto::{base_node as proto, types}; @@ -220,8 +219,7 @@ impl TryFrom for TxQueryBatchResponse { proto_response .signature .ok_or_else(|| "Signature not present".to_string())?, - ) - .map_err(|err: ByteArrayError| err.to_string())?, + )?, location: TxLocation::try_from( proto::TxLocation::from_i32(proto_response.location) .ok_or_else(|| "Invalid or unrecognised `TxLocation` enum".to_string())?, diff --git a/base_layer/core/src/consensus/consensus_encoding/vec.rs b/base_layer/core/src/consensus/consensus_encoding/vec.rs index 82955c8094..719f325b46 100644 --- a/base_layer/core/src/consensus/consensus_encoding/vec.rs +++ b/base_layer/core/src/consensus/consensus_encoding/vec.rs @@ -58,6 +58,15 @@ impl MaxSizeVec { } Some(Self { inner }) } + + #[must_use = "resulting bool must be checked to ensure that the item was added"] + pub fn push(&mut self, item: T) -> bool { + if self.inner.len() + 1 > MAX { + return false; + } + self.inner.push(item); + true + } } impl Deref for MaxSizeVec { diff --git a/base_layer/core/src/proto/transaction.proto b/base_layer/core/src/proto/transaction.proto index fe30e00632..2e3b82bf9d 100644 --- a/base_layer/core/src/proto/transaction.proto +++ b/base_layer/core/src/proto/transaction.proto @@ -240,7 +240,7 @@ message ContractAmendment { } message CommitteeSignatures { - repeated Signature signatures = 1; + repeated SignerSignature signatures = 1; } // The components of the block or transaction. The same struct can be used for either, since in Mimblewimble, diff --git a/base_layer/core/src/proto/transaction.rs b/base_layer/core/src/proto/transaction.rs index 0f4115a168..4634d2c2b1 100644 --- a/base_layer/core/src/proto/transaction.rs +++ b/base_layer/core/src/proto/transaction.rs @@ -27,7 +27,7 @@ use std::{ sync::Arc, }; -use tari_common_types::types::{BlindingFactor, BulletRangeProof, Commitment, FixedHash, PublicKey, Signature}; +use tari_common_types::types::{BlindingFactor, BulletRangeProof, Commitment, FixedHash, PublicKey}; use tari_crypto::tari_utilities::{ByteArray, ByteArrayError}; use tari_script::{ExecutionStack, TariScript}; use tari_utilities::convert::try_convert_all; @@ -68,6 +68,7 @@ use crate::{ SideChainCheckpointFeatures, SideChainConsensus, SideChainFeatures, + SignerSignature, TemplateParameter, Transaction, TransactionInput, @@ -97,8 +98,7 @@ impl TryFrom for TransactionKernel { let excess_sig = kernel .excess_sig .ok_or_else(|| "excess_sig not provided".to_string())? - .try_into() - .map_err(|err: ByteArrayError| err.to_string())?; + .try_into()?; let kernel_features = u8::try_from(kernel.features).map_err(|_| "Kernel features must be a single byte")?; Ok(TransactionKernel::new( @@ -526,8 +526,7 @@ impl TryFrom for ContractAcceptance { let signature = value .signature .ok_or_else(|| "signature not provided".to_string())? - .try_into() - .map_err(|err: ByteArrayError| err.to_string())?; + .try_into()?; Ok(Self { validator_node_public_key, @@ -555,8 +554,7 @@ impl TryFrom for ContractUpdateProposal { let signature = value .signature .ok_or_else(|| "signature not provided".to_string())? - .try_into() - .map_err(|err: ByteArrayError| err.to_string())?; + .try_into()?; let updated_constitution = value .updated_constitution @@ -592,8 +590,7 @@ impl TryFrom for ContractUpdateP let signature = value .signature .ok_or_else(|| "signature not provided".to_string())? - .try_into() - .map_err(|err: ByteArrayError| err.to_string())?; + .try_into()?; Ok(Self { proposal_id: value.proposal_id, @@ -786,7 +783,7 @@ impl TryFrom for CommitteeMembers { impl From for proto::types::CommitteeSignatures { fn from(value: CommitteeSignatures) -> Self { Self { - signatures: value.signatures().into_iter().map(Into::into).collect(), + signatures: value.signatures().iter().map(Into::into).collect(), } } } @@ -808,7 +805,7 @@ impl TryFrom for CommitteeSignatures { .into_iter() .enumerate() .map(|(i, s)| { - Signature::try_from(s) + SignerSignature::try_from(s) .map_err(|err| format!("committee signature #{} was not a valid signature: {}", i + 1, err)) }) .collect::, _>>()?; diff --git a/base_layer/core/src/proto/types.proto b/base_layer/core/src/proto/types.proto index 3801e2b068..4dcbf9610f 100644 --- a/base_layer/core/src/proto/types.proto +++ b/base_layer/core/src/proto/types.proto @@ -22,6 +22,12 @@ message Signature { bytes signature = 2; } +// Signature containing the signer that signed it +message SignerSignature { + bytes signer = 1; + Signature signature = 2; +} + // Define the explicit ComSignature implementation for the Tari base layer. A different signature scheme can be // employed by redefining this type. message ComSignature { @@ -33,4 +39,4 @@ message ComSignature { // BlindingFactor wrapper message BlindingFactor { bytes data = 1; -} +} \ No newline at end of file diff --git a/base_layer/core/src/proto/types_impls.rs b/base_layer/core/src/proto/types_impls.rs index 149ec5869e..376305f17c 100644 --- a/base_layer/core/src/proto/types_impls.rs +++ b/base_layer/core/src/proto/types_impls.rs @@ -20,7 +20,10 @@ // 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::convert::TryFrom; +use std::{ + borrow::Borrow, + convert::{TryFrom, TryInto}, +}; use tari_common_types::types::{ BlindingFactor, @@ -34,6 +37,7 @@ use tari_common_types::types::{ use tari_utilities::{ByteArray, ByteArrayError}; use super::types as proto; +use crate::transactions::transaction_components::SignerSignature; //---------------------------------- Commitment --------------------------------------------// @@ -54,27 +58,50 @@ impl From for proto::Commitment { } //---------------------------------- Signature --------------------------------------------// - impl TryFrom for Signature { - type Error = ByteArrayError; + type Error = String; fn try_from(sig: proto::Signature) -> Result { - let public_nonce = PublicKey::from_bytes(&sig.public_nonce)?; - let signature = PrivateKey::from_bytes(&sig.signature)?; + let public_nonce = PublicKey::from_bytes(&sig.public_nonce).map_err(|e| e.to_string())?; + let signature = PrivateKey::from_bytes(&sig.signature).map_err(|e| e.to_string())?; Ok(Self::new(public_nonce, signature)) } } -impl From for proto::Signature { - fn from(sig: Signature) -> Self { +impl> From for proto::Signature { + fn from(sig: T) -> Self { Self { - public_nonce: sig.get_public_nonce().to_vec(), - signature: sig.get_signature().to_vec(), + public_nonce: sig.borrow().get_public_nonce().to_vec(), + signature: sig.borrow().get_signature().to_vec(), } } } +//---------------------------------- SignerSignature --------------------------------------------// +impl> From for proto::SignerSignature { + fn from(value: B) -> Self { + Self { + signer: value.borrow().signer.to_vec(), + signature: Some(proto::Signature::from(&value.borrow().signature)), + } + } +} + +impl TryFrom for SignerSignature { + type Error = String; + + fn try_from(value: proto::SignerSignature) -> Result { + Ok(Self { + signer: PublicKey::from_bytes(&value.signer).map_err(|err| err.to_string())?, + signature: value + .signature + .map(TryInto::try_into) + .ok_or("signature not provided")??, + }) + } +} + //---------------------------------- ComSignature --------------------------------------------// impl TryFrom for ComSignature { diff --git a/base_layer/core/src/transactions/transaction_components/output_features.rs b/base_layer/core/src/transactions/transaction_components/output_features.rs index b667752fb5..2bbbfd1ad5 100644 --- a/base_layer/core/src/transactions/transaction_components/output_features.rs +++ b/base_layer/core/src/transactions/transaction_components/output_features.rs @@ -560,6 +560,7 @@ mod test { ContractUpdateProposalAcceptance, FunctionRef, PublicFunction, + SignerSignature, }, }; @@ -647,7 +648,7 @@ mod test { validator_committee: vec![PublicKey::default(); CommitteeMembers::MAX_MEMBERS] .try_into() .unwrap(), - validator_signatures: vec![Signature::default(); CommitteeSignatures::MAX_SIGNATURES] + validator_signatures: vec![SignerSignature::default(); CommitteeSignatures::MAX_SIGNATURES] .try_into() .unwrap(), updated_constitution: constitution, @@ -656,7 +657,7 @@ mod test { checkpoint: Some(ContractCheckpoint { checkpoint_number: u64::MAX, merkle_root: FixedHash::zero(), - signatures: vec![Signature::default(); 512].try_into().unwrap(), + signatures: vec![SignerSignature::default(); 512].try_into().unwrap(), }), }), // Deprecated @@ -793,7 +794,7 @@ mod test { let checkpoint = ContractCheckpoint { checkpoint_number: 123, merkle_root: hash, - signatures: vec![Signature::default()].try_into().unwrap(), + signatures: vec![SignerSignature::default()].try_into().unwrap(), }; let features = OutputFeatures::for_contract_checkpoint(contract_id, checkpoint.clone()); diff --git a/base_layer/core/src/transactions/transaction_components/side_chain/committee_signatures.rs b/base_layer/core/src/transactions/transaction_components/side_chain/committee_signatures.rs index 96c6365c47..df7e7a0d45 100644 --- a/base_layer/core/src/transactions/transaction_components/side_chain/committee_signatures.rs +++ b/base_layer/core/src/transactions/transaction_components/side_chain/committee_signatures.rs @@ -26,22 +26,21 @@ use std::{ }; use serde::{Deserialize, Serialize}; -use tari_common_types::types::Signature; use crate::{ consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized, MaxSizeVec}, - transactions::transaction_components::TransactionError, + transactions::transaction_components::{SignerSignature, TransactionError}, }; #[derive(Debug, Clone, Hash, PartialEq, Deserialize, Serialize, Eq, Default)] pub struct CommitteeSignatures { - signatures: MaxSizeVec, + signatures: MaxSizeVec, } impl CommitteeSignatures { pub const MAX_SIGNATURES: usize = 512; - pub fn new(signatures: MaxSizeVec) -> Self { + pub fn new(signatures: MaxSizeVec) -> Self { Self { signatures } } @@ -52,15 +51,29 @@ impl CommitteeSignatures { } } - pub fn signatures(&self) -> Vec { - self.signatures.to_vec() + pub fn signatures(&self) -> &[SignerSignature] { + &self.signatures + } + + #[must_use = "resulting bool must be checked to ensure that the item was added"] + pub fn push>(&mut self, signature: T) -> bool { + self.signatures.push(signature.into()) + } +} + +impl IntoIterator for CommitteeSignatures { + type IntoIter = as IntoIterator>::IntoIter; + type Item = SignerSignature; + + fn into_iter(self) -> Self::IntoIter { + self.signatures.into_vec().into_iter() } } -impl TryFrom> for CommitteeSignatures { +impl TryFrom> for CommitteeSignatures { type Error = TransactionError; - fn try_from(signatures: Vec) -> Result { + fn try_from(signatures: Vec) -> Result { let len = signatures.len(); let signatures = signatures .try_into() @@ -99,7 +112,7 @@ mod tests { #[test] fn it_encodes_and_decodes_correctly() { let subject = CommitteeSignatures::new( - vec![Signature::default(); CommitteeSignatures::MAX_SIGNATURES] + vec![SignerSignature::default(); CommitteeSignatures::MAX_SIGNATURES] .try_into() .unwrap(), ); @@ -111,7 +124,7 @@ mod tests { #[test] fn it_fails_for_more_than_max_signatures() { - let v = vec![Signature::default(); CommitteeSignatures::MAX_SIGNATURES + 1]; + let v = vec![SignerSignature::default(); CommitteeSignatures::MAX_SIGNATURES + 1]; let encoded = v.to_consensus_bytes(); CommitteeSignatures::consensus_decode(&mut encoded.as_slice()).unwrap_err(); } diff --git a/base_layer/core/src/transactions/transaction_components/side_chain/contract_checkpoint.rs b/base_layer/core/src/transactions/transaction_components/side_chain/contract_checkpoint.rs index b43d00c199..42ac773bd2 100644 --- a/base_layer/core/src/transactions/transaction_components/side_chain/contract_checkpoint.rs +++ b/base_layer/core/src/transactions/transaction_components/side_chain/contract_checkpoint.rs @@ -62,17 +62,18 @@ impl ConsensusDecoding for ContractCheckpoint { mod tests { use std::convert::TryInto; - use tari_common_types::types::Signature; - use super::*; - use crate::consensus::check_consensus_encoding_correctness; + use crate::{ + consensus::check_consensus_encoding_correctness, + transactions::transaction_components::SignerSignature, + }; #[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(), + signatures: vec![SignerSignature::default(); 512].try_into().unwrap(), }; check_consensus_encoding_correctness(subject).unwrap(); } diff --git a/base_layer/core/src/transactions/transaction_components/side_chain/mod.rs b/base_layer/core/src/transactions/transaction_components/side_chain/mod.rs index 448449c8e2..866d4d578b 100644 --- a/base_layer/core/src/transactions/transaction_components/side_chain/mod.rs +++ b/base_layer/core/src/transactions/transaction_components/side_chain/mod.rs @@ -58,6 +58,9 @@ pub use committee_members::CommitteeMembers; mod committee_signatures; pub use committee_signatures::CommitteeSignatures; +mod signer_signature; +pub use signer_signature::SignerSignature; + mod sidechain_features; pub use sidechain_features::{SideChainFeatures, SideChainFeaturesBuilder}; diff --git a/base_layer/core/src/transactions/transaction_components/side_chain/sidechain_features.rs b/base_layer/core/src/transactions/transaction_components/side_chain/sidechain_features.rs index feaf964f32..9e1f682ced 100644 --- a/base_layer/core/src/transactions/transaction_components/side_chain/sidechain_features.rs +++ b/base_layer/core/src/transactions/transaction_components/side_chain/sidechain_features.rs @@ -176,6 +176,7 @@ mod tests { PublicFunction, RequirementsForConstitutionChange, SideChainConsensus, + SignerSignature, }, }; @@ -253,7 +254,7 @@ mod tests { validator_committee: vec![PublicKey::default(); CommitteeMembers::MAX_MEMBERS] .try_into() .unwrap(), - validator_signatures: vec![Signature::default(); CommitteeSignatures::MAX_SIGNATURES] + validator_signatures: vec![SignerSignature::default(); CommitteeSignatures::MAX_SIGNATURES] .try_into() .unwrap(), updated_constitution: constitution, @@ -262,7 +263,7 @@ mod tests { checkpoint: Some(ContractCheckpoint { checkpoint_number: u64::MAX, merkle_root: FixedHash::zero(), - signatures: vec![Signature::default(); 512].try_into().unwrap(), + signatures: vec![SignerSignature::default(); 512].try_into().unwrap(), }), }; diff --git a/base_layer/core/src/transactions/transaction_components/side_chain/signer_signature.rs b/base_layer/core/src/transactions/transaction_components/side_chain/signer_signature.rs new file mode 100644 index 0000000000..95a4dbadab --- /dev/null +++ b/base_layer/core/src/transactions/transaction_components/side_chain/signer_signature.rs @@ -0,0 +1,101 @@ +// 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; + +use digest::Digest; +use rand::rngs::OsRng; +use serde::{Deserialize, Serialize}; +use tari_common_types::types::{HashDigest, PrivateKey, PublicKey, Signature}; +use tari_crypto::keys::PublicKey as PublicKeyT; +use tari_utilities::ByteArray; + +use crate::consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized}; + +#[derive(Debug, Clone, Hash, PartialEq, Deserialize, Serialize, Eq, Default)] +pub struct SignerSignature { + pub signer: PublicKey, + pub signature: Signature, +} + +impl SignerSignature { + pub fn new(signer: PublicKey, signature: Signature) -> Self { + Self { signer, signature } + } + + pub fn sign>(signer_secret: &PrivateKey, challenge: C) -> Self { + let signer = PublicKey::from_secret_key(signer_secret); + let (nonce, public_nonce) = PublicKey::random_keypair(&mut OsRng); + // TODO: Use domain-seperated hasher from tari_crypto + let final_challenge = HashDigest::new() + .chain(signer.as_bytes()) + .chain(public_nonce.as_bytes()) + .chain(challenge) + .finalize(); + let signature = + Signature::sign(signer_secret.clone(), nonce, &*final_challenge).expect("challenge is the correct length"); + Self { signer, signature } + } + + pub fn signer(&self) -> &PublicKey { + &self.signer + } + + pub fn signature(&self) -> &Signature { + &self.signature + } +} + +impl ConsensusEncoding for SignerSignature { + fn consensus_encode(&self, writer: &mut W) -> Result<(), io::Error> { + self.signer.consensus_encode(writer)?; + self.signature.consensus_encode(writer)?; + Ok(()) + } +} + +impl ConsensusEncodingSized for SignerSignature { + fn consensus_encode_exact_size(&self) -> usize { + 32 + 64 + } +} + +impl ConsensusDecoding for SignerSignature { + fn consensus_decode(reader: &mut R) -> Result { + Ok(Self { + signer: PublicKey::consensus_decode(reader)?, + signature: Signature::consensus_decode(reader)?, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::consensus::check_consensus_encoding_correctness; + + #[test] + fn it_encodes_and_decodes_correctly() { + let subject = SignerSignature::default(); + check_consensus_encoding_correctness(subject).unwrap(); + } +} diff --git a/base_layer/core/src/transactions/transaction_protocol/proto/recipient_signed_message.rs b/base_layer/core/src/transactions/transaction_protocol/proto/recipient_signed_message.rs index d931d4c2d2..30fa6ce496 100644 --- a/base_layer/core/src/transactions/transaction_protocol/proto/recipient_signed_message.rs +++ b/base_layer/core/src/transactions/transaction_protocol/proto/recipient_signed_message.rs @@ -42,8 +42,7 @@ impl TryFrom for RecipientSignedMessage { let partial_signature = message .partial_signature .map(TryInto::try_into) - .ok_or_else(|| "Transaction partial signature not provided".to_string())? - .map_err(|err| format!("{}", err))?; + .ok_or_else(|| "Transaction partial signature not provided".to_string())??; Ok(Self { tx_id: message.tx_id.into(), diff --git a/base_layer/core/src/validation/dan_validators/test_helpers.rs b/base_layer/core/src/validation/dan_validators/test_helpers.rs index 2a0465bfaf..ba551a1942 100644 --- a/base_layer/core/src/validation/dan_validators/test_helpers.rs +++ b/base_layer/core/src/validation/dan_validators/test_helpers.rs @@ -49,6 +49,7 @@ use crate::{ OutputFeatures, RequirementsForConstitutionChange, SideChainConsensus, + SignerSignature, Transaction, UnblindedOutput, }, @@ -273,7 +274,7 @@ pub fn create_contract_amendment_schema( proposal_id, updated_constitution: updated_constitution.clone(), validator_committee: updated_constitution.validator_committee, - validator_signatures: vec![Signature::default()].try_into().unwrap(), + validator_signatures: vec![SignerSignature::default()].try_into().unwrap(), activation_window: 100, }; diff --git a/base_layer/wallet/src/assets/asset_manager.rs b/base_layer/wallet/src/assets/asset_manager.rs index 1d0b10cd1e..7b82b95506 100644 --- a/base_layer/wallet/src/assets/asset_manager.rs +++ b/base_layer/wallet/src/assets/asset_manager.rs @@ -179,6 +179,7 @@ impl AssetManager { &mut self, contract_id: FixedHash, merkle_root: FixedHash, + committee_signatures: CommitteeSignatures, ) -> Result<(TxId, Transaction), WalletError> { let output = self .output_manager @@ -187,8 +188,7 @@ impl AssetManager { OutputFeatures::for_contract_checkpoint(contract_id, ContractCheckpoint { checkpoint_number: 0, merkle_root, - // TODO: add vn signatures - signatures: CommitteeSignatures::default(), + signatures: committee_signatures, }), ) .await?; @@ -231,6 +231,7 @@ impl AssetManager { contract_id: FixedHash, checkpoint_number: u64, merkle_root: FixedHash, + committee_signatures: CommitteeSignatures, ) -> Result<(TxId, Transaction), WalletError> { let output = self .output_manager @@ -239,8 +240,7 @@ impl AssetManager { OutputFeatures::for_contract_checkpoint(contract_id, ContractCheckpoint { checkpoint_number, merkle_root, - // TODO: add vn signatures - signatures: CommitteeSignatures::default(), + signatures: committee_signatures, }), ) .await?; diff --git a/base_layer/wallet/src/assets/asset_manager_handle.rs b/base_layer/wallet/src/assets/asset_manager_handle.rs index b883f9567a..4536c15f45 100644 --- a/base_layer/wallet/src/assets/asset_manager_handle.rs +++ b/base_layer/wallet/src/assets/asset_manager_handle.rs @@ -25,6 +25,7 @@ use tari_common_types::{ types::{Commitment, FixedHash, PublicKey, Signature}, }; use tari_core::transactions::transaction_components::{ + CommitteeSignatures, ContractAmendment, ContractDefinition, ContractUpdateProposal, @@ -84,13 +85,14 @@ impl AssetManagerHandle { &mut self, contract_id: FixedHash, merkle_root: FixedHash, + committee_signatures: CommitteeSignatures, ) -> Result<(TxId, Transaction), WalletError> { match self .handle .call(AssetManagerRequest::CreateInitialCheckpoint { contract_id, merkle_root, - committee_public_keys: Vec::new(), + committee_signatures, }) .await?? { @@ -107,6 +109,7 @@ impl AssetManagerHandle { contract_id: FixedHash, checkpoint_number: u64, merkle_root: FixedHash, + committee_signatures: CommitteeSignatures, ) -> Result<(TxId, Transaction), WalletError> { match self .handle @@ -114,7 +117,7 @@ impl AssetManagerHandle { contract_id, checkpoint_number, merkle_root, - committee_public_keys: Vec::new(), + committee_signatures, }) .await?? { diff --git a/base_layer/wallet/src/assets/contract_amendment_file_format.rs b/base_layer/wallet/src/assets/contract_amendment_file_format.rs index 65e4ac720b..897a54a150 100644 --- a/base_layer/wallet/src/assets/contract_amendment_file_format.rs +++ b/base_layer/wallet/src/assets/contract_amendment_file_format.rs @@ -24,7 +24,12 @@ use std::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; use tari_common_types::types::{PrivateKey, PublicKey, Signature}; -use tari_core::transactions::transaction_components::{CommitteeSignatures, ContractAmendment}; +use tari_core::transactions::transaction_components::{ + CommitteeMembers, + CommitteeSignatures, + ContractAmendment, + SignerSignature, +}; use tari_utilities::hex::Hex; use super::ConstitutionDefinitionFileFormat; @@ -42,17 +47,16 @@ impl TryFrom for ContractAmendment { type Error = String; fn try_from(value: ContractAmendmentFileFormat) -> Result { - let validator_signature_vec: Vec = value + let validator_signature_vec = value .validator_signatures .into_iter() .map(TryInto::try_into) - .collect::, _>>()?; - let validator_signatures = - CommitteeSignatures::try_from(validator_signature_vec).map_err(|e| format!("{}", e))?; + .collect::, _>>()?; + let validator_signatures = CommitteeSignatures::try_from(validator_signature_vec).map_err(|e| e.to_string())?; Ok(Self { proposal_id: value.proposal_id, - validator_committee: value.validator_committee.try_into().map_err(|e| format!("{}", e))?, + validator_committee: CommitteeMembers::try_from(value.validator_committee).map_err(|e| e.to_string())?, validator_signatures, updated_constitution: value.updated_constitution.try_into()?, activation_window: value.activation_window, @@ -62,17 +66,19 @@ impl TryFrom for ContractAmendment { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SignatureFileFormat { + pub signer: String, pub public_nonce: String, pub signature: String, } -impl TryFrom for Signature { +impl TryFrom for SignerSignature { type Error = String; fn try_from(value: SignatureFileFormat) -> Result { - let public_key = PublicKey::from_hex(&value.public_nonce).map_err(|e| format!("{}", e))?; - let signature = PrivateKey::from_hex(&value.signature).map_err(|e| format!("{}", e))?; + let signer = PublicKey::from_hex(&value.signer).map_err(|e| e.to_string())?; + let public_key = PublicKey::from_hex(&value.public_nonce).map_err(|e| e.to_string())?; + let signature = PrivateKey::from_hex(&value.signature).map_err(|e| e.to_string())?; - Ok(Signature::new(public_key, signature)) + Ok(SignerSignature::new(signer, Signature::new(public_key, signature))) } } diff --git a/base_layer/wallet/src/assets/infrastructure/asset_manager_service.rs b/base_layer/wallet/src/assets/infrastructure/asset_manager_service.rs index 87a9eba16c..c5147fcb0e 100644 --- a/base_layer/wallet/src/assets/infrastructure/asset_manager_service.rs +++ b/base_layer/wallet/src/assets/infrastructure/asset_manager_service.rs @@ -137,11 +137,11 @@ impl AssetManagerService { AssetManagerRequest::CreateInitialCheckpoint { contract_id, merkle_root, - committee_public_keys: _pks, + committee_signatures, } => { let (tx_id, transaction) = self .manager - .create_initial_asset_checkpoint(contract_id, merkle_root) + .create_initial_asset_checkpoint(contract_id, merkle_root, committee_signatures) .await?; Ok(AssetManagerResponse::CreateInitialCheckpoint { transaction: Box::new(transaction), @@ -152,11 +152,16 @@ impl AssetManagerService { contract_id, checkpoint_number, merkle_root, - committee_public_keys: _pks, + committee_signatures, } => { let (tx_id, transaction) = self .manager - .create_follow_on_contract_checkpoint(contract_id, checkpoint_number, merkle_root) + .create_follow_on_contract_checkpoint( + contract_id, + checkpoint_number, + merkle_root, + committee_signatures, + ) .await?; Ok(AssetManagerResponse::CreateFollowOnCheckpoint { transaction: Box::new(transaction), diff --git a/base_layer/wallet/src/assets/infrastructure/mod.rs b/base_layer/wallet/src/assets/infrastructure/mod.rs index ebf7b89f3b..bf53f6e195 100644 --- a/base_layer/wallet/src/assets/infrastructure/mod.rs +++ b/base_layer/wallet/src/assets/infrastructure/mod.rs @@ -27,6 +27,7 @@ use tari_common_types::{ types::{Commitment, FixedHash, PublicKey, Signature}, }; use tari_core::transactions::transaction_components::{ + CommitteeSignatures, ContractAmendment, ContractDefinition, ContractUpdateProposal, @@ -63,13 +64,13 @@ pub enum AssetManagerRequest { CreateInitialCheckpoint { contract_id: FixedHash, merkle_root: FixedHash, - committee_public_keys: Vec, + committee_signatures: CommitteeSignatures, }, CreateFollowOnCheckpoint { contract_id: FixedHash, checkpoint_number: u64, merkle_root: FixedHash, - committee_public_keys: Vec, + committee_signatures: CommitteeSignatures, }, CreateConstitutionDefinition { constitution_definition: Box, diff --git a/dan_layer/core/src/models/checkpoint_challenge.rs b/dan_layer/core/src/models/checkpoint_challenge.rs new file mode 100644 index 0000000000..e5ef3c8450 --- /dev/null +++ b/dan_layer/core/src/models/checkpoint_challenge.rs @@ -0,0 +1,53 @@ +// 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 digest::Digest; +use tari_common_types::types::{Commitment, FixedHash, HashDigest}; +use tari_utilities::ByteArray; + +#[derive(Debug, Clone, Copy)] +pub struct CheckpointChallenge(FixedHash); + +impl CheckpointChallenge { + pub fn new( + contract_id: &FixedHash, + checkpoint_commitment: &Commitment, + merkle_root: FixedHash, + checkpoint_number: u64, + ) -> Self { + // TODO: Use new tari_crypto domain-separated hashing + let hash = HashDigest::new() + .chain(contract_id.as_slice()) + .chain(checkpoint_commitment.as_bytes()) + .chain(merkle_root.as_slice()) + .chain(&checkpoint_number.to_le_bytes()) + .finalize() + .into(); + Self(hash) + } +} + +impl AsRef<[u8]> for CheckpointChallenge { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} diff --git a/dan_layer/core/src/models/hot_stuff_message.rs b/dan_layer/core/src/models/hot_stuff_message.rs index b145ac993f..1ac685dc28 100644 --- a/dan_layer/core/src/models/hot_stuff_message.rs +++ b/dan_layer/core/src/models/hot_stuff_message.rs @@ -22,6 +22,7 @@ use digest::Digest; use tari_common_types::types::FixedHash; +use tari_core::transactions::transaction_components::SignerSignature; use tari_crypto::common::Blake256; use crate::models::{ @@ -29,8 +30,8 @@ use crate::models::{ HotStuffTreeNode, Payload, QuorumCertificate, - Signature, TreeNodeHash, + ValidatorSignature, ViewId, }; @@ -41,7 +42,8 @@ pub struct HotStuffMessage { justify: Option, node: Option>, node_hash: Option, - partial_sig: Option, + partial_sig: Option, + checkpoint_signature: Option, contract_id: FixedHash, } @@ -52,16 +54,18 @@ impl HotStuffMessage { justify: Option, node: Option>, node_hash: Option, - partial_sig: Option, + partial_sig: Option, + checkpoint_signature: Option, contract_id: FixedHash, ) -> Self { - HotStuffMessage { + Self { view_number, message_type, justify, node, node_hash, partial_sig, + checkpoint_signature, contract_id, } } @@ -73,6 +77,7 @@ impl HotStuffMessage { justify: Some(prepare_qc), node: None, partial_sig: None, + checkpoint_signature: None, node_hash: None, contract_id, } @@ -90,6 +95,7 @@ impl HotStuffMessage { justify: high_qc, view_number, partial_sig: None, + checkpoint_signature: None, node_hash: None, contract_id, } @@ -102,6 +108,7 @@ impl HotStuffMessage { view_number, node: None, partial_sig: None, + checkpoint_signature: None, justify: None, contract_id, } @@ -119,6 +126,7 @@ impl HotStuffMessage { justify: prepare_qc, view_number, node_hash: None, + checkpoint_signature: None, partial_sig: None, contract_id, } @@ -131,6 +139,7 @@ impl HotStuffMessage { view_number, node: None, partial_sig: None, + checkpoint_signature: None, justify: None, contract_id, } @@ -148,18 +157,25 @@ impl HotStuffMessage { justify: pre_commit_qc, view_number, partial_sig: None, + checkpoint_signature: None, node_hash: None, contract_id, } } - pub fn vote_commit(node_hash: TreeNodeHash, view_number: ViewId, contract_id: FixedHash) -> Self { + pub fn vote_commit( + node_hash: TreeNodeHash, + view_number: ViewId, + contract_id: FixedHash, + checkpoint_signature: SignerSignature, + ) -> Self { Self { message_type: HotStuffMessageType::Commit, node_hash: Some(node_hash), view_number, node: None, partial_sig: None, + checkpoint_signature: Some(checkpoint_signature), justify: None, contract_id, } @@ -177,6 +193,7 @@ impl HotStuffMessage { justify: commit_qc, view_number, partial_sig: None, + checkpoint_signature: None, node_hash: None, contract_id, } @@ -224,11 +241,15 @@ impl HotStuffMessage { self.message_type() == message_type && view_id == self.view_number() } - pub fn add_partial_sig(&mut self, signature: Signature) { + pub fn add_partial_sig(&mut self, signature: ValidatorSignature) { self.partial_sig = Some(signature) } - pub fn partial_sig(&self) -> Option<&Signature> { + pub fn partial_sig(&self) -> Option<&ValidatorSignature> { self.partial_sig.as_ref() } + + pub fn checkpoint_signature(&self) -> Option<&SignerSignature> { + self.checkpoint_signature.as_ref() + } } diff --git a/dan_layer/core/src/models/mod.rs b/dan_layer/core/src/models/mod.rs index a39acc8c2f..c202a79ea6 100644 --- a/dan_layer/core/src/models/mod.rs +++ b/dan_layer/core/src/models/mod.rs @@ -25,6 +25,7 @@ use std::{convert::TryFrom, fmt::Debug, hash::Hash}; mod asset_definition; mod base_layer_metadata; mod base_layer_output; +mod checkpoint_challenge; mod committee; pub mod domain_events; mod error; @@ -44,6 +45,7 @@ mod view_id; pub use asset_definition::{AssetDefinition, InitialState}; pub use base_layer_metadata::BaseLayerMetadata; pub use base_layer_output::{BaseLayerOutput, CheckpointOutput, CommitteeOutput}; +pub use checkpoint_challenge::CheckpointChallenge; pub use committee::Committee; pub use error::ModelError; pub use hot_stuff_message::HotStuffMessage; @@ -156,14 +158,14 @@ pub enum ConsensusWorkerState { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Signature {} +pub struct ValidatorSignature {} -impl Signature { +impl ValidatorSignature { pub fn from_bytes(_source: &[u8]) -> Self { Self {} } - pub fn combine(&self, other: &Signature) -> Signature { + pub fn combine(&self, other: &ValidatorSignature) -> ValidatorSignature { other.clone() } diff --git a/dan_layer/core/src/models/quorum_certificate.rs b/dan_layer/core/src/models/quorum_certificate.rs index 6b3ab7d433..ee929b00e5 100644 --- a/dan_layer/core/src/models/quorum_certificate.rs +++ b/dan_layer/core/src/models/quorum_certificate.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - models::{HotStuffMessageType, Signature, TreeNodeHash, ViewId}, + models::{HotStuffMessageType, TreeNodeHash, ValidatorSignature, ViewId}, storage::chain::DbQc, }; @@ -30,7 +30,7 @@ pub struct QuorumCertificate { message_type: HotStuffMessageType, node_hash: TreeNodeHash, view_number: ViewId, - signature: Option, + signatures: Option, } impl QuorumCertificate { @@ -38,13 +38,13 @@ impl QuorumCertificate { message_type: HotStuffMessageType, view_number: ViewId, node_hash: TreeNodeHash, - signature: Option, + signature: Option, ) -> Self { Self { message_type, node_hash, view_number, - signature, + signatures: signature, } } @@ -53,7 +53,7 @@ impl QuorumCertificate { message_type: HotStuffMessageType::Genesis, node_hash, view_number: 0.into(), - signature: None, + signatures: None, } } @@ -69,12 +69,12 @@ impl QuorumCertificate { self.message_type } - pub fn signature(&self) -> Option<&Signature> { - self.signature.as_ref() + pub fn signature(&self) -> Option<&ValidatorSignature> { + self.signatures.as_ref() } - pub fn combine_sig(&mut self, partial_sig: &Signature) { - self.signature = match &self.signature { + pub fn combine_sig(&mut self, partial_sig: &ValidatorSignature) { + self.signatures = match &self.signatures { None => Some(partial_sig.clone()), Some(s) => Some(s.combine(partial_sig)), }; @@ -92,7 +92,7 @@ impl From for QuorumCertificate { message_type: rec.message_type, node_hash: rec.node_hash, view_number: rec.view_number, - signature: rec.signature, + signatures: rec.signature, } } } diff --git a/dan_layer/core/src/services/checkpoint_manager.rs b/dan_layer/core/src/services/checkpoint_manager.rs index 04c9881263..d60a025d14 100644 --- a/dan_layer/core/src/services/checkpoint_manager.rs +++ b/dan_layer/core/src/services/checkpoint_manager.rs @@ -22,6 +22,7 @@ use async_trait::async_trait; use log::*; +use tari_core::transactions::transaction_components::SignerSignature; use tari_dan_engine::state::models::StateRoot; use crate::{models::AssetDefinition, services::wallet_client::WalletClient, DigitalAssetError}; @@ -30,7 +31,11 @@ const LOG_TARGET: &str = "tari::dan::checkpoint_manager"; #[async_trait] pub trait CheckpointManager { - async fn create_checkpoint(&mut self, state_root: StateRoot) -> Result<(), DigitalAssetError>; + async fn create_checkpoint( + &mut self, + state_root: StateRoot, + signature: Vec, + ) -> Result<(), DigitalAssetError>; } #[derive(Default)] @@ -54,7 +59,11 @@ impl ConcreteCheckpointManager { #[async_trait] impl CheckpointManager for ConcreteCheckpointManager { - async fn create_checkpoint(&mut self, state_root: StateRoot) -> Result<(), DigitalAssetError> { + async fn create_checkpoint( + &mut self, + state_root: StateRoot, + signatures: Vec, + ) -> Result<(), DigitalAssetError> { if self.num_calls == 0 || self.num_calls >= self.checkpoint_interval { // TODO: fetch and increment checkpoint number let checkpoint_number = u64::from(self.num_calls / self.checkpoint_interval); @@ -63,7 +72,12 @@ impl CheckpointManager for ConcreteCheckpoi "Creating checkpoint for contract {}", self.asset_definition.contract_id ); self.wallet - .create_new_checkpoint(&self.asset_definition.contract_id, &state_root, checkpoint_number) + .create_new_checkpoint( + &self.asset_definition.contract_id, + &state_root, + checkpoint_number, + signatures, + ) .await?; } self.num_calls += 1; diff --git a/dan_layer/core/src/services/mocks/mod.rs b/dan_layer/core/src/services/mocks/mod.rs index 2de451e2b1..d4bdbd1947 100644 --- a/dan_layer/core/src/services/mocks/mod.rs +++ b/dan_layer/core/src/services/mocks/mod.rs @@ -28,7 +28,10 @@ use std::{ use async_trait::async_trait; use tari_common_types::types::{FixedHash, PublicKey}; -use tari_core::{chain_storage::UtxoMinedInfo, transactions::transaction_components::OutputType}; +use tari_core::{ + chain_storage::UtxoMinedInfo, + transactions::transaction_components::{OutputType, SignerSignature}, +}; use tari_crypto::ristretto::RistrettoPublicKey; use tari_dan_common_types::TemplateId; #[cfg(test)] @@ -56,9 +59,9 @@ use crate::{ Payload, SideChainBlock, SidechainMetadata, - Signature, TariDanPayload, TreeNodeHash, + ValidatorSignature, }, services::{ base_node_client::BaseNodeClient, @@ -207,8 +210,8 @@ pub struct MockSigningService { } impl SigningService for MockSigningService { - fn sign(&self, _identity: &TAddr, _challenge: &[u8]) -> Result { - Ok(Signature {}) + fn sign(&self, _identity: &TAddr, _challenge: &[u8]) -> Result { + Ok(ValidatorSignature {}) } } @@ -342,6 +345,7 @@ impl WalletClient for MockWalletClient { _contract_id: &FixedHash, _state_root: &StateRoot, _checkpoint_number: u64, + _checkpoint_signatures: Vec, ) -> Result<(), DigitalAssetError> { Ok(()) } diff --git a/dan_layer/core/src/services/signing_service.rs b/dan_layer/core/src/services/signing_service.rs index 2558ea661a..873267e09a 100644 --- a/dan_layer/core/src/services/signing_service.rs +++ b/dan_layer/core/src/services/signing_service.rs @@ -26,12 +26,12 @@ use tari_comms::{types::CommsPublicKey, NodeIdentity}; use crate::{ digital_assets_error::DigitalAssetError, - models::Signature, + models::ValidatorSignature, services::infrastructure_services::NodeAddressable, }; pub trait SigningService { - fn sign(&self, identity: &TAddr, challenge: &[u8]) -> Result; + fn sign(&self, identity: &TAddr, challenge: &[u8]) -> Result; } pub struct NodeIdentitySigningService { @@ -45,12 +45,12 @@ impl NodeIdentitySigningService { } impl SigningService for NodeIdentitySigningService { - fn sign(&self, identity: &CommsPublicKey, _challenge: &[u8]) -> Result { + fn sign(&self, identity: &CommsPublicKey, _challenge: &[u8]) -> Result { if identity != self.node_identity.public_key() { return Err(DigitalAssetError::InvalidSignature); } // TODO better sig - Ok(Signature {}) + Ok(ValidatorSignature {}) } } diff --git a/dan_layer/core/src/services/wallet_client.rs b/dan_layer/core/src/services/wallet_client.rs index 3ed857c6b6..6906107e67 100644 --- a/dan_layer/core/src/services/wallet_client.rs +++ b/dan_layer/core/src/services/wallet_client.rs @@ -22,6 +22,7 @@ use async_trait::async_trait; use tari_common_types::types::{FixedHash, PublicKey, Signature}; +use tari_core::transactions::transaction_components::SignerSignature; use tari_dan_engine::state::models::StateRoot; use crate::DigitalAssetError; @@ -33,6 +34,7 @@ pub trait WalletClient: Send + Sync { contract_id: &FixedHash, state_root: &StateRoot, checkpoint_number: u64, + checkpoint_signatures: Vec, ) -> Result<(), DigitalAssetError>; async fn submit_contract_acceptance( diff --git a/dan_layer/core/src/storage/chain/db_qc.rs b/dan_layer/core/src/storage/chain/db_qc.rs index 6ede3272e6..8763ad30b0 100644 --- a/dan_layer/core/src/storage/chain/db_qc.rs +++ b/dan_layer/core/src/storage/chain/db_qc.rs @@ -20,12 +20,12 @@ // 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 crate::models::{HotStuffMessageType, Signature, TreeNodeHash, ViewId}; +use crate::models::{HotStuffMessageType, TreeNodeHash, ValidatorSignature, ViewId}; #[derive(Debug, Clone)] pub struct DbQc { pub message_type: HotStuffMessageType, pub view_number: ViewId, pub node_hash: TreeNodeHash, - pub signature: Option, + pub signature: Option, } diff --git a/dan_layer/core/src/workers/consensus_worker.rs b/dan_layer/core/src/workers/consensus_worker.rs index 633f9ce6c8..61b25de7c6 100644 --- a/dan_layer/core/src/workers/consensus_worker.rs +++ b/dan_layer/core/src/workers/consensus_worker.rs @@ -312,9 +312,10 @@ impl<'a, T: ServiceSpecification> ConsensusWorkerProcessor<'a, unit_of_work.commit()?; if let Some(mut state_tx) = self.worker.state_db_unit_of_work.take() { state_tx.commit()?; + let signatures = state.collected_checkpoint_signatures(); self.worker .checkpoint_manager - .create_checkpoint(state_tx.calculate_root()?) + .create_checkpoint(state_tx.calculate_root()?, signatures) .await?; Ok(res) } else { diff --git a/dan_layer/core/src/workers/states/commit_state.rs b/dan_layer/core/src/workers/states/commit_state.rs index b4097252dc..1ba3a374d8 100644 --- a/dan_layer/core/src/workers/states/commit_state.rs +++ b/dan_layer/core/src/workers/states/commit_state.rs @@ -23,12 +23,24 @@ use std::collections::HashMap; use log::*; -use tari_common_types::types::FixedHash; +use rand::rngs::OsRng; +use tari_common_types::types::{Commitment, FixedHash, PrivateKey}; +use tari_core::transactions::transaction_components::SignerSignature; +use tari_crypto::keys::SecretKey; use tokio::time::{sleep, Duration}; use crate::{ digital_assets_error::DigitalAssetError, - models::{Committee, HotStuffMessage, HotStuffMessageType, QuorumCertificate, TreeNodeHash, View, ViewId}, + models::{ + CheckpointChallenge, + Committee, + HotStuffMessage, + HotStuffMessageType, + QuorumCertificate, + TreeNodeHash, + View, + ViewId, + }, services::{ infrastructure_services::{InboundConnectionService, OutboundService}, ServiceSpecification, @@ -154,6 +166,21 @@ impl CommitState { .await } + fn generate_checkpoint_signature(&self) -> SignerSignature { + // TODO: wire in the signer secret (probably node identity) + let signer_secret = PrivateKey::random(&mut OsRng); + // TODO: Validators should have agreed on a checkpoint commitment and included this in the signature for base + // layer validation + let commitment = Commitment::default(); + // TODO: We need the finalized state root to be able to produce a signature + let state_root = FixedHash::zero(); + // TODO: Load next checkpoint number from db + let checkpoint_number = 0; + + let challenge = CheckpointChallenge::new(&self.contract_id, &commitment, state_root, checkpoint_number); + SignerSignature::sign(&signer_secret, challenge) + } + fn create_qc(&self, current_view: &View) -> Option { // TODO: This can be done in one loop instead of two let mut node_hash = None; @@ -235,7 +262,8 @@ impl CommitState { view_number: ViewId, signing_service: &TSpecification::SigningService, ) -> Result<(), DigitalAssetError> { - let mut message = HotStuffMessage::vote_commit(node, view_number, self.contract_id); + let checkpoint_signature = self.generate_checkpoint_signature(); + let mut message = HotStuffMessage::vote_commit(node, view_number, self.contract_id, checkpoint_signature); message.add_partial_sig(signing_service.sign(&self.node_id, &message.create_signature_challenge())?); outbound.send(self.node_id.clone(), view_leader.clone(), message).await } diff --git a/dan_layer/core/src/workers/states/decide_state.rs b/dan_layer/core/src/workers/states/decide_state.rs index 422e17df9d..c3486f953c 100644 --- a/dan_layer/core/src/workers/states/decide_state.rs +++ b/dan_layer/core/src/workers/states/decide_state.rs @@ -24,6 +24,7 @@ use std::collections::HashMap; use log::*; use tari_common_types::types::FixedHash; +use tari_core::transactions::transaction_components::SignerSignature; use tari_utilities::hex::Hex; use tokio::time::{sleep, Duration}; @@ -114,6 +115,7 @@ impl DecideState { warn!(target: LOG_TARGET, "Already received message from {:?}", &sender); return Ok(None); } + debug!(target: LOG_TARGET, "MSG={:?}", message); self.received_new_view_messages.insert(sender.clone(), message); @@ -219,4 +221,11 @@ impl DecideState { Ok(None) } } + + pub fn collected_checkpoint_signatures(&self) -> Vec { + self.received_new_view_messages + .values() + .filter_map(|msg| msg.checkpoint_signature().cloned()) + .collect() + } } diff --git a/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs b/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs index 7eebbbc743..f48f95618f 100644 --- a/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs +++ b/dan_layer/storage_sqlite/src/sqlite_chain_backend_adapter.rs @@ -25,7 +25,7 @@ use std::convert::{TryFrom, TryInto}; use diesel::{prelude::*, Connection, SqliteConnection}; use log::*; use tari_dan_core::{ - models::{HotStuffMessageType, QuorumCertificate, Signature, TariDanPayload, TreeNodeHash, ViewId}, + models::{HotStuffMessageType, QuorumCertificate, TariDanPayload, TreeNodeHash, ValidatorSignature, ViewId}, storage::chain::{ChainDbBackendAdapter, DbInstruction, DbNode, DbQc}, }; use tari_utilities::ByteArray; @@ -273,7 +273,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { HotStuffMessageType::try_from(u8::try_from(qc.message_type).unwrap()).unwrap(), ViewId::from(qc.view_number as u64), qc.node_hash.try_into()?, - qc.signature.map(|s| Signature::from_bytes(s.as_slice())), + qc.signature.map(|s| ValidatorSignature::from_bytes(s.as_slice())), )) }) .transpose() @@ -336,7 +336,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { HotStuffMessageType::try_from(u8::try_from(qc.message_type).unwrap()).unwrap(), ViewId::from(qc.view_number as u64), qc.node_hash.try_into()?, - qc.signature.map(|s| Signature::from_bytes(s.as_slice())), + qc.signature.map(|s| ValidatorSignature::from_bytes(s.as_slice())), )) } @@ -355,7 +355,7 @@ impl ChainDbBackendAdapter for SqliteChainBackendAdapter { HotStuffMessageType::try_from(u8::try_from(qc.message_type).unwrap()).unwrap(), ViewId::from(qc.view_number as u64), qc.node_hash.try_into()?, - qc.signature.map(|s| Signature::from_bytes(s.as_slice())), + qc.signature.map(|s| ValidatorSignature::from_bytes(s.as_slice())), )) } diff --git a/integration_tests/fixtures/contract_amendment.json b/integration_tests/fixtures/contract_amendment.json index 13b31ce6f1..7fd9a90ddf 100644 --- a/integration_tests/fixtures/contract_amendment.json +++ b/integration_tests/fixtures/contract_amendment.json @@ -7,16 +7,25 @@ ], "validator_signatures": [ { - "public_nonce": "3431860a4f70ddd6748d759cf66179321809e1c120a97cbdbbf2c01af5c8802f", - "signature": "be1b1e7cd18210bfced717d39bebc2534b31274976fb141856d9ee2bfe571900" + "signer": "ccac168b8edd67b10d152d1ed2337efc65da9fc0b6256dd49b3c559032553d44", + "signature": { + "public_nonce": "3431860a4f70ddd6748d759cf66179321809e1c120a97cbdbbf2c01af5c8802f", + "signature": "be1b1e7cd18210bfced717d39bebc2534b31274976fb141856d9ee2bfe571900" + } }, { - "public_nonce": "3431860a4f70ddd6748d759cf66179321809e1c120a97cbdbbf2c01af5c8802f", - "signature": "be1b1e7cd18210bfced717d39bebc2534b31274976fb141856d9ee2bfe571900" + "signer": "ccac168b8edd67b10d152d1ed2337efc65da9fc0b6256dd49b3c559032553d44", + "signature": { + "public_nonce": "3431860a4f70ddd6748d759cf66179321809e1c120a97cbdbbf2c01af5c8802f", + "signature": "be1b1e7cd18210bfced717d39bebc2534b31274976fb141856d9ee2bfe571900" + } }, { - "public_nonce": "3431860a4f70ddd6748d759cf66179321809e1c120a97cbdbbf2c01af5c8802f", - "signature": "be1b1e7cd18210bfced717d39bebc2534b31274976fb141856d9ee2bfe571900" + "signer": "ccac168b8edd67b10d152d1ed2337efc65da9fc0b6256dd49b3c559032553d44", + "signature": { + "public_nonce": "3431860a4f70ddd6748d759cf66179321809e1c120a97cbdbbf2c01af5c8802f", + "signature": "be1b1e7cd18210bfced717d39bebc2534b31274976fb141856d9ee2bfe571900" + } } ], "updated_constitution": {