Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Other guiding principles:
### Changed

- **amaru-ledger**: validate voters in a transaction actually exist in ledger state. ([#1138][], [#923][])
- **amaru-ledger**: validate the governance actions a transaction votes on actually exist, counting proposals submitted earlier in the same block. ([#1139][], [#924][])

### Fixed

Expand Down Expand Up @@ -275,6 +276,7 @@ Other guiding principles:
[#912]: https://github.com/pragma-org/amaru/issues/912
[#915]: https://github.com/pragma-org/amaru/issues/915
[#923]: https://github.com/pragma-org/amaru/issues/923
[#924]: https://github.com/pragma-org/amaru/issues/924
[#928]: https://github.com/pragma-org/amaru/issues/928
[#929]: https://github.com/pragma-org/amaru/issues/929
[#932]: https://github.com/pragma-org/amaru/issues/932
Expand Down Expand Up @@ -330,3 +332,4 @@ Other guiding principles:
[#1109]: https://github.com/pragma-org/amaru/pull/1109
[#1118]: https://github.com/pragma-org/amaru/pull/1118
[#1138]: https://github.com/pragma-org/amaru/pull/1138
[#1139]: https://github.com/pragma-org/amaru/pull/1139
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ pub(super) enum Predicate {
ConwayTxRefScriptsSizeTooBig,
ConwayWdrlNotDelegatedToDRep,
FeeTooSmallUTxO,
GovActionsDoNotExist,
IncorrectDepositDELEG,
IncorrectTotalCollateralField,
ConwayTreasuryValueMismatch,
Expand Down Expand Up @@ -342,6 +343,9 @@ impl From<PhaseOneError> for Predicate {
PhaseOneError::VotingProcedures(InvalidVotingProcedures::VotersDoNotExist(_)) => {
Predicate::VotersDoNotExist
}
PhaseOneError::VotingProcedures(InvalidVotingProcedures::GovActionsDoNotExist(_)) => {
Predicate::GovActionsDoNotExist
}
PhaseOneError::ValueNotPreserved(_) => Predicate::ValueNotConservedUTxO,
PhaseOneError::Certificates(InvalidCertificates::StakeCredentialInvalidPoolDelegation(ref e)) => match e {
DelegateError::UnknownSource(_) => Predicate::StakeCredentialInvalidPoolDelegation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ use crate::context::{CommitteeSlice, DRepsSlice, PoolsSlice, ProposalsSlice, Wit
pub enum InvalidVotingProcedures {
#[error("voters do not exist: {0:?}")]
VotersDoNotExist(BTreeSet<Voter>),

#[error("governance actions do not exist: {0:?}")]
GovActionsDoNotExist(BTreeSet<ProposalId>),
}

pub(crate) fn execute<C>(
Expand All @@ -38,13 +41,29 @@ where
if let Some(voting_procedures) = voting_procedures {
let voting_procedures = voting_procedures.into_iter().collect::<BTreeMap<_, _>>();

let unknown_voters =
voting_procedures.keys().filter(|voter| !exists(context, voter)).cloned().collect::<BTreeSet<_>>();
let mut unknown_voters = BTreeSet::new();
let mut unknown_proposals = BTreeSet::new();

for (voter, votes) in voting_procedures.iter() {
if !exists(context, voter) {
unknown_voters.insert(voter.clone());
}

for (proposal_id, _) in votes.iter() {
if !ProposalsSlice::exists(context, proposal_id) {
unknown_proposals.insert(*proposal_id);
}
}
}

if !unknown_voters.is_empty() {
return Err(InvalidVotingProcedures::VotersDoNotExist(unknown_voters));
}

if !unknown_proposals.is_empty() {
return Err(InvalidVotingProcedures::GovActionsDoNotExist(unknown_proposals));
}

voting_procedures.into_iter().enumerate().for_each(|(index, (voter, votes))| {
match voter.owner() {
StakeCredential::ScriptHash(hash) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"title": "vote cast on a governance action absent from the proposals state",
"description": "A registered DRep naming a proposal id that no proposal in state carries.",
"network": "preprod",
"eraHistory": {
"$ref": "common/eraHistory/preprod-conway.json"
},
"protocolParameters": {
"$ref": "common/protocolParameters/preprod-conway-v10.json"
},
"initialState": {
"utxo": [
{
"input": "8258207ae12fe7076ec75319e0ecac782bcb6d828bb6a4baa49eada7116b47a80d449200",
"output": "a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a004c4b40"
}
],
"pools": [],
"accounts": [],
"dreps": [
{
"credential": "8200581c93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8",
"deposit": 500000000,
"registeredAt": {
"transaction": {
"slot": 0,
"transactionIndex": 0
},
"certificateIndex": 0
},
"validUntil": 1000
}
],
"committee": [],
"proposals": [
"8258207e2b9d5f1a3c7e5b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b00"
],
"governanceActivity": {
"consecutiveDormantEpochs": 0
}
},
"point": {
"slot": 0,
"transactionIndex": 0
},
"transaction": "84a500d90102818258207ae12fe7076ec75319e0ecac782bcb6d828bb6a4baa49eada7116b47a80d4492000181a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a00493e00021a00030d400f0013a18202581c93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8a1825820bbd665a051206b767522b19427cced4e0420a050852f7ba1c875c9ec1e4983e1008201f6a100d90102818258202152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db1258405c8b74a8926ec66661779cff7512c53ef14cc243fb20907a1a62c841f9fdaef6d409301c96944bdbd5f355b077894b773717722e8fd7764a1c5fd1020f56540ff5f6",
"expected": {
"predicate": "GovActionsDoNotExist"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"title": "vote cast on a governance action whose index does not match any proposal",
"description": "A proposal id sharing the seeded proposal's transaction id but naming a different action index.",
"network": "preprod",
"eraHistory": {
"$ref": "common/eraHistory/preprod-conway.json"
},
"protocolParameters": {
"$ref": "common/protocolParameters/preprod-conway-v10.json"
},
"initialState": {
"utxo": [
{
"input": "825820c25d414957cf674b477d9bec7c295a653f02aee955828f9ebec7a4ece7891f2900",
"output": "a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a004c4b40"
}
],
"pools": ["93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8"],
"accounts": [],
"dreps": [],
"committee": [],
"proposals": [
"8258207e2b9d5f1a3c7e5b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b00"
],
"governanceActivity": {
"consecutiveDormantEpochs": 0
}
},
"point": {
"slot": 0,
"transactionIndex": 0
},
"transaction": "84a500d9010281825820c25d414957cf674b477d9bec7c295a653f02aee955828f9ebec7a4ece7891f29000181a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a00493e00021a00030d400f0013a18204581c93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8a18258207e2b9d5f1a3c7e5b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b018201f6a100d90102818258202152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db1258406d6fd3a60b8e7a94ebd0dda9f809aa4adc4c3ea24c4c29b58aae7b7a7c70f0f8543d7c8efb406a5e37ca38d3c340c681aa8e7a7ef5837327d8ecb29d58aba60bf5f6",
"expected": {
"predicate": "GovActionsDoNotExist"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"title": "vote cast by a committee member on a governance action that does not exist",
"description": "An authorized committee hot key naming an absent proposal id.",
"network": "preprod",
"eraHistory": {
"$ref": "common/eraHistory/preprod-conway.json"
},
"protocolParameters": {
"$ref": "common/protocolParameters/preprod-conway-v10.json"
},
"initialState": {
"utxo": [
{
"input": "82582033e3dfb56c093ef6a5e0a85e186f6c4cba64004d1c21d06d868e1168672b9cdc00",
"output": "a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a004c4b40"
}
],
"pools": [],
"accounts": [],
"dreps": [],
"committee": [
{
"coldCredential": "8200581cecc3093b061a9ed426cd9956161fc48d4ed1ac58dc4aaed7e1ce1830",
"hotCredential": "8200581c93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8",
"validUntil": 200
}
],
"proposals": [
"8258207e2b9d5f1a3c7e5b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b00"
],
"governanceActivity": {
"consecutiveDormantEpochs": 0
}
},
"point": {
"slot": 0,
"transactionIndex": 0
},
"transaction": "84a500d901028182582033e3dfb56c093ef6a5e0a85e186f6c4cba64004d1c21d06d868e1168672b9cdc000181a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a00493e00021a00030d400f0013a18200581c93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8a1825820bbd665a051206b767522b19427cced4e0420a050852f7ba1c875c9ec1e4983e1008201f6a100d90102818258202152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db1258407c0b8db38f40877a619d45a2da54831f6d6bec42d67d3fa70b4db8a1dca933eaf07e1adf533e05e439c404f15d57cba594cc6bc2155bfc7552d79526896e3002f5f6",
"expected": {
"predicate": "GovActionsDoNotExist"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"title": "vote cast on two governance actions of which only one exists",
"description": "A single voter casting one ballot on the seeded proposal and one on an absent id.",
"network": "preprod",
"eraHistory": {
"$ref": "common/eraHistory/preprod-conway.json"
},
"protocolParameters": {
"$ref": "common/protocolParameters/preprod-conway-v10.json"
},
"initialState": {
"utxo": [
{
"input": "8258202b648a1f906db52cc04eac0a58116b1ed17c7bacab29a2f592d325b12281cafc00",
"output": "a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a004c4b40"
}
],
"pools": [],
"accounts": [],
"dreps": [
{
"credential": "8200581c93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8",
"deposit": 500000000,
"registeredAt": {
"transaction": {
"slot": 0,
"transactionIndex": 0
},
"certificateIndex": 0
},
"validUntil": 1000
}
],
"committee": [],
"proposals": [
"8258207e2b9d5f1a3c7e5b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b00"
],
"governanceActivity": {
"consecutiveDormantEpochs": 0
}
},
"point": {
"slot": 0,
"transactionIndex": 0
},
"transaction": "84a500d90102818258202b648a1f906db52cc04eac0a58116b1ed17c7bacab29a2f592d325b12281cafc000181a200581d6093c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8011a00493e00021a00030d400f0013a18202581c93c191b1094746961f6f00fba27f3d8eff6a66490baf806d4e179fd8a28258207e2b9d5f1a3c7e5b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b008201f6825820bbd665a051206b767522b19427cced4e0420a050852f7ba1c875c9ec1e4983e1008201f6a100d90102818258202152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db125840f608a4bbfed1cf60d841586def7f826ba2d65241612d4b5e0512a1285024aae057abf43a3e38db8e57cbe23fe3b95f09a6633030139959a72bcda8f2122c5e0df5f6",
"expected": {
"predicate": "GovActionsDoNotExist"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
# PassEpoch event that this harness skips, so the empty prev-gov-action-id can't be rejected here.
"conway/fail-gov-empty-prevgovid-after-the-first-constitution-was-enacted/0" = "Expected failure, got success"
"conway/fail-gov-expired-gov-actions/0" = "Expected failure, got success"
"conway/fail-gov-non-existent-gov-actions/0" = "Expected failure, got success"
"conway/fail-gov-policy-is-respected-by-proposals/0" = "Expected failure, got success"
"conway/fail-govcert-resigning-a-non-cc-key/0" = "Expected failure, got success"
"conway/fail-utxos-alwaysfails-plutus-govpolicy-does-not-validate/0" = "Expected failure, got success"
Expand Down
Loading