Skip to content

Commit

Permalink
Add a preview partial transaction & builder
Browse files Browse the repository at this point in the history
  • Loading branch information
0xOmarA committed Nov 11, 2024
1 parent 221c1ea commit 2bdefe1
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 29 deletions.
1 change: 1 addition & 0 deletions crates/radix-engine-toolkit-uniffi/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ pub mod transaction_v1_builder;
pub mod transaction_v2_builder;

pub mod partial_transaction_v2_builder;
pub mod preview_partial_transaction_v2_builder;
pub mod signed_partial_transaction_v2_builder;
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::prelude::*;
use std::ops::Deref;

#[derive(Clone, Debug, Object)]
pub struct PreviewPartialTransactionV2Builder {
children_with_signers: Vec<PreviewPartialTransactionV2>,
root_subintent_header: Option<IntentHeaderV2>,
root_subintent_message: MessageV2,
root_subintent_manifest: Option<TransactionManifestV2>,
}

#[uniffi::export]
impl PreviewPartialTransactionV2Builder {
#[uniffi::constructor]
pub fn new() -> Arc<Self> {
Arc::new(Self {
children_with_signers: Default::default(),
root_subintent_header: Default::default(),
root_subintent_message: Default::default(),
root_subintent_manifest: Default::default(),
})
}

pub fn add_child(
self: Arc<Self>,
child: Arc<PreviewPartialTransactionV2>,
) -> Arc<Self> {
self.with_builder(|builder| {
builder.children_with_signers.push(child.as_ref().clone())
})
}

pub fn message(self: Arc<Self>, message: MessageV2) -> Arc<Self> {
self.with_builder(|builder| builder.root_subintent_message = message)
}

pub fn intent_header(
self: Arc<Self>,
intent_header: IntentHeaderV2,
) -> Arc<Self> {
self.with_builder(|builder| {
builder.root_subintent_header = Some(intent_header)
})
}

pub fn manifest(
self: Arc<Self>,
manifest: Arc<TransactionManifestV2>,
) -> Arc<Self> {
self.with_builder(|builder| {
builder.root_subintent_manifest = Some(manifest.as_ref().clone())
})
}

pub fn prepare_for_signing(
self: Arc<Self>,
) -> Result<Arc<PreviewPartialTransactionV2>> {
// Deconstructing the builder.
let PreviewPartialTransactionV2Builder {
children_with_signers,
root_subintent_header: Some(header),
root_subintent_message: message,
root_subintent_manifest:
Some(TransactionManifestV2 {
instructions,
blobs,
children,
}),
} = Arc::try_unwrap(self).unwrap_or_else(|x| (*x).clone())
else {
return Err(
RadixEngineToolkitError::NotAllBuilderItemsWereSpecified,
);
};

// Constructing the partial transaction
let partial_transaction = PartialTransactionV2 {
root_subintent: SubintentV2::new(IntentCoreV2::new(
header,
blobs,
message,
children,
instructions,
)),
non_root_subintents: children_with_signers
.iter()
.flat_map(|child| {
let mut subintents = Vec::new();
subintents
.push(child.partial_transaction.root_subintent.clone());
subintents.extend(
child
.partial_transaction
.non_root_subintents
.iter()
.cloned(),
);
subintents
})
.collect(),
};

// Constructing the signed partial transaction
let preview_partial_transaction = PreviewPartialTransactionV2 {
partial_transaction: Arc::new(partial_transaction),
root_subintent_signers: Default::default(),
non_root_subintent_signers: children_with_signers
.iter()
.flat_map(|child| {
let mut signers = Vec::new();
signers.push(child.root_subintent_signers.clone());
signers.extend(child.non_root_subintent_signers.clone());
signers
})
.collect(),
};

Ok(Arc::new(preview_partial_transaction))
}
}

