Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: add committee management utxo #3835

Merged
merged 17 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,7 @@ node_modules
buildtools/Output/
/applications/tari_collectibles/src-tauri/data

# Asset files
assets/
# some folders called assets are kind of important now
# any specific "assets" folders should be gitignored
# closer to where they live
#assets/
7 changes: 6 additions & 1 deletion applications/tari_app_grpc/proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ message TransactionOutput {
uint32 version = 9;
}

// Options for UTXO's
// Options for UTXOs
message OutputFeatures {
// Flags are the feature flags that differentiate between outputs, eg Coinbase all of which has different rules
uint32 flags = 1;
Expand All @@ -225,6 +225,7 @@ message OutputFeatures {
SideChainCheckpointFeatures sidechain_checkpoint = 8;
// Version
uint32 version = 9;
CommitteeDefinitionFeatures committee_definition = 10;
}

message AssetOutputFeatures {
Expand All @@ -249,6 +250,10 @@ message SideChainCheckpointFeatures {
repeated bytes committee = 2;
}

message CommitteeDefinitionFeatures {
repeated bytes committee = 1;
uint64 effective_sidechain_height = 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
Expand Down
11 changes: 11 additions & 0 deletions applications/tari_app_grpc/proto/wallet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ service Wallet {
rpc CreateInitialAssetCheckpoint(CreateInitialAssetCheckpointRequest) returns (CreateInitialAssetCheckpointResponse);
// TODO: Needs a better name pls
rpc CreateFollowOnAssetCheckpoint(CreateFollowOnAssetCheckpointRequest) returns (CreateFollowOnAssetCheckpointResponse);
rpc CreateCommitteeDefinition(CreateCommitteeDefinitionRequest) returns (CreateCommitteeDefinitionResponse);

rpc GetOwnedAssets(Empty) returns (GetOwnedAssetsResponse);

Expand Down Expand Up @@ -282,6 +283,16 @@ message CreateFollowOnAssetCheckpointResponse {

}

message CreateCommitteeDefinitionRequest {
bytes asset_public_key = 1;
repeated bytes committee = 2;
uint64 effective_sidechain_height = 3;
}

message CreateCommitteeDefinitionResponse {

}

message GetOwnedAssetsResponse {
repeated Asset assets = 1;
}
Expand Down
34 changes: 33 additions & 1 deletion applications/tari_app_grpc/src/conversions/output_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use tari_common_types::{
};
use tari_core::transactions::transaction_components::{
AssetOutputFeatures,
CommitteeDefinitionFeatures,
MintNonFungibleFeatures,
OutputFeatures,
OutputFeaturesVersion,
Expand Down Expand Up @@ -66,7 +67,8 @@ impl TryFrom<grpc::OutputFeatures> for OutputFeatures {
parent_public_key,
features.asset.map(|a| a.try_into()).transpose()?,
features.mint_non_fungible.map(|m| m.try_into()).transpose()?,
features.sidechain_checkpoint.map(|m| m.try_into()).transpose()?,
features.sidechain_checkpoint.map(|s| s.try_into()).transpose()?,
features.committee_definition.map(|c| c.try_into()).transpose()?,
))
}
}
Expand All @@ -86,6 +88,7 @@ impl From<OutputFeatures> for grpc::OutputFeatures {
mint_non_fungible: features.mint_non_fungible.map(|m| m.into()),
sidechain_checkpoint: features.sidechain_checkpoint.map(|m| m.into()),
version: features.version as u32,
committee_definition: features.committee_definition.map(|c| c.into()),
}
}
}
Expand Down Expand Up @@ -184,3 +187,32 @@ impl TryFrom<grpc::SideChainCheckpointFeatures> for SideChainCheckpointFeatures
Ok(Self { merkle_root, committee })
}
}

impl From<CommitteeDefinitionFeatures> for grpc::CommitteeDefinitionFeatures {
fn from(value: CommitteeDefinitionFeatures) -> Self {
Self {
committee: value.committee.iter().map(|c| c.as_bytes().to_vec()).collect(),
effective_sidechain_height: value.effective_sidechain_height,
}
}
}

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

