Skip to content

Commit

Permalink
feat(core): add template registration sidechain features
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Aug 15, 2022
1 parent ecd5577 commit f0b19b0
Show file tree
Hide file tree
Showing 21 changed files with 1,868 additions and 792 deletions.
152 changes: 129 additions & 23 deletions applications/tari_app_grpc/src/conversions/sidechain_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,35 @@ use std::{
convert::{TryFrom, TryInto},
};

use tari_common_types::types::{FixedHash, PublicKey};
use tari_core::transactions::transaction_components::{
bytes_into_fixed_string,
CheckpointParameters,
CommitteeMembers,
CommitteeSignatures,
ConstitutionChangeFlags,
ConstitutionChangeRules,
ContractAcceptance,
ContractAcceptanceRequirements,
ContractAmendment,
ContractCheckpoint,
ContractConstitution,
ContractDefinition,
ContractSpecification,
ContractUpdateProposal,
ContractUpdateProposalAcceptance,
FunctionRef,
PublicFunction,
RequirementsForConstitutionChange,
SideChainConsensus,
SideChainFeatures,
SignerSignature,
use tari_common_types::types::{FixedHash, PublicKey, Signature};
use tari_core::{
consensus::MaxSizeString,
transactions::transaction_components::{
bytes_into_fixed_string,
BuildInfo,
CheckpointParameters,
CodeTemplateRegistration,
CommitteeMembers,
CommitteeSignatures,
ConstitutionChangeFlags,
ConstitutionChangeRules,
ContractAcceptance,
ContractAcceptanceRequirements,
ContractAmendment,
ContractCheckpoint,
ContractConstitution,
ContractDefinition,
ContractSpecification,
ContractUpdateProposal,
ContractUpdateProposalAcceptance,
FunctionRef,
PublicFunction,
RequirementsForConstitutionChange,
SideChainConsensus,
SideChainFeatures,
SignerSignature,
TemplateType,
},
};
use tari_utilities::ByteArray;

Expand All @@ -64,6 +70,7 @@ impl From<SideChainFeatures> for grpc::SideChainFeatures {
update_proposal_acceptance: value.update_proposal_acceptance.map(Into::into),
amendment: value.amendment.map(Into::into),
checkpoint: value.checkpoint.map(Into::into),
template_registration: value.template_registration.map(Into::into),
}
}
}
Expand All @@ -85,6 +92,10 @@ impl TryFrom<grpc::SideChainFeatures> for SideChainFeatures {
.transpose()?;
let amendment = features.amendment.map(ContractAmendment::try_from).transpose()?;
let checkpoint = features.checkpoint.map(ContractCheckpoint::try_from).transpose()?;
let template_registration = features
.template_registration
.map(CodeTemplateRegistration::try_from)
.transpose()?;

Ok(Self {
contract_id: features.contract_id.try_into().map_err(|_| "Invalid contract_id")?,
Expand All @@ -93,6 +104,7 @@ impl TryFrom<grpc::SideChainFeatures> for SideChainFeatures {
acceptance,
update_proposal,
update_proposal_acceptance,
template_registration,
amendment,
checkpoint,
})
Expand Down Expand Up @@ -140,10 +152,104 @@ impl TryFrom<grpc::CreateConstitutionDefinitionRequest> for SideChainFeatures {
update_proposal_acceptance: None,
amendment: None,
checkpoint: None,
template_registration: None,
})
}
}

// -------------------------------- TemplateRegistration -------------------------------- //
impl TryFrom<grpc::TemplateRegistration> for CodeTemplateRegistration {
type Error = String;

fn try_from(value: grpc::TemplateRegistration) -> Result<Self, Self::Error> {
Ok(Self {
author_public_key: PublicKey::from_bytes(&value.author_public_key).map_err(|e| e.to_string())?,
author_signature: value
.author_signature
.map(Signature::try_from)
.ok_or("author_signature not provided")??,
template_name: MaxSizeString::try_from(value.template_name).map_err(|e| e.to_string())?,
template_version: value
.template_version
.try_into()
.map_err(|_| "Invalid template version")?,
template_type: value
.template_type
.map(TryFrom::try_from)
.ok_or("Template type not provided")??,
build_info: value
.build_info
.map(TryFrom::try_from)
.ok_or("Build info not provided")??,
binary_sha: value.binary_sha.try_into().map_err(|_| "Invalid commit sha")?,
binary_url: MaxSizeString::try_from(value.binary_url).map_err(|e| e.to_string())?,
})
}
}

