Add script context translations for voting purpose.

This commit is contained in:
KtorZ 2024-08-13 16:18:52 +02:00
parent bfc93bf076
commit 7501538053
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
10 changed files with 1729 additions and 29 deletions

View File

@ -1,13 +1,13 @@
use super::{ use super::{
error::Error, error::Error,
script_context::{DataLookupTable, ResolvedInput, ScriptPurpose, ScriptVersion}, script_context::{sort_voters, DataLookupTable, ResolvedInput, ScriptPurpose, ScriptVersion},
}; };
use itertools::Itertools; use itertools::Itertools;
use pallas_addresses::{Address, ScriptHash, ShelleyPaymentPart, StakePayload}; use pallas_addresses::{Address, ScriptHash, ShelleyPaymentPart, StakePayload};
use pallas_codec::utils::Nullable; use pallas_codec::utils::Nullable;
use pallas_primitives::conway::{ use pallas_primitives::conway::{
Certificate, GovAction, MintedTx, PolicyId, RedeemerTag, RedeemersKey, RewardAccount, Certificate, GovAction, MintedTx, PolicyId, RedeemerTag, RedeemersKey, RewardAccount,
StakeCredential, TransactionOutput, StakeCredential, TransactionOutput, Voter,
}; };
use std::collections::HashMap; use std::collections::HashMap;
@ -166,14 +166,29 @@ pub fn scripts_needed(tx: &MintedTx, utxos: &[ResolvedInput]) -> Result<ScriptsN
}) })
.unwrap_or_default(); .unwrap_or_default();
// TODO let mut voting = txb
assert!(txb.voting_procedures.is_none()); .voting_procedures
.as_deref()
.map(|m| {
m.iter()
.filter_map(|(voter, _)| match voter {
Voter::ConstitutionalCommitteeScript(hash) | Voter::DRepScript(hash) => {
Some((ScriptPurpose::Voting(voter.clone()), *hash))
}
Voter::ConstitutionalCommitteeKey(_)
| Voter::DRepKey(_)
| Voter::StakePoolKey(_) => None,
})
.collect::<ScriptsNeeded>()
})
.unwrap_or_default();
needed.append(&mut spend); needed.append(&mut spend);
needed.append(&mut reward); needed.append(&mut reward);
needed.append(&mut cert); needed.append(&mut cert);
needed.append(&mut mint); needed.append(&mut mint);
needed.append(&mut propose); needed.append(&mut propose);
needed.append(&mut voting);
Ok(needed) Ok(needed)
} }
@ -329,6 +344,24 @@ fn build_redeemer_key(
Ok(redeemer_key) Ok(redeemer_key)
} }
ScriptPurpose::Voting(v) => {
let redeemer_key = tx_body
.voting_procedures
.as_deref()
.map(|m| {
m.iter()
.sorted_by(|(a, _), (b, _)| sort_voters(a, b))
.position(|x| &x.0 == v)
})
.unwrap_or_default()
.map(|index| RedeemersKey {
tag: RedeemerTag::Vote,
index: index as u32,
});
Ok(redeemer_key)
}
ScriptPurpose::Proposing(_, procedure) => { ScriptPurpose::Proposing(_, procedure) => {
let redeemer_key = tx_body let redeemer_key = tx_body
.proposal_procedures .proposal_procedures

View File

@ -8,12 +8,12 @@ use pallas_crypto::hash::Hash;
use pallas_primitives::{ use pallas_primitives::{
alonzo, alonzo,
conway::{ conway::{
AddrKeyhash, Certificate, Coin, DatumHash, DatumOption, GovAction, Mint, AddrKeyhash, Certificate, Coin, DatumHash, DatumOption, GovAction, GovActionId, Mint,
MintedTransactionBody, MintedTransactionOutput, MintedTx, MintedWitnessSet, NativeScript, MintedTransactionBody, MintedTransactionOutput, MintedTx, MintedWitnessSet, NativeScript,
PlutusData, PlutusV1Script, PlutusV2Script, PlutusV3Script, PolicyId, PlutusData, PlutusV1Script, PlutusV2Script, PlutusV3Script, PolicyId,
PostAlonzoTransactionOutput, ProposalProcedure, PseudoDatumOption, PseudoScript, Redeemer, PostAlonzoTransactionOutput, ProposalProcedure, PseudoDatumOption, PseudoScript, Redeemer,
RedeemerTag, RedeemersKey, RequiredSigners, RewardAccount, ScriptHash, StakeCredential, RedeemerTag, RedeemersKey, RequiredSigners, RewardAccount, ScriptHash, StakeCredential,
TransactionInput, TransactionOutput, Value, TransactionInput, TransactionOutput, Value, Voter, VotingProcedure,
}, },
}; };
use pallas_traverse::{ComputeHash, OriginalHash}; use pallas_traverse::{ComputeHash, OriginalHash};
@ -53,6 +53,7 @@ pub enum ScriptInfo<T> {
Spending(TransactionInput, T), Spending(TransactionInput, T),
Rewarding(StakeCredential), Rewarding(StakeCredential),
Certifying(usize, Certificate), Certifying(usize, Certificate),
Voting(Voter),
Proposing(usize, ProposalProcedure), Proposing(usize, ProposalProcedure),
} }
@ -67,6 +68,7 @@ impl ScriptPurpose {
} }
Self::Rewarding(stake_credential) => ScriptInfo::Rewarding(stake_credential), Self::Rewarding(stake_credential) => ScriptInfo::Rewarding(stake_credential),
Self::Certifying(ix, certificate) => ScriptInfo::Certifying(ix, certificate), Self::Certifying(ix, certificate) => ScriptInfo::Certifying(ix, certificate),
Self::Voting(voter) => ScriptInfo::Voting(voter),
Self::Proposing(ix, procedure) => ScriptInfo::Proposing(ix, procedure), Self::Proposing(ix, procedure) => ScriptInfo::Proposing(ix, procedure),
} }
} }
@ -220,7 +222,7 @@ impl TxInfoV1 {
let redeemers = get_redeemers_info( let redeemers = get_redeemers_info(
&tx.transaction_witness_set, &tx.transaction_witness_set,
script_purpose_builder(&inputs[..], &mint, &certificates, &withdrawals, &[]), script_purpose_builder(&inputs[..], &mint, &certificates, &withdrawals, &[], &[]),
)?; )?;
Ok(TxInfo::V1(TxInfoV1 { Ok(TxInfo::V1(TxInfoV1 {
@ -269,7 +271,7 @@ impl TxInfoV2 {
let redeemers = get_redeemers_info( let redeemers = get_redeemers_info(
&tx.transaction_witness_set, &tx.transaction_witness_set,
script_purpose_builder(&inputs[..], &mint, &certificates, &withdrawals, &[]), script_purpose_builder(&inputs[..], &mint, &certificates, &withdrawals, &[], &[]),
)?; )?;
let reference_inputs = tx let reference_inputs = tx
@ -310,12 +312,11 @@ pub struct TxInfoV3 {
pub signatories: Vec<AddrKeyhash>, pub signatories: Vec<AddrKeyhash>,
pub redeemers: KeyValuePairs<ScriptPurpose, Redeemer>, pub redeemers: KeyValuePairs<ScriptPurpose, Redeemer>,
pub data: KeyValuePairs<DatumHash, PlutusData>, pub data: KeyValuePairs<DatumHash, PlutusData>,
pub proposal_procedures: Vec<ProposalProcedure>,
pub id: Hash<32>, pub id: Hash<32>,
pub votes: KeyValuePairs<Voter, KeyValuePairs<GovActionId, VotingProcedure>>,
pub proposal_procedures: Vec<ProposalProcedure>,
pub current_treasury_amount: Option<Coin>, pub current_treasury_amount: Option<Coin>,
pub treasury_donation: Option<PositiveCoin>, pub treasury_donation: Option<PositiveCoin>,
// TODO:
// votes : KeyValuePairs<Voter, KeyValuePairs<GovernanceActionId, Vote>>
} }
impl TxInfoV3 { impl TxInfoV3 {
@ -336,6 +337,8 @@ impl TxInfoV3 {
let proposal_procedures = let proposal_procedures =
get_proposal_procedures_info(&tx.transaction_body.proposal_procedures); get_proposal_procedures_info(&tx.transaction_body.proposal_procedures);
let votes = get_votes_info(&tx.transaction_body.voting_procedures);
let redeemers = get_redeemers_info( let redeemers = get_redeemers_info(
&tx.transaction_witness_set, &tx.transaction_witness_set,
script_purpose_builder( script_purpose_builder(
@ -344,6 +347,7 @@ impl TxInfoV3 {
&certificates, &certificates,
&withdrawals, &withdrawals,
&proposal_procedures, &proposal_procedures,
&votes.iter().map(|(k, _v)| k).collect_vec()[..],
), ),
)?; )?;
@ -368,6 +372,7 @@ impl TxInfoV3 {
data: KeyValuePairs::from(get_data_info(&tx.transaction_witness_set)), data: KeyValuePairs::from(get_data_info(&tx.transaction_witness_set)),
redeemers, redeemers,
proposal_procedures, proposal_procedures,
votes,
current_treasury_amount: get_current_treasury_amount_info( current_treasury_amount: get_current_treasury_amount_info(
&tx.transaction_body.treasury_value, &tx.transaction_body.treasury_value,
), ),
@ -713,12 +718,44 @@ pub fn get_redeemers_info<'a>(
)) ))
} }
pub fn get_votes_info(
votes: &Option<
NonEmptyKeyValuePairs<Voter, NonEmptyKeyValuePairs<GovActionId, VotingProcedure>>,
>,
) -> KeyValuePairs<Voter, KeyValuePairs<GovActionId, VotingProcedure>> {
KeyValuePairs::from(
votes
.as_deref()
.map(|votes| {
votes
.iter()
.sorted_by(|(a, _), (b, _)| sort_voters(a, b))
.cloned()
.map(|(voter, actions)| {
(
voter,
KeyValuePairs::from(
actions
.iter()
.sorted_by(|(a, _), (b, _)| sort_gov_action_id(a, b))
.cloned()
.collect::<Vec<_>>(),
),
)
})
.collect_vec()
})
.unwrap_or_default(),
)
}
fn script_purpose_builder<'a>( fn script_purpose_builder<'a>(
inputs: &'a [TxInInfo], inputs: &'a [TxInInfo],
mint: &'a MintValue, mint: &'a MintValue,
certificates: &'a [Certificate], certificates: &'a [Certificate],
withdrawals: &'a KeyValuePairs<Address, Coin>, withdrawals: &'a KeyValuePairs<Address, Coin>,
proposal_procedures: &'a [ProposalProcedure], proposal_procedures: &'a [ProposalProcedure],
votes: &'a [&'a Voter],
) -> impl Fn(&'a RedeemersKey) -> Result<ScriptPurpose, Error> { ) -> impl Fn(&'a RedeemersKey) -> Result<ScriptPurpose, Error> {
move |redeemer: &'a RedeemersKey| { move |redeemer: &'a RedeemersKey| {
let tag = redeemer.tag; let tag = redeemer.tag;
@ -754,12 +791,16 @@ fn script_purpose_builder<'a>(
}) })
.transpose()?, .transpose()?,
RedeemerTag::Vote => votes
.get(index)
.cloned()
.cloned()
.map(ScriptPurpose::Voting),
RedeemerTag::Propose => proposal_procedures RedeemerTag::Propose => proposal_procedures
.get(redeemer.index as usize) .get(index)
.cloned() .cloned()
.map(|p| ScriptPurpose::Proposing(index, p)), .map(|p| ScriptPurpose::Proposing(index, p)),
tag => todo!("get_script_purpose for {tag:?}"),
} }
.ok_or(Error::ExtraneousRedeemer) .ok_or(Error::ExtraneousRedeemer)
} }
@ -867,6 +908,18 @@ pub fn find_script(
_ => Err(Error::NonScriptStakeCredential), _ => Err(Error::NonScriptStakeCredential),
}), }),
RedeemerTag::Vote => get_votes_info(&tx.transaction_body.voting_procedures)
.get(redeemer.index as usize)
.ok_or(Error::MissingScriptForRedeemer)
.and_then(|(voter, _)| match voter {
Voter::ConstitutionalCommitteeScript(hash) => Ok(hash),
Voter::ConstitutionalCommitteeKey(..) => Err(Error::NonScriptStakeCredential),
Voter::DRepScript(hash) => Ok(hash),
Voter::DRepKey(..) => Err(Error::NonScriptStakeCredential),
Voter::StakePoolKey(..) => Err(Error::NonScriptStakeCredential),
})
.and_then(lookup_script),
RedeemerTag::Propose => { RedeemerTag::Propose => {
get_proposal_procedures_info(&tx.transaction_body.proposal_procedures) get_proposal_procedures_info(&tx.transaction_body.proposal_procedures)
.get(redeemer.index as usize) .get(redeemer.index as usize)
@ -884,8 +937,6 @@ pub fn find_script(
}) })
.and_then(lookup_script) .and_then(lookup_script)
} }
RedeemerTag::Vote => todo!("find_script: RedeemerTag::Vote"),
} }
} }
@ -1006,6 +1057,35 @@ fn sort_redeemers(a: &RedeemersKey, b: &RedeemersKey) -> Ordering {
} }
} }
pub fn sort_voters(a: &Voter, b: &Voter) -> Ordering {
fn explode(voter: &Voter) -> (usize, &Hash<28>) {
match voter {
Voter::ConstitutionalCommitteeScript(hash) => (0, hash),
Voter::ConstitutionalCommitteeKey(hash) => (1, hash),
Voter::DRepScript(hash) => (2, hash),
Voter::DRepKey(hash) => (3, hash),
Voter::StakePoolKey(hash) => (4, hash),
}
}
let (tag_a, hash_a) = explode(a);
let (tag_b, hash_b) = explode(b);
if tag_a == tag_b {
hash_a.cmp(hash_b)
} else {
tag_a.cmp(&tag_b)
}
}
fn sort_gov_action_id(a: &GovActionId, b: &GovActionId) -> Ordering {
if a.transaction_id == b.transaction_id {
a.action_index.cmp(&b.action_index)
} else {
a.transaction_id.cmp(&b.transaction_id)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
@ -1346,4 +1426,57 @@ mod tests {
// from the Haskell ledger / cardano node. // from the Haskell ledger / cardano node.
insta::assert_debug_snapshot!(script_context.to_plutus_data()); insta::assert_debug_snapshot!(script_context.to_plutus_data());
} }
#[test]
fn script_context_voting() {
let redeemer = Redeemer {
tag: RedeemerTag::Vote,
index: 0,
data: Data::constr(0, vec![Data::integer(42.into())]),
ex_units: ExUnits {
mem: 1000000,
steps: 100000000,
},
};
// NOTE: The transaction also contains treasury donation and current treasury amount
let script_context = fixture_tx_info(
"84a4008182582000000000000000000000000000000000000000000000000000\
0000000000000000018002182a13a58200581c00000000000000000000000000\
000000000000000000000000000000a182582099999999999999999999999999\
9999999999999999999999999999999999999918988200827668747470733a2f\
2f61696b656e2d6c616e672e6f72675820000000000000000000000000000000\
00000000000000000000000000000000008202581c0000000000000000000000\
0000000000000000000000000000000000a38258209999999999999999999999\
999999999999999999999999999999999999999999008202f682582088888888\
88888888888888888888888888888888888888888888888888888888018202f6\
8258207777777777777777777777777777777777777777777777777777777777\
777777028202f68203581c43fa47afc68a7913fbe2f400e3849cb492d9a2610c\
85966de0f2ba1ea1825820999999999999999999999999999999999999999999\
9999999999999999999999038200f68204581c00000000000000000000000000\
000000000000000000000000000000a182582099999999999999999999999999\
99999999999999999999999999999999999999048201f68201581c43fa47afc6\
8a7913fbe2f400e3849cb492d9a2610c85966de0f2ba1ea18258209999999999\
999999999999999999999999999999999999999999999999999999018201f6a2\
0582840402d87980821a000f42401a05f5e100840400d87981182a821a000f42\
401a05f5e1000781587d587b0101003232323232323225333333008001153330\
033370e900018029baa001153330073006375400224a66600894452615330054\
911856616c696461746f722072657475726e65642066616c7365001365600200\
2002002002002153300249010b5f746d70303a20566f696400165734ae7155ce\
aab9e5573eae91f5f6",
"8182582000000000000000000000000000000000000000000000000000000000\
0000000000",
"81a200581d600000000000000000000000000000000000000000000000000000\
0000011a000f4240",
)
.into_script_context(&redeemer, None)
.unwrap();
// NOTE: The initial snapshot has been generated using the Haskell
// implementation of the ledger library for that same serialized
// transactions. It is meant to control that our construction of the
// script context and its serialization matches exactly those
// from the Haskell ledger / cardano node.
insta::assert_debug_snapshot!(script_context.to_plutus_data());
}
} }