impl PreviewPartialTransactionV2Builder {
fn with_builder(
self: Arc<Self>,
callback: impl FnOnce(&mut Self),
) -> Arc<Self> {
let mut this = Arc::try_unwrap(self).unwrap_or_else(|x| (*x).clone());
callback(&mut this);
Arc::new(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,36 @@ use std::ops::Deref;

#[derive(Clone, Debug, Object)]
pub struct PreviewTransactionV2Builder {
children_with_signers: Vec<PreviewPartialTransactionV2>,
transaction_header: Option<TransactionHeaderV2>,
transaction_intent_header: Option<IntentHeaderV2>,
transaction_intent_message: MessageV2,
transaction_intent_manifest: Option<TransactionManifestV2>,
child_partial_transactions: Vec<PartialTransactionV2>,
root_signer_public_keys: IndexSet<PublicKey>,
non_root_subintent_signer_public_keys: Vec<Vec<PublicKey>>,
transaction_intent_signers: Vec<PublicKey>,
}

#[uniffi::export]
impl PreviewTransactionV2Builder {
#[uniffi::constructor]
pub fn new() -> Arc<Self> {
Arc::new(Self {
children_with_signers: Default::default(),
transaction_header: Default::default(),
transaction_intent_header: Default::default(),
transaction_intent_message: Default::default(),
transaction_intent_manifest: Default::default(),
child_partial_transactions: Default::default(),
root_signer_public_keys: Default::default(),
non_root_subintent_signer_public_keys: Default::default(),
transaction_intent_signers: Default::default(),
})
}

pub fn add_child(
self: Arc<Self>,
partial_transaction: Arc<PartialTransactionV2>,
signers: Vec<PublicKey>,
partial_preview_transaction: Arc<PreviewPartialTransactionV2>,
) -> Arc<Self> {
self.with_builder(|builder| {
builder
.child_partial_transactions
.push(partial_transaction.deref().clone());
builder.non_root_subintent_signer_public_keys.push(signers);
.children_with_signers
.push(partial_preview_transaction.deref().clone());
})
}

Expand Down Expand Up @@ -96,19 +92,18 @@ impl PreviewTransactionV2Builder {
signer: PublicKey,
) -> Arc<Self> {
self.with_builder(|builder| {
builder.root_signer_public_keys.insert(signer);
builder.transaction_intent_signers.push(signer);
})
}

pub fn build(self: Arc<Self>) -> Result<Vec<u8>> {
// Deconstructing the builder.
let Self {
children_with_signers,
transaction_header: Some(transaction_header),
transaction_intent_header: Some(header),
transaction_intent_message: message,
child_partial_transactions,
root_signer_public_keys,
non_root_subintent_signer_public_keys,
transaction_intent_signers,
transaction_intent_manifest:
Some(TransactionManifestV2 {
instructions,
Expand All @@ -132,13 +127,19 @@ impl PreviewTransactionV2Builder {
children,
instructions,
),
non_root_subintents: child_partial_transactions
non_root_subintents: children_with_signers
.iter()
.flat_map(|child| {
let mut subintents = Vec::new();
subintents.push(child.root_subintent.clone());
subintents
.extend(child.non_root_subintents.iter().cloned());
.push(child.partial_transaction.root_subintent.clone());
subintents.extend(
child
.partial_transaction
.non_root_subintents
.iter()
.cloned(),
);
subintents
})
.collect(),
Expand All @@ -148,20 +149,24 @@ impl PreviewTransactionV2Builder {

let preview_transaction = NativePreviewTransactionV2 {
transaction_intent,
root_signer_public_keys: root_signer_public_keys
root_signer_public_keys: transaction_intent_signers
.into_iter()
.map(TryInto::try_into)
.collect::<Result<_>>()?,
non_root_subintent_signer_public_keys:
non_root_subintent_signer_public_keys
.into_iter()
.map(|public_keys| {
public_keys
.into_iter()
.map(TryInto::try_into)
.collect::<Result<_>>()
})
.collect::<Result<_>>()?,
non_root_subintent_signer_public_keys: children_with_signers
.iter()
.flat_map(|child| {
let mut signers = Vec::new();
signers.push(child.root_subintent_signers.clone());
signers.extend(child.non_root_subintent_signers.clone());
signers
})
.map(|vec| {
vec.into_iter()
.map(TryInto::try_into)
.collect::<Result<_>>()
})
.collect::<Result<_>>()?,
};

let raw_preview_transaction = preview_transaction.to_raw()?;
Expand Down
1 change: 1 addition & 0 deletions crates/radix-engine-toolkit-uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pub mod prelude {
pub use crate::transaction_v2::message::*;
pub use crate::transaction_v2::notarized_transaction::*;
pub use crate::transaction_v2::partial_transaction::*;
pub use crate::transaction_v2::preview_partial_transaction::*;
pub use crate::transaction_v2::signed_intent::*;
pub use crate::transaction_v2::signed_partial_transaction::*;
pub use crate::transaction_v2::subintent::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod intent_header;
pub mod message;
pub mod notarized_transaction;
pub mod partial_transaction;
pub mod preview_partial_transaction;
pub mod signed_intent;
pub mod signed_partial_transaction;
pub mod subintent;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::prelude::*;

#[derive(Clone, Debug, Object)]
pub struct PreviewPartialTransactionV2 {
pub partial_transaction: Arc<PartialTransactionV2>,
pub root_subintent_signers: Vec<PublicKey>,
pub non_root_subintent_signers: Vec<Vec<PublicKey>>,
}

#[uniffi::export]
impl PreviewPartialTransactionV2 {
#[uniffi::constructor]
pub fn new(
partial_transaction: Arc<PartialTransactionV2>,
root_subintent_signers: Vec<PublicKey>,
non_root_subintent_signers: Vec<Vec<PublicKey>>,
) -> Arc<Self> {
Arc::new(Self {
partial_transaction,
root_subintent_signers,
non_root_subintent_signers,
})
}

pub fn partial_transaction(&self) -> Arc<PartialTransactionV2> {
// TODO: We're creating another pointer to the partial transaction
// object which means that this doesn't quite follow value semantics.
// The caller will have a reference to the partial transaction which
// means that any changes made to it will reflect in the object that
// they get back. This isn't the first instance of this but it's my
// first time noticing it. This might be something that we want to fix
// or look into when rearchitecting the toolkit such that it follows the
// value semantics perfectly. Perhaps even taking a step back, am I
// right about the assumption that this is now a reference and that it
// won't follow value semantics?
self.partial_transaction.clone()
}

pub fn root_subintent_signers(&self) -> Vec<PublicKey> {
self.root_subintent_signers.clone()
}

pub fn non_root_subintent_signers(&self) -> Vec<Vec<PublicKey>> {
self.non_root_subintent_signers.clone()
}

pub fn root_subintent_hash(&self) -> Result<Arc<TransactionHash>> {
self.partial_transaction.root_subintent_hash()
}
}

0 comments on commit 2bdefe1

Please sign in to comment.