impl From<CodeTemplateRegistration> for grpc::TemplateRegistration {
fn from(value: CodeTemplateRegistration) -> Self {
Self {
author_public_key: value.author_public_key.to_vec(),
author_signature: Some(value.author_signature.into()),
template_name: value.template_name.to_string(),
template_version: u32::from(value.template_version),
template_type: Some(value.template_type.into()),
build_info: Some(value.build_info.into()),
binary_sha: value.binary_sha.to_vec(),
binary_url: value.binary_url.to_string(),
}
}
}

// -------------------------------- TemplateType -------------------------------- //
impl TryFrom<grpc::TemplateType> for TemplateType {
type Error = String;

fn try_from(value: grpc::TemplateType) -> Result<Self, Self::Error> {
let template_type = value.template_type.ok_or("Template type not provided")?;
match template_type {
grpc::template_type::TemplateType::Wasm(wasm) => Ok(TemplateType::Wasm {
abi_version: wasm.abi_version.try_into().map_err(|_| "abi_version overflowed")?,
}),
}
}
}

impl From<TemplateType> for grpc::TemplateType {
fn from(value: TemplateType) -> Self {
match value {
TemplateType::Wasm { abi_version } => Self {
template_type: Some(grpc::template_type::TemplateType::Wasm(grpc::WasmInfo {
abi_version: abi_version.into(),
})),
},
}
}
}

// -------------------------------- BuildInfo -------------------------------- //

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

fn try_from(value: grpc::BuildInfo) -> Result<Self, Self::Error> {
Ok(Self {
repo_url: value.repo_url.try_into().map_err(|_| "Invalid repo url")?,
commit_hash: value.commit_hash.try_into().map_err(|_| "Invalid commit hash")?,
})
}
}

impl From<BuildInfo> for grpc::BuildInfo {
fn from(value: BuildInfo) -> Self {
Self {
repo_url: value.repo_url.into_string(),
commit_hash: value.commit_hash.into_vec(),
}
}
}

//---------------------------------- ContractDefinition --------------------------------------------//