fn try_from(value: grpc::CommitteeDefinitionFeatures) -> Result<Self, Self::Error> {
let committee = value
.committee
.iter()
.map(|c| {
PublicKey::from_bytes(c).map_err(|err| format!("committee member was not a valid public key: {}", err))
})
.collect::<Result<_, _>>()?;
let effective_sidechain_height = value.effective_sidechain_height;

Ok(Self {
committee,
effective_sidechain_height,
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl BaseNodeClient {
pub async fn connect(endpoint: String) -> Result<Self, CollectiblesError> {
let client = grpc::base_node_client::BaseNodeClient::connect(endpoint.clone())
.await
.map_err(|err| CollectiblesError::ClientConnectionError {
.map_err(|err| CollectiblesError::ClientConnection {
client: "wallet",
address: endpoint,
error: err.to_string(),
Expand All @@ -57,14 +57,14 @@ impl BaseNodeClient {
.list_asset_registrations(request)
.await
.map(|response| response.into_inner())
.map_err(|source| CollectiblesError::ClientRequestError {
.map_err(|source| CollectiblesError::ClientRequest {
request: "list_asset_registrations".to_string(),
source,
})?;

let mut assets = vec![];
while let Some(result) = stream.next().await {
let asset = result.map_err(|source| CollectiblesError::ClientRequestError {
let asset = result.map_err(|source| CollectiblesError::ClientRequest {
request: "list_asset_registrations".to_string(),
source,
})?;
Expand All @@ -87,7 +87,7 @@ impl BaseNodeClient {
.get_asset_metadata(request)
.await
.map(|response| response.into_inner())
.map_err(|s| CollectiblesError::ClientRequestError {
.map_err(|s| CollectiblesError::ClientRequest {
request: "get_asset_metadata".to_string(),
source: s,
})?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl GrpcValidatorNodeClient {
let s = Self {
client: grpc::validator_node_client::ValidatorNodeClient::connect(endpoint.clone())
.await
.map_err(|e| CollectiblesError::ClientConnectionError {
.map_err(|e| CollectiblesError::ClientConnection {
client: "validator_node",
address: endpoint,
error: e.to_string(),
Expand Down Expand Up @@ -69,7 +69,7 @@ impl GrpcValidatorNodeClient {
.map_err(|e| {
error!(target: LOG_TARGET, "{}", e);

CollectiblesError::ClientRequestError {
CollectiblesError::ClientRequest {
source: e,
request: "invoke_read_method".to_string(),
}
Expand Down Expand Up @@ -100,7 +100,7 @@ impl GrpcValidatorNodeClient {
.map_err(|e| {
error!(target: LOG_TARGET, "{}", e);

CollectiblesError::ClientRequestError {
CollectiblesError::ClientRequest {
source: e,
request: "invoke_method".to_string(),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl WalletClient {
let dst = format!("http://{}", self.endpoint);
let client = grpc::wallet_client::WalletClient::connect(dst)
.await
.map_err(|err| CollectiblesError::ClientConnectionError {
.map_err(|err| CollectiblesError::ClientConnection {
client: "wallet",
address: self.endpoint.clone(),
error: err.to_string(),
Expand All @@ -55,6 +55,15 @@ impl WalletClient {
Ok(())
}

fn get_inner_mut(
&mut self,
) -> Result<&mut grpc::wallet_client::WalletClient<tonic::transport::Channel>, CollectiblesError>
{
let inner = self.inner.as_mut().ok_or(CollectiblesError::NoConnection)?;

Ok(inner)
}

pub async fn register_asset(
&mut self,
name: String,
Expand All @@ -64,7 +73,7 @@ impl WalletClient {
template_ids_implemented: Vec<u32>,
template_parameters: Vec<grpc::TemplateParameter>,
) -> Result<String, CollectiblesError> {
let inner = self.inner.as_mut().unwrap();
let inner = self.get_inner_mut()?;
let request = RegisterAssetRequest {
name,
public_key: public_key.as_bytes().into(),
Expand All @@ -73,64 +82,93 @@ impl WalletClient {
image,
template_parameters,
};
let result = inner.register_asset(request).await.map_err(|error| {
CollectiblesError::ClientRequestError {
request: "register_asset".to_string(),
source: error,
}
})?;
let result =
inner
.register_asset(request)
.await
.map_err(|error| CollectiblesError::ClientRequest {
request: "register_asset".to_string(),
source: error,
})?;
debug!(target: LOG_TARGET, "result {:?}", result);
Ok(result.into_inner().public_key.to_hex())
}

pub async fn list_owned_assets(
&mut self,
) -> Result<grpc::GetOwnedAssetsResponse, CollectiblesError> {
let inner = self.inner.as_mut().unwrap();
let inner = self.get_inner_mut()?;
let request = grpc::Empty {};
let result = inner.get_owned_assets(request).await.map_err(|source| {
CollectiblesError::ClientRequestError {
request: "get_owned_assets".to_string(),
source,
}
})?;
let result =
inner
.get_owned_assets(request)
.await
.map_err(|source| CollectiblesError::ClientRequest {
request: "get_owned_assets".to_string(),
source,
})?;
debug!(target: LOG_TARGET, "result {:?}", result);
Ok(result.into_inner())
}

pub async fn create_initial_asset_checkpoint(
&mut self,
asset_public_key: String,
asset_public_key: &str,
merkle_root: Vec<u8>,
committee: Vec<String>,
) -> Result<grpc::CreateInitialAssetCheckpointResponse, CollectiblesError> {
let inner = self.inner.as_mut().unwrap();
let inner = self.get_inner_mut()?;
let committee = vec![];
let request = grpc::CreateInitialAssetCheckpointRequest {
asset_public_key: Vec::from_hex(&asset_public_key).unwrap(),
asset_public_key: Vec::from_hex(asset_public_key)?,
merkle_root,
committee: committee
.iter()
.map(|s| Vec::from_hex(s).unwrap())
.collect(),
committee,
};
let result = inner
.create_initial_asset_checkpoint(request)
.await
.map_err(|source| CollectiblesError::ClientRequestError {
.map_err(|source| CollectiblesError::ClientRequest {
request: "create_initial_asset_checkpoint".to_string(),
source,
})?;
debug!(target: LOG_TARGET, "result {:?}", result);
Ok(result.into_inner())
}

pub async fn create_committee_definition(
&mut self,
asset_public_key: &str,
committee: Vec<String>,
effective_sidechain_height: u64,
) -> Result<grpc::CreateCommitteeDefinitionResponse, CollectiblesError> {
let inner = self.get_inner_mut()?;
let committee = committee
.iter()
.map(|s| Vec::from_hex(s))
.collect::<Result<Vec<_>, _>>()?;

let request = grpc::CreateCommitteeDefinitionRequest {
asset_public_key: Vec::from_hex(asset_public_key)?,
committee,
effective_sidechain_height,
};
let result = inner
.create_committee_definition(request)
.await
.map_err(|source| CollectiblesError::ClientRequest {
request: "create_committee_definition".to_string(),
source,
})?;
debug!(target: LOG_TARGET, "result {:?}", result);
Ok(result.into_inner())
}

pub async fn get_unspent_amounts(
&mut self,
) -> Result<grpc::GetUnspentAmountsResponse, CollectiblesError> {
let inner = self.inner.as_mut().unwrap();
let inner = self.get_inner_mut()?;
let request = grpc::Empty {};
let result = inner.get_unspent_amounts(request).await.map_err(|source| {
CollectiblesError::ClientRequestError {
CollectiblesError::ClientRequest {
request: "get_unspent_amounts".to_string(),
source,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,21 +237,39 @@ pub(crate) async fn assets_list_registered_assets(

#[tauri::command]
pub(crate) async fn assets_create_initial_checkpoint(
asset_pub_key: String,
committee: Vec<String>,
asset_public_key: String,
state: tauri::State<'_, ConcurrentAppState>,
) -> Result<(), Status> {
let mmr = MerkleMountainRange::<Blake256, _>::new(MemBackendVec::new());

let root = mmr.get_merkle_root().unwrap();
let merkle_root = mmr.get_merkle_root().unwrap();

let mut client = state.create_wallet_client().await;
client.connect().await?;

// todo: check for enough utxos first

// create asset reg checkpoint
client
.create_initial_asset_checkpoint(asset_pub_key, root, committee)
.await
.unwrap();
.create_initial_asset_checkpoint(&asset_public_key, merkle_root)
.await?;

Ok(())
}

#[tauri::command]
pub(crate) async fn assets_create_committee_definition(
asset_public_key: String,
committee: Vec<String>,
state: tauri::State<'_, ConcurrentAppState>,
) -> Result<(), Status> {
let mut client = state.create_wallet_client().await;
client.connect().await?;

// TODO: effective sidechain height...
client
.create_committee_definition(&asset_public_key, committee, 0)
.await?;

Ok(())
}
Expand Down
Loading