fix(txbuilder): sign transactions using Conway era (#531)

This commit is contained in:
Santiago Carmuega 2024-10-24 16:17:34 -03:00 committed by GitHub
parent a29a6cf50f
commit 3adc16b798
5 changed files with 45 additions and 21 deletions

View file

@ -6,8 +6,8 @@ use pallas_primitives::{
conway::{ conway::{
DatumOption, ExUnits as PallasExUnits, NativeScript, NetworkId, NonZeroInt, PlutusData, DatumOption, ExUnits as PallasExUnits, NativeScript, NetworkId, NonZeroInt, PlutusData,
PlutusScript, PostAlonzoTransactionOutput, PseudoScript as PallasScript, PlutusScript, PostAlonzoTransactionOutput, PseudoScript as PallasScript,
PseudoTransactionOutput, Redeemer, RedeemerTag, TransactionBody, TransactionInput, PseudoTransactionOutput, Redeemer, RedeemerTag, TransactionBody, TransactionInput, Tx,
Tx as BabbageTx, Value, WitnessSet, Value, WitnessSet,
}, },
Fragment, NonEmptyKeyValuePairs, NonEmptySet, PositiveCoin, Fragment, NonEmptyKeyValuePairs, NonEmptySet, PositiveCoin,
}; };
@ -25,15 +25,15 @@ use crate::{
TxBuilderError, TxBuilderError,
}; };
pub trait BuildBabbage { pub trait BuildConway {
fn build_babbage_raw(self) -> Result<BuiltTransaction, TxBuilderError>; fn build_conway_raw(self) -> Result<BuiltTransaction, TxBuilderError>;
// fn build_babbage(staging_tx: StagingTransaction, resolver: (), params: ()) -> // fn build_babbage(staging_tx: StagingTransaction, resolver: (), params: ()) ->
// Result<BuiltTransaction, TxBuilderError>; // Result<BuiltTransaction, TxBuilderError>;
} }
impl BuildBabbage for StagingTransaction { impl BuildConway for StagingTransaction {
fn build_babbage_raw(self) -> Result<BuiltTransaction, TxBuilderError> { fn build_conway_raw(self) -> Result<BuiltTransaction, TxBuilderError> {
let mut inputs = self let mut inputs = self
.inputs .inputs
.unwrap_or_default() .unwrap_or_default()
@ -220,15 +220,21 @@ impl BuildBabbage for StagingTransaction {
); );
let script_data_hash = self.language_view.map(|language_view| { let script_data_hash = self.language_view.map(|language_view| {
scriptdata::ScriptData { let dta = scriptdata::ScriptData {
redeemers: witness_set_redeemers.clone(), redeemers: witness_set_redeemers.clone(),
datums: Some(plutus_data.clone()), datums: if !plutus_data.is_empty() {
Some(plutus_data.clone())
} else {
None
},
language_view, language_view,
} };
.hash()
dbg!(&dta);
dta.hash()
}); });
let mut pallas_tx = BabbageTx { let mut pallas_tx = Tx {
transaction_body: TransactionBody { transaction_body: TransactionBody {
inputs: pallas_primitives::Set::from(inputs), inputs: pallas_primitives::Set::from(inputs),
outputs, outputs,
@ -274,7 +280,7 @@ impl BuildBabbage for StagingTransaction {
Ok(BuiltTransaction { Ok(BuiltTransaction {
version: self.version, version: self.version,
era: BuilderEra::Babbage, era: BuilderEra::Conway,
status: TransactionStatus::Built, status: TransactionStatus::Built,
tx_hash: Bytes32(*pallas_tx.transaction_body.compute_hash()), tx_hash: Bytes32(*pallas_tx.transaction_body.compute_hash()),
tx_bytes: Bytes(pallas_tx.encode_fragment().unwrap()), tx_bytes: Bytes(pallas_tx.encode_fragment().unwrap()),

View file

@ -1,8 +1,8 @@
mod babbage; mod conway;
mod scriptdata; mod scriptdata;
mod transaction; mod transaction;
pub use babbage::BuildBabbage; pub use conway::BuildConway;
pub use transaction::model::{ pub use transaction::model::{
BuiltTransaction, ExUnits, Input, Output, ScriptKind, StagingTransaction, BuiltTransaction, ExUnits, Input, Output, ScriptKind, StagingTransaction,
}; };
@ -34,4 +34,7 @@ pub enum TxBuilderError {
/// Asset name is too long, it must be 32 bytes or less /// Asset name is too long, it must be 32 bytes or less
#[error("Asset name must be 32 bytes or less")] #[error("Asset name must be 32 bytes or less")]
AssetNameTooLong, AssetNameTooLong,
/// Unsupported era
#[error("Unsupported era")]
UnsupportedEra,
} }

View file

@ -39,6 +39,7 @@ impl<C> Encode<C> for LanguageView {
} }
} }
#[derive(Debug, Clone)]
pub struct ScriptData { pub struct ScriptData {
pub redeemers: Redeemers, pub redeemers: Redeemers,
pub datums: Option<Vec<PlutusData>>, pub datums: Option<Vec<PlutusData>>,
@ -112,6 +113,10 @@ mod tests {
hex::decode(include_str!("../../test_data/conway2.tx")).unwrap(), hex::decode(include_str!("../../test_data/conway2.tx")).unwrap(),
LanguageView(0, COST_MODEL_PLUTUS_V1.clone()), LanguageView(0, COST_MODEL_PLUTUS_V1.clone()),
), ),
(
hex::decode(include_str!("../../test_data/hydra-init.tx")).unwrap(),
LanguageView(1, COST_MODEL_PLUTUS_V2.clone()),
),
] ]
}); });

View file

@ -3,7 +3,7 @@ use pallas_crypto::{
hash::{Hash, Hasher}, hash::{Hash, Hasher},
key::ed25519, key::ed25519,
}; };
use pallas_primitives::{babbage, Fragment}; use pallas_primitives::{babbage, conway, Fragment, NonEmptySet};
use pallas_wallet::PrivateKey; use pallas_wallet::PrivateKey;
use std::{collections::HashMap, ops::Deref}; use std::{collections::HashMap, ops::Deref};
@ -599,6 +599,7 @@ impl From<PallasAddress> for Address {
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum BuilderEra { pub enum BuilderEra {
Babbage, Babbage,
Conway,
} }
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
@ -626,7 +627,7 @@ impl BuiltTransaction {
.unwrap(); .unwrap();
match self.era { match self.era {
BuilderEra::Babbage => { BuilderEra::Conway => {
let mut new_sigs = self.signatures.unwrap_or_default(); let mut new_sigs = self.signatures.unwrap_or_default();
new_sigs.insert(Bytes32(pubkey), Bytes64(signature)); new_sigs.insert(Bytes32(pubkey), Bytes64(signature));
@ -634,20 +635,26 @@ impl BuiltTransaction {
self.signatures = Some(new_sigs); self.signatures = Some(new_sigs);
// TODO: chance for serialisation round trip issues? // TODO: chance for serialisation round trip issues?
let mut tx = babbage::Tx::decode_fragment(&self.tx_bytes.0) let mut tx = conway::Tx::decode_fragment(&self.tx_bytes.0)
.map_err(|_| TxBuilderError::CorruptedTxBytes)?; .map_err(|_| TxBuilderError::CorruptedTxBytes)?;
let mut vkey_witnesses = tx.transaction_witness_set.vkeywitness.unwrap_or_default(); let mut vkey_witnesses = tx
.transaction_witness_set
.vkeywitness
.map(|x| x.to_vec())
.unwrap_or_default();
vkey_witnesses.push(babbage::VKeyWitness { vkey_witnesses.push(babbage::VKeyWitness {
vkey: Vec::from(pubkey.as_ref()).into(), vkey: Vec::from(pubkey.as_ref()).into(),
signature: Vec::from(signature.as_ref()).into(), signature: Vec::from(signature.as_ref()).into(),
}); });
tx.transaction_witness_set.vkeywitness = Some(vkey_witnesses); tx.transaction_witness_set.vkeywitness =
Some(NonEmptySet::from_vec(vkey_witnesses).unwrap());
self.tx_bytes = tx.encode_fragment().unwrap().into(); self.tx_bytes = tx.encode_fragment().unwrap().into();
} }
_ => return Err(TxBuilderError::UnsupportedEra),
} }
Ok(self) Ok(self)
@ -659,7 +666,7 @@ impl BuiltTransaction {
signature: [u8; 64], signature: [u8; 64],
) -> Result<Self, TxBuilderError> { ) -> Result<Self, TxBuilderError> {
match self.era { match self.era {
BuilderEra::Babbage => { BuilderEra::Conway => {
let mut new_sigs = self.signatures.unwrap_or_default(); let mut new_sigs = self.signatures.unwrap_or_default();
new_sigs.insert( new_sigs.insert(
@ -689,6 +696,7 @@ impl BuiltTransaction {
self.tx_bytes = tx.encode_fragment().unwrap().into(); self.tx_bytes = tx.encode_fragment().unwrap().into();
} }
_ => return Err(TxBuilderError::UnsupportedEra),
} }
Ok(self) Ok(self)
@ -696,7 +704,7 @@ impl BuiltTransaction {
pub fn remove_signature(mut self, pub_key: ed25519::PublicKey) -> Result<Self, TxBuilderError> { pub fn remove_signature(mut self, pub_key: ed25519::PublicKey) -> Result<Self, TxBuilderError> {
match self.era { match self.era {
BuilderEra::Babbage => { BuilderEra::Conway => {
let mut new_sigs = self.signatures.unwrap_or_default(); let mut new_sigs = self.signatures.unwrap_or_default();
let pk = Bytes32( let pk = Bytes32(
@ -722,6 +730,7 @@ impl BuiltTransaction {
self.tx_bytes = tx.encode_fragment().unwrap().into(); self.tx_bytes = tx.encode_fragment().unwrap().into();
} }
_ => return Err(TxBuilderError::UnsupportedEra),
} }
Ok(self) Ok(self)

1
test_data/hydra-init.tx Normal file

File diff suppressed because one or more lines are too long