Skip to content

Commit 5bb0573

Browse files
authored
Merge pull request #311 from pragma-org/jshy/collateral
Collateral Validations
2 parents 7893b79 + 5566693 commit 5bb0573

63 files changed

Lines changed: 1883 additions & 576 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/amaru-kernel/src/lib.rs

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ use pallas_addresses::{
2626
byron::{AddrAttrProperty, AddressPayload},
2727
*,
2828
};
29-
use pallas_primitives::{
30-
alonzo::Value as AlonzoValue,
31-
conway::{MintedPostAlonzoTransactionOutput, NativeScript},
32-
};
29+
use pallas_primitives::conway::{MintedPostAlonzoTransactionOutput, NativeScript, RedeemerTag};
3330
use sha3::{Digest as _, Sha3_256};
3431
use std::{
35-
array::TryFromSliceError, borrow::Cow, collections::BTreeMap, fmt::Debug, ops::Deref, sync::Arc,
32+
array::TryFromSliceError,
33+
borrow::Cow,
34+
collections::BTreeMap,
35+
fmt::{self, Debug, Formatter},
36+
ops::Deref,
37+
sync::Arc,
3638
};
3739

3840
pub use amaru_minicbor_extra::*;
@@ -50,20 +52,21 @@ pub use pallas_crypto::{
5052
key::ed25519,
5153
};
5254
pub use pallas_primitives::{
53-
AssetName, BigInt, Constr, DatumHash, DnsName, IPv4, IPv6, MaybeIndefArray, PlutusData,
54-
PlutusScript, PolicyId, Port, PositiveCoin,
55+
alonzo::Value as AlonzoValue,
5556
babbage::{Header, MintedHeader, PseudoHeader},
5657
conway::{
57-
AddrKeyhash, AuxiliaryData, Block, BootstrapWitness, Certificate, Coin, Constitution,
58-
CostModel, CostModels, DRep, DRepVotingThresholds, DatumOption, ExUnitPrices, ExUnits,
59-
GovAction, HeaderBody, KeepRaw, Language, MintedBlock, MintedDatumOption, MintedScriptRef,
60-
MintedTransactionBody, MintedTransactionOutput, MintedTx, MintedWitnessSet, Multiasset,
61-
NonEmptySet, NonZeroInt, PoolMetadata, PoolVotingThresholds, PostAlonzoTransactionOutput,
58+
AddrKeyhash, AssetName, AuxiliaryData, BigInt, Block, BootstrapWitness, Certificate, Coin,
59+
Constitution, Constr, CostModel, CostModels, DRep, DRepVotingThresholds, DatumHash,
60+
DatumOption, DnsName, ExUnitPrices, ExUnits, GovAction, GovActionId as ProposalId,
61+
HeaderBody, IPv4, IPv6, KeepRaw, Language, MaybeIndefArray, MintedBlock, MintedDatumOption,
62+
MintedScriptRef, MintedTransactionBody, MintedTransactionOutput, MintedTx,
63+
MintedWitnessSet, Multiasset, NonEmptySet, NonZeroInt, PlutusData, PlutusScript, PolicyId,
64+
PoolMetadata, PoolVotingThresholds, Port, PositiveCoin, PostAlonzoTransactionOutput,
6265
ProposalProcedure as Proposal, ProtocolParamUpdate, ProtocolVersion, PseudoScript,
63-
PseudoTransactionOutput, RationalNumber, Redeemer, RedeemerTag, Redeemers,
64-
RedeemersKey as RedeemerKey, Relay, RewardAccount, ScriptHash, ScriptRef, StakeCredential,
65-
TransactionBody, TransactionInput, TransactionOutput, Tx, UnitInterval, VKeyWitness, Value,
66-
Vote, Voter, VotingProcedure, VotingProcedures, VrfKeyhash, WitnessSet,
66+
PseudoTransactionOutput, RationalNumber, Redeemer, Redeemers, RedeemersKey as RedeemerKey,
67+
Relay, RewardAccount, ScriptHash, ScriptRef, StakeCredential, TransactionBody,
68+
TransactionInput, TransactionOutput, Tx, UnitInterval, VKeyWitness, Value, Vote, Voter,
69+
VotingProcedure, VotingProcedures, VrfKeyhash, WitnessSet,
6770
},
6871
};
6972
pub use pallas_traverse::{ComputeHash, OriginalHash};
@@ -266,6 +269,29 @@ impl From<&[u8]> for RawBlock {
266269
}
267270
}
268271

272+
#[derive(Debug, Clone)]
273+
pub struct TransactionInputAdapter(TransactionInput);
274+
275+
impl Deref for TransactionInputAdapter {
276+
type Target = TransactionInput;
277+
278+
fn deref(&self) -> &Self::Target {
279+
&self.0
280+
}
281+
}
282+
283+
impl std::fmt::Display for TransactionInputAdapter {
284+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
285+
write!(f, "{}#{}", self.0.transaction_id, self.0.index)
286+
}
287+
}
288+
289+
impl From<TransactionInput> for TransactionInputAdapter {
290+
fn from(value: TransactionInput) -> Self {
291+
Self(value)
292+
}
293+
}
294+
269295
pub type TransactionId = Hash<32>;
270296