impl TryFrom<grpc::ContractDefinition> for ContractDefinition {
Expand Down
39 changes: 38 additions & 1 deletion applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ use tari_app_grpc::{
CreateFollowOnAssetCheckpointResponse,
CreateInitialAssetCheckpointRequest,
CreateInitialAssetCheckpointResponse,
CreateTemplateRegistrationRequest,
CreateTemplateRegistrationResponse,
FileDeletedResponse,
GetBalanceRequest,
GetBalanceResponse,
Expand Down Expand Up @@ -105,7 +107,7 @@ use tari_common_types::{
use tari_comms::{multiaddr::Multiaddr, types::CommsPublicKey, CommsNode};
use tari_core::transactions::{
tari_amount::MicroTari,
transaction_components::{OutputFeatures, SideChainFeatures, UnblindedOutput},
transaction_components::{CodeTemplateRegistration, OutputFeatures, SideChainFeatures, UnblindedOutput},
};
use tari_utilities::{hex::Hex, ByteArray, Hashable};
use tari_wallet::{
Expand Down Expand Up @@ -1272,6 +1274,41 @@ impl wallet_server::Wallet for WalletGrpcServer {

Ok(Response::new(FileDeletedResponse {}))
}

async fn create_template_registration(
&self,
request: Request<CreateTemplateRegistrationRequest>,
) -> Result<Response<CreateTemplateRegistrationResponse>, Status> {
let mut asset_manager = self.wallet.asset_manager.clone();
let mut transaction_service = self.wallet.transaction_service.clone();
let message = request.into_inner();

let template_registration = CodeTemplateRegistration::try_from(
message
.template_registration
.ok_or_else(|| Status::invalid_argument("template_registration is empty"))?,
)
.map_err(|e| Status::invalid_argument(format!("template_registration is invalid: {}", e)))?;

let message = format!("Template registration {}", template_registration.template_name);

let (tx_id, transaction) = asset_manager
.create_code_template_registration(template_registration)
.await
.map_err(|e| Status::internal(e.to_string()))?;

debug!(
target: LOG_TARGET,
"Template registration transaction: {:?}", transaction
);

let _ = transaction_service
.submit_transaction(tx_id, transaction, 0.into(), message)
.await
.map_err(|e| Status::internal(e.to_string()))?;

Ok(Response::new(CreateTemplateRegistrationResponse {}))
}
}

async fn handle_completed_tx(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ use crate::{
},
txn_schema,
};

fn setup() -> BlockchainDatabase<TempDatabase> {
create_new_blockchain()
}
Expand Down
9 changes: 9 additions & 0 deletions base_layer/core/src/consensus/consensus_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ mod hashing;
mod integers;
mod micro_tari;
mod script;
mod string;
mod vec;

use std::io;

pub use hashing::{ConsensusHasher, DomainSeparatedConsensusHasher};
pub use string::MaxSizeString;
pub use vec::MaxSizeVec;

pub use self::bytes::MaxSizeBytes;
Expand Down Expand Up @@ -76,6 +79,12 @@ impl<T: ConsensusEncoding + ConsensusEncodingSized + ?Sized> ToConsensusBytes fo
}
}

pub fn read_byte<R: io::Read>(reader: &mut R) -> Result<u8, io::Error> {
let mut buf = [0u8; 1];
reader.read_exact(&mut buf)?;
Ok(buf[0])
}

#[cfg(test)]
pub mod test {
use super::*;
Expand Down
58 changes: 53 additions & 5 deletions base_layer/core/src/consensus/consensus_encoding/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::{
cmp,
convert::TryFrom,
io,
io::{Error, Read, Write},
ops::Deref,
};

use integer_encoding::{VarInt, VarIntReader, VarIntWriter};
use serde::{Deserialize, Serialize};

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

Expand All @@ -47,10 +49,34 @@ impl ConsensusEncodingSized for Vec<u8> {
}
}

#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default, Deserialize, Serialize)]
pub struct MaxSizeBytes<const MAX: usize> {
inner: Vec<u8>,
}

impl<const MAX: usize> MaxSizeBytes<MAX> {
pub fn into_vec(self) -> Vec<u8> {
self.inner
}

pub fn from_bytes_checked<T: AsRef<[u8]>>(bytes: T) -> Option<Self> {
let b = bytes.as_ref();
if b.len() > MAX {
None
} else {
Some(Self { inner: b.to_vec() })
}
}

pub fn from_bytes_truncate<T: AsRef<[u8]>>(bytes: T) -> Self {
let b = bytes.as_ref();
let len = cmp::min(b.len(), MAX);
Self {
inner: b[..len].to_vec(),
}
}
}

impl<const MAX: usize> From<MaxSizeBytes<MAX>> for Vec<u8> {
fn from(value: MaxSizeBytes<MAX>) -> Self {
value.inner
Expand All @@ -68,6 +94,18 @@ impl<const MAX: usize> TryFrom<Vec<u8>> for MaxSizeBytes<MAX> {
}
}

impl<const SZ: usize> ConsensusEncoding for MaxSizeBytes<SZ> {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
self.inner.consensus_encode(writer)
}
}

impl<const SZ: usize> ConsensusEncodingSized for MaxSizeBytes<SZ> {
fn consensus_encode_exact_size(&self) -> usize {
self.inner.consensus_encode_exact_size()
}
}

impl<const MAX: usize> ConsensusDecoding for MaxSizeBytes<MAX> {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, io::Error> {
let len = reader.read_varint()?;
Expand Down Expand Up @@ -108,7 +146,8 @@ impl ConsensusEncoding for &[u8] {

impl ConsensusEncodingSized for &[u8] {
fn consensus_encode_exact_size(&self) -> usize {
self.len()
let len = self.len();
len.required_space() + len
}
}

Expand Down Expand Up @@ -139,17 +178,26 @@ mod test {
use rand::{rngs::OsRng, RngCore};

use super::*;
use crate::consensus::{check_consensus_encoding_correctness, ToConsensusBytes};
use crate::consensus::check_consensus_encoding_correctness;

#[test]
fn it_encodes_and_decodes_correctly() {
let mut subject = [0u8; 1024];
OsRng.fill_bytes(&mut subject);
check_consensus_encoding_correctness(subject).unwrap();

// &[u8] consensus encoding
let mut buf = Vec::new();
let slice = subject.as_slice();
slice.consensus_encode(&mut buf).unwrap();
assert_eq!(buf.len(), slice.consensus_encode_exact_size());
let mut reader = buf.as_slice();
let decoded: MaxSizeBytes<1024> = ConsensusDecoding::consensus_decode(&mut reader).unwrap();
assert_eq!(&*decoded, slice);
assert!(reader.is_empty());

// Get vec encoding with length byte
let encoded = subject.to_vec().to_consensus_bytes();
let decoded = MaxSizeBytes::<1024>::consensus_decode(&mut encoded.as_slice()).unwrap();
assert_eq!(*decoded, *subject.as_slice());
let subject = MaxSizeBytes::<1024>::from_bytes_checked(&subject).unwrap();
check_consensus_encoding_correctness(subject).unwrap();
}
}
Loading

0 comments on commit f0b19b0

Please sign in to comment.