View File

@ -18,7 +18,8 @@ use pallas_primitives::conway::{
AssetName, BigInt, Certificate, Coin, Constitution, Constr, DRep, DRepVotingThresholds, AssetName, BigInt, Certificate, Coin, Constitution, Constr, DRep, DRepVotingThresholds,
DatumOption, ExUnitPrices, ExUnits, GovAction, GovActionId, Mint, PlutusData, PolicyId, DatumOption, ExUnitPrices, ExUnits, GovAction, GovActionId, Mint, PlutusData, PolicyId,
PoolVotingThresholds, ProposalProcedure, ProtocolParamUpdate, PseudoScript, RationalNumber, PoolVotingThresholds, ProposalProcedure, ProtocolParamUpdate, PseudoScript, RationalNumber,
Redeemer, ScriptRef, StakeCredential, TransactionInput, TransactionOutput, Value, Redeemer, ScriptRef, StakeCredential, TransactionInput, TransactionOutput, Value, Vote, Voter,
VotingProcedure,
}; };
use pallas_traverse::ComputeHash; use pallas_traverse::ComputeHash;
@ -953,6 +954,9 @@ impl ToPlutusData for ScriptPurpose {
ScriptPurpose::Certifying(ix, dcert) => { ScriptPurpose::Certifying(ix, dcert) => {
wrap_multiple_with_constr(3, vec![ix.to_plutus_data(), dcert.to_plutus_data()]) wrap_multiple_with_constr(3, vec![ix.to_plutus_data(), dcert.to_plutus_data()])
} }
ScriptPurpose::Voting(voter) => {
wrap_multiple_with_constr(4, vec![voter.to_plutus_data()])
}
ScriptPurpose::Proposing(ix, procedure) => { ScriptPurpose::Proposing(ix, procedure) => {
wrap_multiple_with_constr(5, vec![ix.to_plutus_data(), procedure.to_plutus_data()]) wrap_multiple_with_constr(5, vec![ix.to_plutus_data(), procedure.to_plutus_data()])
} }
@ -1293,6 +1297,42 @@ impl<'a> ToPlutusData for WithWrappedStakeCredential<'a, KeyValuePairs<Address,
} }
} }
impl ToPlutusData for Voter {
fn to_plutus_data(&self) -> PlutusData {
match self {
Voter::ConstitutionalCommitteeScript(hash) => {
wrap_with_constr(0, StakeCredential::Scripthash(*hash).to_plutus_data())
}
Voter::ConstitutionalCommitteeKey(hash) => {
wrap_with_constr(0, StakeCredential::AddrKeyhash(*hash).to_plutus_data())
}
Voter::DRepScript(hash) => {
wrap_with_constr(1, StakeCredential::Scripthash(*hash).to_plutus_data())
}
Voter::DRepKey(hash) => {
wrap_with_constr(1, StakeCredential::AddrKeyhash(*hash).to_plutus_data())
}
Voter::StakePoolKey(hash) => wrap_with_constr(2, hash.to_plutus_data()),
}
}
}
impl ToPlutusData for VotingProcedure {
fn to_plutus_data(&self) -> PlutusData {
self.vote.to_plutus_data()
}
}
impl ToPlutusData for Vote {
fn to_plutus_data(&self) -> PlutusData {
match self {
Vote::No => empty_constr(0),
Vote::Yes => empty_constr(1),
Vote::Abstain => empty_constr(2),
}
}
}
impl<T> ToPlutusData for ScriptInfo<T> impl<T> ToPlutusData for ScriptInfo<T>
where where
T: ToPlutusData, T: ToPlutusData,
@ -1309,6 +1349,7 @@ where
ScriptInfo::Certifying(ix, dcert) => { ScriptInfo::Certifying(ix, dcert) => {
wrap_multiple_with_constr(3, vec![ix.to_plutus_data(), dcert.to_plutus_data()]) wrap_multiple_with_constr(3, vec![ix.to_plutus_data(), dcert.to_plutus_data()])
} }
ScriptInfo::Voting(voter) => wrap_multiple_with_constr(4, vec![voter.to_plutus_data()]),
ScriptInfo::Proposing(ix, procedure) => { ScriptInfo::Proposing(ix, procedure) => {
wrap_multiple_with_constr(5, vec![ix.to_plutus_data(), procedure.to_plutus_data()]) wrap_multiple_with_constr(5, vec![ix.to_plutus_data(), procedure.to_plutus_data()])
} }
@ -1370,7 +1411,7 @@ impl ToPlutusData for TxInfo {
tx_info.redeemers.to_plutus_data(), tx_info.redeemers.to_plutus_data(),
tx_info.data.to_plutus_data(), tx_info.data.to_plutus_data(),
tx_info.id.to_plutus_data(), tx_info.id.to_plutus_data(),
Data::map(vec![]), // TODO tx_info.votes :: Map Voter (Map GovernanceActionId Vote) tx_info.votes.to_plutus_data(),
tx_info.proposal_procedures.to_plutus_data(), tx_info.proposal_procedures.to_plutus_data(),
tx_info.current_treasury_amount.to_plutus_data(), tx_info.current_treasury_amount.to_plutus_data(),
tx_info.treasury_donation.to_plutus_data(), tx_info.treasury_donation.to_plutus_data(),

View File

@ -9,14 +9,36 @@ Because we can't have fully static context (since they contain the validator
and its hash), we define _templates_. and its hash), we define _templates_.
Everything is a bit clunky, but steps have been captured in a `test.sh` script Everything is a bit clunky, but steps have been captured in a `test.sh` script
for convenience. for convenience. The test still assumes a few things. For any
`VALIDATOR_GROUP`:
- There's a `ctx/{VALIDATOR_GROUP}/tx.template` and
`ctx/{VALIDATOR_GROUP}/resolved_inputs.template` respectively.
- There's a corresponding validator `validators/{VALIDATOR_GROUP}.ak`
- Templates may reference variables using a mustache-template-like syntax `{{ ... }}`.
Provided variables are:
- `{VALIDATOR_GROUP}.{VALIDATOR_TITLE}.hash`
- `{VALIDATOR_GROUP}.{VALIDATOR_TITLE}.cbor`
Where `VALIDATOR_TITLE` corresponds to the validator Aiken's name.
## How to use ## How to use
``` ```
./test.sh [VALIDATOR_TITLE] ./test.sh VALIDATOR_GROUP
``` ```
> ![TIP]
> By default, this recompiles the project in --release mode, which can be long
> when iterating / testing. You can provide a binary to use as a second
> argument. For a dev build, just do:
>
> ```
> ./test.sh VALIDATOR_GROUP "cargo run --"
> ```
## Test Coverage ## Test Coverage
- Purpose - Purpose
@ -24,7 +46,7 @@ for convenience.
- [x] mint - [x] mint
- [ ] withdraw - [ ] withdraw
- [x] publish - [x] publish
- [ ] voting - [x] voting
- [x] proposing - [x] proposing
- Transaction body - Transaction body
@ -66,7 +88,7 @@ for convenience.
- [x] datums - [x] datums
- votes - votes
- [x] none - [x] none
- [ ] some - [x] some
- proposal procedures - proposal procedures
- [x] none - [x] none
- [x] some - [x] some
@ -122,14 +144,14 @@ for convenience.
- [x] info action - [x] info action
- Vote - Vote
- [ ] No - [x] No
- [ ] Yes - [x] Yes
- [ ] Abstain - [x] Abstain
- Voter - Voter
- [ ] CC - [x] CC
- [ ] DRep - [x] DRep
- [ ] SPO - [x] SPO
- ChangedParameters - ChangedParameters
- [x] txFeePerByte - [x] txFeePerByte