271297
pub type PoolId = Hash<28>;

crates/amaru-kernel/src/memoized/transaction_output.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use pallas_primitives::{Bytes, Hash, PolicyId, PositiveCoin, conway::Multiasset};
16+
1517
use crate::{
1618
Address, AlonzoValue, AssetName, KeyValuePairs, Lovelace, MemoizedDatum, MemoizedNativeScript,
1719
MemoizedPlutusData, MemoizedScript, MintedTransactionOutput, NonEmptyKeyValuePairs,
@@ -338,11 +340,57 @@ fn serialize_value<S: serde::ser::Serializer>(
338340
}
339341
}
340342

341-
// FIXME: Eventually allow deserializing complete values, not just coins.
342343
fn deserialize_value<'de, D: serde::de::Deserializer<'de>>(
343344
deserializer: D,
344345
) -> Result<Value, D::Error> {
345-
Ok(Value::Coin(serde::Deserialize::deserialize(deserializer)?))
346+
#[derive(serde::Deserialize)]
347+
enum ValueHelper {
348+
Coin(u64),
349+
Multiasset(u64, Vec<(String, Vec<(String, u64)>)>),
350+
}
351+
352+
let helper: ValueHelper = serde::Deserialize::deserialize(deserializer)?;
353+
354+
match helper {
355+
ValueHelper::Coin(coin) => Ok(Value::Coin(coin)),
356+
ValueHelper::Multiasset(coin, multiasset_data) => {
357+
let mut converted_multiasset = Vec::new();
358+
359+
for (policy_id, assets) in multiasset_data {
360+
let policy_id = hex::decode(&policy_id).map_err(|_| {
361+
serde::de::Error::custom(format!("invalid hex string: {policy_id}"))
362+
})?;
363+
364+
let mut converted_assets = Vec::new();
365+
for (asset_name, quantity) in assets {
366+
let asset_name = hex::decode(&asset_name).map_err(|_| {
367+
serde::de::Error::custom(format!("invalid hex string: {asset_name}"))
368+
})?;
369+
370+
converted_assets.push((
371+
Bytes::from(asset_name),
372+
quantity.try_into().map_err(|_| {
373+
serde::de::Error::custom(format!("invalid quantity value: {quantity}"))
374+
})?,
375+
));
376+
}
377+
378+
let policy_id: PolicyId = Hash::from(policy_id.as_slice());
379+
380+
converted_multiasset.push((
381+
policy_id,
382+
NonEmptyKeyValuePairs::from_vec(converted_assets).ok_or(
383+
serde::de::Error::custom(format!("empty asset bundle: {policy_id}")),
384+
)?,
385+
));
386+
}
387+
388+
let multiasset: Multiasset<PositiveCoin> =
389+
Multiasset::from_vec(converted_multiasset)
390+
.ok_or(serde::de::Error::custom("empty multiasset"))?;
391+
Ok(Value::Multiasset(coin, multiasset))
392+
}
393+
}
346394
}
347395

348396
pub fn serialize_script<S: serde::ser::Serializer>(

crates/amaru-ledger/src/rules/transaction.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub use fees::InvalidFees;
3030
pub mod inputs;
3131
pub use inputs::InvalidInputs;
3232

33+
pub mod collateral;
34+
pub use collateral::InvalidCollateral;
35+
3336
pub mod metadata;
3437
pub use metadata::InvalidTransactionMetadata;
3538

@@ -74,6 +77,9 @@ pub enum InvalidTransaction {
7477
#[error("invalid transaction scripts: {0}")]
7578
Scripts(#[from] InvalidScripts),
7679

80+
#[error("invalid collateral: {0}")]
81+
Collateral(#[from] InvalidCollateral),
82+
7783
#[error("invalid transaction metadata: {0}")]
7884
Metadata(#[from] InvalidTransactionMetadata),
7985
}
@@ -124,12 +130,22 @@ where
124130
.reference_inputs
125131
.as_deref()
126132
.map(|vec| vec.as_slice()),
127-
transaction_body
128-
.collateral
129-
.as_deref()
130-
.map(|vec| vec.as_slice()),
131133
)?;
132134

135+
if transaction_witness_set.redeemer.is_some() {
136+
collateral::execute(
137+
context,
138+
transaction_body
139+
.collateral
140+
.as_deref()
141+
.map(|vec| vec.as_slice()),
142+
transaction_body.collateral_return.as_ref(),
143+
transaction_body.total_collateral,
144+
transaction_body.fee,
145+
protocol_parameters,
146+
)?;
147+
}
148+
133149
mint::execute(context, transaction_body.mint.as_ref());
134150

135151
outputs::execute(

0 commit comments

Comments
 (0)