Skip to content

Commit

Permalink
follow tx tag state for new vkeys and boostrap witnesses
Browse files Browse the repository at this point in the history
  • Loading branch information
lisicky committed Dec 26, 2024
1 parent a2a19db commit e3d6eff
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 81 deletions.
93 changes: 76 additions & 17 deletions rust/src/protocol_types/fixed_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ use crate::*;
#[wasm_bindgen]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FixedTransaction {
pub(crate) body: TransactionBody,
pub(crate) body_bytes: Vec<u8>,
pub(crate) tx_hash: TransactionHash,
body: TransactionBody,
body_bytes: Vec<u8>,
tx_hash: TransactionHash,

pub(crate) witness_set: FixedTxWitnessesSet,
witness_set: FixedTxWitnessesSet,

pub(crate) is_valid: bool,
is_valid: bool,

pub(crate) auxiliary_data: Option<AuxiliaryData>,
pub(crate) auxiliary_bytes: Option<Vec<u8>>,
auxiliary_data: Option<AuxiliaryData>,
auxiliary_bytes: Option<Vec<u8>>,
}

to_from_bytes!(FixedTransaction);
Expand All @@ -26,9 +26,17 @@ impl FixedTransaction {
is_valid: bool,
) -> Result<FixedTransaction, JsError> {
let body = TransactionBody::from_bytes(raw_body.to_vec())?;
let witness_set = FixedTxWitnessesSet::from_bytes(raw_witness_set.to_vec())?;
let mut witness_set = FixedTxWitnessesSet::from_bytes(raw_witness_set.to_vec())?;
let tx_hash = TransactionHash::from(blake2b256(raw_body));

let tag_state =
has_transaction_set_tag_internal(&body, Some(witness_set.tx_witnesses_set_ref()))?;
let force_set_tag = match tag_state {
TransactionSetsState::AllSetsHaveNoTag => false,
_ => true,
};
witness_set.force_set_tags_for_new_witnesses(force_set_tag);

Ok(FixedTransaction {
body,
body_bytes: raw_body.to_vec(),
Expand All @@ -47,10 +55,18 @@ impl FixedTransaction {
is_valid: bool,
) -> Result<FixedTransaction, JsError> {
let body = TransactionBody::from_bytes(raw_body.to_vec())?;
let witness_set = FixedTxWitnessesSet::from_bytes(raw_witness_set.to_vec())?;
let mut witness_set = FixedTxWitnessesSet::from_bytes(raw_witness_set.to_vec())?;
let tx_hash = TransactionHash::from(blake2b256(raw_body));
let auxiliary_data = Some(AuxiliaryData::from_bytes(raw_auxiliary_data.to_vec())?);

let tag_state =
has_transaction_set_tag_internal(&body, Some(witness_set.tx_witnesses_set_ref()))?;
let force_set_tag = match tag_state {
TransactionSetsState::AllSetsHaveNoTag => false,
_ => true,
};
witness_set.force_set_tags_for_new_witnesses(force_set_tag);

Ok(FixedTransaction {
body,
body_bytes: raw_body.to_vec(),
Expand All @@ -66,11 +82,20 @@ impl FixedTransaction {
let body = TransactionBody::from_bytes(raw_body.to_vec())?;
let tx_hash = TransactionHash::from(blake2b256(raw_body));

let tag_state = has_transaction_set_tag_internal(&body, None)?;
let force_set_tag = match tag_state {
TransactionSetsState::AllSetsHaveNoTag => false,
_ => true,
};

let mut witness_set = FixedTxWitnessesSet::new_empty();
witness_set.force_set_tags_for_new_witnesses(force_set_tag);

Ok(FixedTransaction {
body,
body_bytes: raw_body.to_vec(),
tx_hash,
witness_set: FixedTxWitnessesSet::new_empty(),
witness_set,
is_valid: true,
auxiliary_data: None,
auxiliary_bytes: None,
Expand All @@ -80,22 +105,33 @@ impl FixedTransaction {
pub(crate) fn new_with_original_bytes(
tx_body: TransactionBody,
raw_body: Vec<u8>,
tx_witnesses_set: FixedTxWitnessesSet,
mut tx_witnesses_set: FixedTxWitnessesSet,
is_valid: bool,
auxiliary_data: Option<AuxiliaryData>,
raw_auxiliary_data: Option<Vec<u8>>,
) -> FixedTransaction {
) -> Result<FixedTransaction, JsError> {
let tx_hash = TransactionHash::from(blake2b256(&raw_body));

FixedTransaction {
let tag_state = has_transaction_set_tag_internal(
&tx_body,
Some(tx_witnesses_set.tx_witnesses_set_ref()),
)?;
let force_set_tag = match tag_state {
TransactionSetsState::AllSetsHaveNoTag => false,
_ => true,
};

tx_witnesses_set.force_set_tags_for_new_witnesses(force_set_tag);

Ok(FixedTransaction {
body: tx_body,
body_bytes: raw_body,
tx_hash,
witness_set: tx_witnesses_set,
is_valid,
auxiliary_data,
auxiliary_bytes: raw_auxiliary_data,
}
})
}

pub fn body(&self) -> TransactionBody {
Expand All @@ -116,7 +152,10 @@ impl FixedTransaction {
/// We do not recommend using this function, since it might lead to script integrity hash.
/// The only purpose of this struct is to sign the transaction from third-party sources.
/// Use `.sign_and_add_vkey_signature` or `.sign_and_add_icarus_bootstrap_signature` or `.sign_and_add_daedalus_bootstrap_signature` instead.
#[deprecated(since = "12.1.0", note = "Use `.sign_and_add_vkey_signature` or `.sign_and_add_icarus_bootstrap_signature` or `.sign_and_add_daedalus_bootstrap_signature` instead.")]
#[deprecated(
since = "12.1.0",
note = "Use `.sign_and_add_vkey_signature` or `.sign_and_add_icarus_bootstrap_signature` or `.sign_and_add_daedalus_bootstrap_signature` instead."
)]
pub fn set_witness_set(&mut self, raw_witness_set: &[u8]) -> Result<(), JsError> {
let witness_set = FixedTxWitnessesSet::from_bytes(raw_witness_set.to_vec())?;
self.witness_set = witness_set;
Expand Down Expand Up @@ -172,15 +211,35 @@ impl FixedTransaction {
Ok(())
}

pub fn sign_and_add_icarus_bootstrap_signature(&mut self, addr: &ByronAddress, private_key: &Bip32PrivateKey) -> Result<(), JsError> {
pub fn sign_and_add_icarus_bootstrap_signature(
&mut self,
addr: &ByronAddress,
private_key: &Bip32PrivateKey,
) -> Result<(), JsError> {
let bootstrap_witness = make_icarus_bootstrap_witness(&self.tx_hash, addr, private_key);
self.witness_set.add_bootstrap_witness(&bootstrap_witness);
Ok(())
}

pub fn sign_and_add_daedalus_bootstrap_signature(&mut self, addr: &ByronAddress, private_key: &LegacyDaedalusPrivateKey) -> Result<(), JsError> {
pub fn sign_and_add_daedalus_bootstrap_signature(
&mut self,
addr: &ByronAddress,
private_key: &LegacyDaedalusPrivateKey,
) -> Result<(), JsError> {
let bootstrap_witness = make_daedalus_bootstrap_witness(&self.tx_hash, addr, private_key);
self.witness_set.add_bootstrap_witness(&bootstrap_witness);
Ok(())
}

pub(crate) fn body_bytes_ref(&self) -> &Vec<u8> {
&self.body_bytes
}

pub(crate) fn witnesses_set_ref(&self) -> &FixedTxWitnessesSet {
&self.witness_set
}

pub(crate) fn auxiliary_bytes_ref(&self) -> Option<&Vec<u8>> {
self.auxiliary_bytes.as_ref()
}
}
25 changes: 23 additions & 2 deletions rust/src/protocol_types/witnesses/fixed_tx_witnesses_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::*;
pub struct FixedTxWitnessesSet {
raw_parts: TransactionWitnessSetRaw,
tx_witnesses_set: TransactionWitnessSet,
transaction_has_set_tags: bool,
}

#[wasm_bindgen]
Expand All @@ -27,13 +28,15 @@ impl FixedTxWitnessesSet {
Self {
tx_witnesses_set: witnesses_set,
raw_parts,
transaction_has_set_tags: true,
}
}

pub(crate) fn new_empty() -> Self {
Self {
tx_witnesses_set: TransactionWitnessSet::new(),
raw_parts: TransactionWitnessSetRaw::new(),
transaction_has_set_tags: true
}
}

Expand All @@ -43,7 +46,14 @@ impl FixedTxWitnessesSet {

pub fn add_vkey_witness(&mut self, vkey_witness: &Vkeywitness) {
if self.tx_witnesses_set.vkeys.is_none() {
self.tx_witnesses_set.vkeys = Some(Vkeywitnesses::new());
let mut vkeys = Vkeywitnesses::new();
vkeys.set_force_original_cbor_set_type(true);
if self.transaction_has_set_tags {
vkeys.set_set_type(CborSetType::Tagged)
} else {
vkeys.set_set_type(CborSetType::Untagged)
}
self.tx_witnesses_set.vkeys = Some(vkeys);
}
if let Some(vkeys) = &mut self.tx_witnesses_set.vkeys {
vkeys.add(vkey_witness);
Expand All @@ -53,7 +63,14 @@ impl FixedTxWitnessesSet {

pub fn add_bootstrap_witness(&mut self, bootstrap_witness: &BootstrapWitness) {
if self.tx_witnesses_set.bootstraps.is_none() {
self.tx_witnesses_set.bootstraps = Some(BootstrapWitnesses::new());
let mut bootstraps = BootstrapWitnesses::new();
bootstraps.set_force_original_cbor_set_type(true);
if self.transaction_has_set_tags {
bootstraps.set_set_type(CborSetType::Tagged)
} else {
bootstraps.set_set_type(CborSetType::Untagged)
}
self.tx_witnesses_set.bootstraps = Some(bootstraps);
}
if let Some(bootstraps) = &mut self.tx_witnesses_set.bootstraps {
bootstraps.add(bootstrap_witness);
Expand Down Expand Up @@ -86,4 +103,8 @@ impl FixedTxWitnessesSet {
pub(crate) fn raw_parts_ref(&self) -> &TransactionWitnessSetRaw {
&self.raw_parts
}

pub(crate) fn force_set_tags_for_new_witnesses(&mut self, set_tags: bool) {
self.transaction_has_set_tags = set_tags;
}
}
25 changes: 16 additions & 9 deletions rust/src/serialization/fixed_tx.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::*;
use crate::serialization::utils::deserilized_with_orig_bytes;
use crate::*;

impl cbor_event::se::Serialize for FixedTransaction {
fn serialize<'se, W: Write>(
&self,
serializer: &'se mut Serializer<W>,
) -> cbor_event::Result<&'se mut Serializer<W>> {
serializer.write_array(cbor_event::Len::Len(4))?;
serializer.write_raw_bytes(&self.body_bytes)?;
self.witness_set.serialize(serializer)?;
serializer.write_special(CBORSpecial::Bool(self.is_valid))?;
match &self.auxiliary_bytes {
serializer.write_raw_bytes(&self.body_bytes_ref())?;
self.witnesses_set_ref().serialize(serializer)?;
serializer.write_special(CBORSpecial::Bool(self.is_valid()))?;
match &self.auxiliary_bytes_ref() {
Some(auxiliary_bytes) => serializer.write_raw_bytes(auxiliary_bytes)?,
None => serializer.write_special(CBORSpecial::Null)?,
};
Expand Down Expand Up @@ -52,8 +52,8 @@ impl DeserializeEmbeddedGroup for FixedTransaction {
let (body, body_bytes) =
deserilized_with_orig_bytes(raw, |raw| TransactionBody::deserialize(raw))
.map_err(|e| e.annotate("body"))?;
let witness_set = FixedTxWitnessesSet::deserialize(raw)
.map_err(|e| e.annotate("witness_set"))?;
let witness_set =
FixedTxWitnessesSet::deserialize(raw).map_err(|e| e.annotate("witness_set"))?;
let mut checked_auxiliary_data = false;
let mut auxiliary_data = None;
let mut auxiliary_bytes = None;
Expand Down Expand Up @@ -105,13 +105,20 @@ impl DeserializeEmbeddedGroup for FixedTransaction {
})()
.map_err(|e| e.annotate("auxiliary_data"))?;
}
Ok(FixedTransaction::new_with_original_bytes(
FixedTransaction::new_with_original_bytes(
body,
body_bytes,
witness_set,
is_valid,
auxiliary_data,
auxiliary_bytes,
))
)
.map_err(|_| {
DeserializeError::new(
"FixedTransaction",
DeserializeFailure::CustomError("Failed to create FixedTransaction. \
Smth wrong with FixedTransaction::new_with_original_bytes()".to_string()),
)
})
}
}
52 changes: 52 additions & 0 deletions rust/src/tests/protocol_types/fixed_tx.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::*;
use hex;
use crate::fakes::fake_bootstrap_witness;
use crate::tests::fakes::{fake_byron_address, fake_vkey_witness};

#[test]
fn simple_round_trip() {
Expand Down Expand Up @@ -170,4 +172,54 @@ fn fixed_transaction_with_plutus_witnesses() {

assert!(fixed_tx_roundtrip.witness_set().vkeys().unwrap().contains(&vkey_witness_1));
assert_eq!(fixed_tx.transaction_hash(), fixed_tx_roundtrip.transaction_hash());
}

#[test]
fn add_witnesses_to_tagged_tx() {
let hex = "84a400d90102818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182581d611c616f1acb460668a9b2f123c80372c2adad3583b9c6cd2b1deeed1c01021a00016f32030aa0f5f6";
let vkey_witness = fake_vkey_witness(1);
let byron_address = ByronAddress::from_base58("Ae2tdPwUPEZ5uzkzh1o2DHECiUi3iugvnnKHRisPgRRP3CTF4KCMvy54Xd3")
.unwrap();
let bootstrap_witness = fake_bootstrap_witness(1, &byron_address);
let mut fixed_tx = FixedTransaction::from_hex(hex).unwrap();
fixed_tx.add_bootstrap_witness(&bootstrap_witness);
fixed_tx.add_vkey_witness(&vkey_witness);

let new_bytes = fixed_tx.to_bytes();

let tx_sets = has_transaction_set_tag(hex::decode(hex).unwrap()).unwrap();
assert_eq!(tx_sets, TransactionSetsState::AllSetsHaveTag);

let new_tx_sets = has_transaction_set_tag(new_bytes.clone()).unwrap();
assert_eq!(new_tx_sets, TransactionSetsState::AllSetsHaveTag);

let new_tx = FixedTransaction::from_bytes(new_bytes).unwrap();

let wit_set_tag = has_transaction_witnesses_set_tag(&new_tx.witness_set());
assert_eq!(wit_set_tag, Some(TransactionSetsState::AllSetsHaveTag));
}

#[test]
fn add_witnesses_to_untagged_tx() {
let hex = "84a400818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018182581d611c616f1acb460668a9b2f123c80372c2adad3583b9c6cd2b1deeed1c01021a00016f32030aa0f5f6";
let vkey_witness = fake_vkey_witness(1);
let byron_address = ByronAddress::from_base58("Ae2tdPwUPEZ5uzkzh1o2DHECiUi3iugvnnKHRisPgRRP3CTF4KCMvy54Xd3")
.unwrap();
let bootstrap_witness = fake_bootstrap_witness(1, &byron_address);
let mut fixed_tx = FixedTransaction::from_hex(hex).unwrap();
fixed_tx.add_bootstrap_witness(&bootstrap_witness);
fixed_tx.add_vkey_witness(&vkey_witness);

let new_bytes = fixed_tx.to_bytes();

let tx_sets = has_transaction_set_tag(hex::decode(hex).unwrap()).unwrap();
assert_eq!(tx_sets, TransactionSetsState::AllSetsHaveNoTag);

let new_tx_sets = has_transaction_set_tag(new_bytes.clone()).unwrap();
assert_eq!(new_tx_sets, TransactionSetsState::AllSetsHaveNoTag);

let new_tx = FixedTransaction::from_bytes(new_bytes).unwrap();

let wit_set_tag = has_transaction_witnesses_set_tag(&new_tx.witness_set());
assert_eq!(wit_set_tag, Some(TransactionSetsState::AllSetsHaveNoTag));
}
Loading

0 comments on commit e3d6eff

Please sign in to comment.