View File

@ -0,0 +1,5 @@
[
{ 0: h'6000000000000000000000000000000000000000000000000000000000'
, 1: 1000000
}
]

View File

@ -0,0 +1,52 @@
[
{ 0:
[ [h'0000000000000000000000000000000000000000000000000000000000000000', 0]
]
, 1:
[]
, 2: 42
, 19:
{ [ 0, h'00000000000000000000000000000000000000000000000000000000' ]:
{ [ h'9999999999999999999999999999999999999999999999999999999999999999', 152 ]:
[ 0
, [ "https://aiken-lang.org"
, h'0000000000000000000000000000000000000000000000000000000000000000'
]
]
}
, [ 2, h'00000000000000000000000000000000000000000000000000000000' ]:
{ [ h'9999999999999999999999999999999999999999999999999999999999999999', 0 ]: [ 2, null ]
, [ h'8888888888888888888888888888888888888888888888888888888888888888', 1 ]: [ 2, null ]
, [ h'7777777777777777777777777777777777777777777777777777777777777777', 2 ]: [ 2, null ]
}
, [ 3, h'{{ voting.script.hash }}' ]:
{ [ h'9999999999999999999999999999999999999999999999999999999999999999', 3 ]: [ 0, null ]
}
, [ 4, h'00000000000000000000000000000000000000000000000000000000' ]:
{ [ h'9999999999999999999999999999999999999999999999999999999999999999', 4 ]: [ 1, null ]
}
, [ 1, h'{{ voting.script.hash }}' ]:
{ [ h'9999999999999999999999999999999999999999999999999999999999999999', 1 ]: [ 1, null ]
}
}
},
{ 5: [ [4, 2, 121([]), [1000000, 100000000]]
, [4, 0, 121([42]), [1000000, 100000000]]
]
, 7: [h'{{ voting.script.cbor }}']
},
true,
null
]

View File

@ -6,7 +6,7 @@
"plutusVersion": "v3", "plutusVersion": "v3",
"compiler": { "compiler": {
"name": "Aiken", "name": "Aiken",
"version": "v1.0.31-alpha+81c0152" "version": "v1.0.31-alpha+bfc93bf"
}, },
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
@ -82,6 +82,17 @@
}, },
"compiledCode": "59099f010100323232323232323232323232322533333300e00115332330073001300937540042a66601660146ea8008494cccccc04000454ccc020c008c028dd50008a99980618059baa001125333009323232323253330123758600660226ea8c014c044dd50030a9998091bac3014301530113754600a60226ea801854ccc048dd6180a180a980a980a980a980a980a980a980a98089baa30053011375400c2a66601c66e1d2054375a6028602a602a602a60226ea8c014c044dd5003099299980799baf4c101a0003015301630163016301630163016301630163016301630123754600c60246ea801c5288a9980824932657870656374205b5d203d3d20646963742e746f5f7061697273286374782e7472616e73616374696f6e2e646174756d73290016533300e3375e98012fa1d87a9fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffffd8798000301430153015301530153015301530153015301530113754600a60226ea8018526153300f491e86578706563740a202020205b0a20202020202050616972285370656e64280a20202020202020204f75747075745265666572656e6365207b0a202020202020202020207472616e73616374696f6e5f69643a20232230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030222c0a202020202020202020206f75747075745f696e6465783a20302c0a20202020202020207d2c0a202020202020292c0a202020202020766f69642829292c0a202020205d203d3d2072656465656d6572730016153300f49120657870656374203432203d3d206374782e7472616e73616374696f6e2e6665650016153300f4912d657870656374205b5d203d206374782e7472616e73616374696f6e2e65787472615f7369676e61746f726965730016153300f4912c657870656374205b5d203d206374782e7472616e73616374696f6e2e7265666572656e63655f696e707574730016153300f49123657870656374205b5d203d206374782e7472616e73616374696f6e2e6f757470757473001632533301200100c132533301330160021323232325333013300d375a603260340042646464646464a66603266e1d2004301b3754603e0042a66466034600260386ea800854ccc068cdc7804245200000000000000000000000000000000000000000000000000000000000000000001533301a3375e6e98010dd3299980d25014bd6f7b6300991919800800a5eb7bdb180894ccc0840044cc088cdd82601014000374c00697adef6c60132323232533302133720910100002133026337609801014000374c00e00a2a66604266e3d22100002133026337609801014000374c00e00626604c66ec0dd48011ba600133006006003375660460066eb8c084008c094008c08c004c8cc0040052f5bded8c044a66604000226604266ec130010140004c01051a3b9aca00004bd6f7b630099191919299981019b90489000021330253376098010140004c01051a3b9aca0000005153330203371e9101000021330253376098010140004c01051a3b9aca0000003133025337606ea4008dd4000998030030019bad3022003375c60400046048004604400226464a6660386006603c6ea8c08800854ccc070c00cc078dd50008a4c03603660426044002603a6ea801854cc06d24013f657870656374207265736f6c7665645f696e7075745f76616c7565203d3d206173736574732e66726f6d5f6c6f76656c6163652831303030303030303030290016153301b491606578706563740a202020207472616e73616374696f6e5f6964203d3d20232230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030220016370e900100b80b980f180f800980f0011bab301c001301c002301a001301637540060226eb8c060004c050dd5180b801180b180b80098091baa00100d30140013758600860206ea8c010c040dd5002a99980619baf4c0132d87a9fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffd8799fd87980ffff003001300f37540082930a99806a49cd6578706563740a202020205370656e64696e67280a2020202020204f75747075745265666572656e6365207b0a20202020202020207472616e73616374696f6e5f69643a20232230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030222c0a20202020202020206f75747075745f696e6465783a20302c0a2020202020207d2c0a202020202020536f6d6528766f69642829292c0a2020202029203d3d20696e666f00162301230133013001533300a3371e910120c6fbd346681a8f8337f6b3e51e6ec973f1509367eabc3a44c849af58a1d8471b00375c602060226022602260226022602260226022602260226022601a6ea8c004c034dd50010a4c2a66016921546578706563740a2020202023226336666264333436363831613866383333376636623365353165366563393733663135303933363765616263336134346338343961663538613164383437316222203d3d206964001623010001149854cc0292411856616c696461746f722072657475726e65642066616c73650013656004004004004004004004370e90000018018018018018a99802a4810b5f746d70323a20566f6964001615330044910b5f746d70313a20566f696400161533003491ff657870656374205b0a20202020496e707574207b0a2020202020206f75747075745f7265666572656e63653a204f75747075745265666572656e6365207b207472616e73616374696f6e5f69642c206f75747075745f696e6465783a2030207d2c0a2020202020206f75747075743a204f7574707574207b0a2020202020202020616464726573732c0a202020202020202076616c75653a207265736f6c7665645f696e7075745f76616c75652c0a2020202020202020646174756d3a20496e6c696e65446174756d285f292c0a20202020202020207265666572656e63655f7363726970743a204e6f6e652c0a2020202020207d2c0a202020207d2c0a200b205d203d20696e7075747300161533002491566578706563742041646472657373207b207061796d656e745f63726564656e7469616c3a20536372697074285f292c207374616b655f63726564656e7469616c3a204e6f6e65207d203d0a202020206164647265737300165734ae7155ceaab9e5573eae815d0aba257481", "compiledCode": "59099f010100323232323232323232323232322533333300e00115332330073001300937540042a66601660146ea8008494cccccc04000454ccc020c008c028dd50008a99980618059baa001125333009323232323253330123758600660226ea8c014c044dd50030a9998091bac3014301530113754600a60226ea801854ccc048dd6180a180a980a980a980a980a980a980a980a98089baa30053011375400c2a66601c66e1d2054375a6028602a602a602a60226ea8c014c044dd5003099299980799baf4c101a0003015301630163016301630163016301630163016301630123754600c60246ea801c5288a9980824932657870656374205b5d203d3d20646963742e746f5f7061697273286374782e7472616e73616374696f6e2e646174756d73290016533300e3375e98012fa1d87a9fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffffd8798000301430153015301530153015301530153015301530113754600a60226ea8018526153300f491e86578706563740a202020205b0a20202020202050616972285370656e64280a20202020202020204f75747075745265666572656e6365207b0a202020202020202020207472616e73616374696f6e5f69643a20232230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030222c0a202020202020202020206f75747075745f696e6465783a20302c0a20202020202020207d2c0a202020202020292c0a202020202020766f69642829292c0a202020205d203d3d2072656465656d6572730016153300f49120657870656374203432203d3d206374782e7472616e73616374696f6e2e6665650016153300f4912d657870656374205b5d203d206374782e7472616e73616374696f6e2e65787472615f7369676e61746f726965730016153300f4912c657870656374205b5d203d206374782e7472616e73616374696f6e2e7265666572656e63655f696e707574730016153300f49123657870656374205b5d203d206374782e7472616e73616374696f6e2e6f757470757473001632533301200100c132533301330160021323232325333013300d375a603260340042646464646464a66603266e1d2004301b3754603e0042a66466034600260386ea800854ccc068cdc7804245200000000000000000000000000000000000000000000000000000000000000000001533301a3375e6e98010dd3299980d25014bd6f7b6300991919800800a5eb7bdb180894ccc0840044cc088cdd82601014000374c00697adef6c60132323232533302133720910100002133026337609801014000374c00e00a2a66604266e3d22100002133026337609801014000374c00e00626604c66ec0dd48011ba600133006006003375660460066eb8c084008c094008c08c004c8cc0040052f5bded8c044a66604000226604266ec130010140004c01051a3b9aca00004bd6f7b630099191919299981019b90489000021330253376098010140004c01051a3b9aca0000005153330203371e9101000021330253376098010140004c01051a3b9aca0000003133025337606ea4008dd4000998030030019bad3022003375c60400046048004604400226464a6660386006603c6ea8c08800854ccc070c00cc078dd50008a4c03603660426044002603a6ea801854cc06d24013f657870656374207265736f6c7665645f696e7075745f76616c7565203d3d206173736574732e66726f6d5f6c6f76656c6163652831303030303030303030290016153301b491606578706563740a202020207472616e73616374696f6e5f6964203d3d20232230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030220016370e900100b80b980f180f800980f0011bab301c001301c002301a001301637540060226eb8c060004c050dd5180b801180b180b80098091baa00100d30140013758600860206ea8c010c040dd5002a99980619baf4c0132d87a9fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffd8799fd87980ffff003001300f37540082930a99806a49cd6578706563740a202020205370656e64696e67280a2020202020204f75747075745265666572656e6365207b0a20202020202020207472616e73616374696f6e5f69643a20232230303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030222c0a20202020202020206f75747075745f696e6465783a20302c0a2020202020207d2c0a202020202020536f6d6528766f69642829292c0a2020202029203d3d20696e666f00162301230133013001533300a3371e910120c6fbd346681a8f8337f6b3e51e6ec973f1509367eabc3a44c849af58a1d8471b00375c602060226022602260226022602260226022602260226022601a6ea8c004c034dd50010a4c2a66016921546578706563740a2020202023226336666264333436363831613866383333376636623365353165366563393733663135303933363765616263336134346338343961663538613164383437316222203d3d206964001623010001149854cc0292411856616c696461746f722072657475726e65642066616c73650013656004004004004004004004370e90000018018018018018a99802a4810b5f746d70323a20566f6964001615330044910b5f746d70313a20566f696400161533003491ff657870656374205b0a20202020496e707574207b0a2020202020206f75747075745f7265666572656e63653a204f75747075745265666572656e6365207b207472616e73616374696f6e5f69642c206f75747075745f696e6465783a2030207d2c0a2020202020206f75747075743a204f7574707574207b0a2020202020202020616464726573732c0a202020202020202076616c75653a207265736f6c7665645f696e7075745f76616c75652c0a2020202020202020646174756d3a20496e6c696e65446174756d285f292c0a20202020202020207265666572656e63655f7363726970743a204e6f6e652c0a2020202020207d2c0a202020207d2c0a200b205d203d20696e7075747300161533002491566578706563742041646472657373207b207061796d656e745f63726564656e7469616c3a20536372697074285f292c207374616b655f63726564656e7469616c3a204e6f6e65207d203d0a202020206164647265737300165734ae7155ceaab9e5573eae815d0aba257481",
"hash": "cef0769e42ca13a9ffcd71a6ed03e3e03adb72f4cdf81bb28137c55a" "hash": "cef0769e42ca13a9ffcd71a6ed03e3e03adb72f4cdf81bb28137c55a"
},
{
"title": "voting.script",
"redeemer": {
"title": "_tmp0",
"schema": {
"$ref": "#/definitions/Void"
}
},
"compiledCode": "5908e2010100323232323232323232323232322533333300e00115332330073001300937540042a66601660146ea8008494ccc020c8c8c8c8c94ccc034c01cc03cdd500089919192999808180518091baa0021533233011300130133754602e60286ea800c54ccc0540080344c94ccc058c06400c4c8c8c94ccc054c014dd6980d980e0010a99980a9802980b9baa003153330153371e002910120999999999999999999999999999999999999999999999999999999999999999900153330153375e98158d8799f9fd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffffa1d8799f582099999999999999999999999999999999999999999999999999999999999999991898ffd87980ffff003300a00c480084c94ccc058c040c060dd50008991919299980c9804980d9baa002153330193009301b3754603e60386ea800854ccc07400405854ccc064cdd7a61abd8799f9fd87a9fd8799f581c00000000000000000000000000000000000000000000000000000000ffffa3d8799f5820777777777777777777777777777777777777777777777777777777777777777702ffd87b80d8799f5820888888888888888888888888888888888888888888888888888888888888888801ffd87b80d8799f5820999999999999999999999999999999999999999999999999999999999999999900ffd87b80ffff003300e010480184c94ccc068c050c070dd50008991919299980e99b8748010c07cdd5001099299981100100e0a99980f19b8f0014891c000000000000000000000000000000000000000000000000000000000014a22a6603e9211865787065637420706f6f6c5f6964203d3d206f6e6c7930730016375c604660406ea800806cdd5980f801180e8009919bb030210013021302200137586040603a6ea8004060cc0380412008153301a491ff6578706563740a202020202020536f6d65280a2020202020202020506169722844656c6567617465526570726573656e74617469766528566572696669636174696f6e4b6579286f6e6c79307329292c0a20202020202020205b0a202020202020202020205061697228476f7665726e616e6365416374696f6e4964207b207472616e73616374696f6e3a206f6e6c7937732c2070726f706f73616c5f70726f6365647572653a2032207d2c0a202020202020202020204162737461696e292c0a202020202020202020205061697228476f7665726e616e6365416374696f6e4964207b207472616e73616374696f6e3a206f6e6c7938732c2070726f706fb673616c5f70726f6365647572653a2031207d2c0a202020202020202020204162737461696e292c0a202020202020202020205061697228476f7665726e616e6365416374696f6e4964207b207472616e73616374696f6e3a206f6e6c7939732c2070726f706f73616c5f70726f6365647572653a2030207d2c0a202020202020202020204162737461696e292c0a20202020202020205d292c0a20202020202029203d3d206c6973742e617428766f7465732c20332900160160163756603600460320026466ec0c074004c074c078004dd6180e180c9baa0010133300a00c4801054cc0592401ff6578706563740a202020202020536f6d65280a20202020202020205061697228436f6e737469747574696f6e616c436f6d6d69747465654d656d62657228566572696669636174696f6e4b6579286f6e6c79307329292c0a20202020202020205b0a202020202020202020205061697228476f7665726e616e6365416374696f6e4964207b0a2020202020202020202020207472616e73616374696f6e3a206f6e6c7939732c0a20202020202020202020202070726f706f73616c5f70726f6365647572653a203135322c0a202020202020202020207d2c0a202020202020202020204e6f292c0a20202020202020205d292c0a20202020202029203d3d20116c6973742e617428766f7465732c203129001615330164911c657870656374207472616e73616374696f6e203d3d206f6e6c7939730016011011375c6034002602c6ea8c054008c054004038c05c008dc3a40040180186eacc048008c040004c8cdd8180a000980a180a8009bac301330103754002012660020069000180080091129998088010a60103d87a800013232533300f300900313374a90001980a1ba73301430110023301430120024bd7025eb804ccc014014004cdc0001a4002602a00660260046eacc03cc040c040c040c040c040c040c040c040c040c040c040c040c030dd5180798061baa0023253330093253333330120021533300a3004300c3754004264a66601e002004264a666666028002006006006264a66602260280062a66601a66e1d205400114a20080086eb400400cc044004c034dd500100080080080080089929999998090010a999805180218061baa0021533300e300d375400429440040040040040040045280a4c2a660149210f6578706563742069735f76616c69640016300e300f300b37540022930a99804a491856616c696461746f722072657475726e65642066616c73650013656006370e90000028028028028028a99802a481ab65787065637420536f6d65280a2020202020205061697228436f6e737469747574696f6e616c436f6d6d69747465654d656d62657228536372697074282e2e29292c0a2020202020205b5061697228476f7665726e616e6365416374696f6e4964207b207472616e73616374696f6e2c2070726f706f73616c5f70726f6365647572653a2031207d2c20596573295d292c0a2020202029203d206c6973742e617428766f7465732c203029001615330044915865787065637420536f6d6528506169722844656c6567617465526570726573656e74617469766528536372697074282e2e29292c205b5f2c202e2e5d2929203d0a2020202020206c6973742e617428766f7465732c203229001615330034914265787065637420536f6d652850616972285374616b65506f6f6c28706f6f6c5f6964292c205b5f2c202e2e5d2929203d206c6973742e617428766f7465732c203429001615330024910b5f746d70303a20566f696400165734ae7155ceaab9e5573eae815d0aba257481",
"hash": "849324b02de5c5d1cbf2226bd321e7ca5200de4a4c314864dbc24813"
} }
], ],
"definitions": { "definitions": {

View File

@ -56,8 +56,11 @@ for ITEM in ${VALIDATORS[@]}; do
done done
echo $RESOLVED_INPUTS | cbor-diag --to hex --from diag > ctx/$TITLE/resolved_inputs.cbor echo $RESOLVED_INPUTS | cbor-diag --to hex --from diag > ctx/$TITLE/resolved_inputs.cbor
echo $TRANSACTION | cbor-diag --to hex --from diag > ctx/$TITLE/tx.cbor echo $TRANSACTION | cbor-diag --to hex --from diag > ctx/$TITLE/tx.cbor
# ogmios inspect transaction $(cat ctx/$TITLE/tx.cbor) | jq ".votes"
$AIKEN tx simulate \ $AIKEN tx simulate \
ctx/$TITLE/tx.cbor \ ctx/$TITLE/tx.cbor \
ctx/inputs.cbor \ ctx/inputs.cbor \

View File

@ -0,0 +1,83 @@
use aiken/collection/list
use cardano/credential.{Script, VerificationKey}
use cardano/governance.{
Abstain, ConstitutionalCommitteeMember, DelegateRepresentative,
GovernanceActionId, No, StakePool, Yes,
}
use cardano/transaction.{ScriptContext}
type Foo {
Foo(Int)
}
const only0s = #"00000000000000000000000000000000000000000000000000000000"
const only7s =
#"7777777777777777777777777777777777777777777777777777777777777777"
const only8s =
#"8888888888888888888888888888888888888888888888888888888888888888"
const only9s =
#"9999999999999999999999999999999999999999999999999999999999999999"
validator {
fn script(_tmp0: Void, ctx: ScriptContext) {
assert_redeemer(ctx.redeemer)
let votes = ctx.transaction.votes
expect Some(
Pair(ConstitutionalCommitteeMember(Script(..)),
[Pair(GovernanceActionId { transaction, proposal_procedure: 1 }, Yes)]),
) = list.at(votes, 0)
expect transaction == only9s
expect
Some(
Pair(ConstitutionalCommitteeMember(VerificationKey(only0s)),
[
Pair(GovernanceActionId {
transaction: only9s,
proposal_procedure: 152,
},
No),
]),
) == list.at(votes, 1)
expect Some(Pair(DelegateRepresentative(Script(..)), [_, ..])) =
list.at(votes, 2)
expect
Some(
Pair(DelegateRepresentative(VerificationKey(only0s)),
[
Pair(GovernanceActionId { transaction: only7s, proposal_procedure: 2 },
Abstain),
Pair(GovernanceActionId { transaction: only8s, proposal_procedure: 1 },
Abstain),
Pair(GovernanceActionId { transaction: only9s, proposal_procedure: 0 },
Abstain),
]),
) == list.at(votes, 3)
expect Some(Pair(StakePool(pool_id), [_, ..])) = list.at(votes, 4)
expect pool_id == only0s
True
}
}
fn assert_redeemer(data: Data) {
let is_valid =
if data is Foo(42): Foo {
True
} else if data is Void {
True
} else {
False
}
expect is_valid
Void
}