Skip to content
Merged
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
7 changes: 6 additions & 1 deletion crates/cardano/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::{
StakeRegistration, VoteDelegation, WithdrawalInc,
},
assets::MintStatsUpdate,
dreps::{DRepRegistration, DRepUnRegistration},
dreps::{DRepActivity, DRepRegistration, DRepUnRegistration},
epochs::{EpochStatsUpdate, NoncesUpdate, PParamsUpdate},
pools::{MintedBlocksInc, PoolRegistration},
},
Expand Down Expand Up @@ -958,6 +958,7 @@ pub enum CardanoDelta {
EpochStatsUpdate(EpochStatsUpdate),
DRepRegistration(DRepRegistration),
DRepUnRegistration(DRepUnRegistration),
DRepActivity(DRepActivity),
WithdrawalInc(WithdrawalInc),
VoteDelegation(VoteDelegation),
PParamsUpdate(PParamsUpdate),
Expand Down Expand Up @@ -1009,6 +1010,7 @@ delta_from!(MintStatsUpdate);
delta_from!(EpochStatsUpdate);
delta_from!(DRepRegistration);
delta_from!(DRepUnRegistration);
delta_from!(DRepActivity);
delta_from!(WithdrawalInc);
delta_from!(VoteDelegation);
delta_from!(PParamsUpdate);
Expand All @@ -1029,6 +1031,7 @@ impl dolos_core::EntityDelta for CardanoDelta {
Self::MintStatsUpdate(x) => x.key(),
Self::EpochStatsUpdate(x) => x.key(),
Self::DRepRegistration(x) => x.key(),
Self::DRepActivity(x) => x.key(),
Self::DRepUnRegistration(x) => x.key(),
Self::WithdrawalInc(x) => x.key(),
Self::VoteDelegation(x) => x.key(),
Expand All @@ -1050,6 +1053,7 @@ impl dolos_core::EntityDelta for CardanoDelta {
Self::EpochStatsUpdate(x) => Self::downcast_apply(x, entity),
Self::DRepRegistration(x) => Self::downcast_apply(x, entity),
Self::DRepUnRegistration(x) => Self::downcast_apply(x, entity),
Self::DRepActivity(x) => Self::downcast_apply(x, entity),
Self::WithdrawalInc(x) => Self::downcast_apply(x, entity),
Self::VoteDelegation(x) => Self::downcast_apply(x, entity),
Self::PParamsUpdate(x) => Self::downcast_apply(x, entity),
Expand All @@ -1070,6 +1074,7 @@ impl dolos_core::EntityDelta for CardanoDelta {
Self::EpochStatsUpdate(x) => Self::downcast_undo(x, entity),
Self::DRepRegistration(x) => Self::downcast_undo(x, entity),
Self::DRepUnRegistration(x) => Self::downcast_undo(x, entity),
Self::DRepActivity(x) => Self::downcast_undo(x, entity),
Self::WithdrawalInc(x) => Self::downcast_undo(x, entity),
Self::VoteDelegation(x) => Self::downcast_undo(x, entity),
Self::PParamsUpdate(x) => Self::downcast_undo(x, entity),
Expand Down
178 changes: 105 additions & 73 deletions crates/cardano/src/roll/dreps.rs
Original file line number Diff line number Diff line change
@@ -1,58 +1,55 @@
use std::ops::Deref as _;

use dolos_core::{batch::WorkDeltas, ChainError, NsKey};
use pallas::{
codec::minicbor,
ledger::{
primitives::{
conway::{self, Anchor},
StakeCredential,
},
traverse::{MultiEraBlock, MultiEraCert, MultiEraTx},
use pallas::ledger::{
primitives::{
conway::{self, Anchor},
StakeCredential,
},
traverse::{MultiEraBlock, MultiEraCert, MultiEraTx},
};
use serde::{Deserialize, Serialize};

use crate::{model::DRepState, roll::BlockVisitor, CardanoLogic, FixedNamespace as _};

//const DREP_KEY_PREFIX: u8 = 0b00100010;
//const DREP_SCRIPT_PREFIX: u8 = 0b00100011;
//
//fn cred_to_id(cred: &StakeCredential) -> Vec<u8> {
// match cred {
// StakeCredential::AddrKeyhash(key) => [vec![DREP_KEY_PREFIX], key.to_vec()].concat(),
// StakeCredential::ScriptHash(key) => [vec![DREP_SCRIPT_PREFIX], key.to_vec()].concat(),
// }
//}
//
//fn drep_to_id(drep: &conway::DRep) -> Vec<u8> {
// match drep {
// conway::DRep::Key(key) => [vec![DREP_KEY_PREFIX], key.to_vec()].concat(),
// conway::DRep::Script(key) => [vec![DREP_SCRIPT_PREFIX], key.to_vec()].concat(),
// // Invented keys for convenience
// conway::DRep::Abstain => vec![0],
// conway::DRep::NoConfidence => vec![1],
// }
//}
//
//fn cert_to_id(cert: &MultiEraCert) -> Option<Vec<u8>> {
// match &cert {
// MultiEraCert::Conway(conway) => match conway.deref().deref() {
// conway::Certificate::RegDRepCert(cert, _, _) => Some(cred_to_id(cert)),
// conway::Certificate::UnRegDRepCert(cert, _) => Some(cred_to_id(cert)),
// conway::Certificate::UpdateDRepCert(cert, _) => Some(cred_to_id(cert)),
// conway::Certificate::StakeVoteDeleg(_, _, drep) => Some(drep_to_id(drep)),
// conway::Certificate::VoteRegDeleg(_, drep, _) => Some(drep_to_id(drep)),
// conway::Certificate::VoteDeleg(_, drep) => Some(drep_to_id(drep)),
// _ => None,
// },
// _ => None,
// }
//}
const DREP_KEY_PREFIX: u8 = 0b00100010;
const DREP_SCRIPT_PREFIX: u8 = 0b00100011;

fn cred_to_id(cred: &StakeCredential) -> Vec<u8> {
match cred {
StakeCredential::AddrKeyhash(key) => [vec![DREP_KEY_PREFIX], key.to_vec()].concat(),
StakeCredential::ScriptHash(key) => [vec![DREP_SCRIPT_PREFIX], key.to_vec()].concat(),
}
}

fn drep_to_id(drep: &conway::DRep) -> Vec<u8> {
match drep {
conway::DRep::Key(key) => [vec![DREP_KEY_PREFIX], key.to_vec()].concat(),
conway::DRep::Script(key) => [vec![DREP_SCRIPT_PREFIX], key.to_vec()].concat(),
// Invented keys for convenience
conway::DRep::Abstain => vec![0],
conway::DRep::NoConfidence => vec![1],
}
}

fn cert_to_id(cert: &MultiEraCert) -> Option<Vec<u8>> {
match &cert {
MultiEraCert::Conway(conway) => match conway.deref().deref() {
conway::Certificate::RegDRepCert(cert, _, _) => Some(cred_to_id(cert)),
conway::Certificate::UnRegDRepCert(cert, _) => Some(cred_to_id(cert)),
conway::Certificate::UpdateDRepCert(cert, _) => Some(cred_to_id(cert)),
conway::Certificate::StakeVoteDeleg(_, _, drep) => Some(drep_to_id(drep)),
conway::Certificate::VoteRegDeleg(_, drep, _) => Some(drep_to_id(drep)),
conway::Certificate::VoteDeleg(_, drep) => Some(drep_to_id(drep)),
_ => None,
},
_ => None,
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DRepRegistration {
cred: StakeCredential,
drep_id: Vec<u8>,
slot: u64,
deposit: u64,
anchor: Option<Anchor>,
Expand All @@ -62,9 +59,9 @@ pub struct DRepRegistration {
}

impl DRepRegistration {
pub fn new(cred: StakeCredential, slot: u64, deposit: u64, anchor: Option<Anchor>) -> Self {
pub fn new(drep_id: Vec<u8>, slot: u64, deposit: u64, anchor: Option<Anchor>) -> Self {
Self {
cred,
drep_id,
slot,
deposit,
anchor,
Expand All @@ -77,8 +74,7 @@ impl dolos_core::EntityDelta for DRepRegistration {
type Entity = DRepState;

fn key(&self) -> NsKey {
let enc = minicbor::to_vec(&self.cred).unwrap();
NsKey::from((DRepState::NS, enc))
NsKey::from((DRepState::NS, self.drep_id.clone()))
}

fn apply(&mut self, entity: &mut Option<DRepState>) {
Expand All @@ -103,19 +99,17 @@ impl dolos_core::EntityDelta for DRepRegistration {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DRepUnRegistration {
cred: StakeCredential,
slot: u64,
drep_id: Vec<u8>,
deposit: u64,

// undo data
prev_voting_power: Option<u64>,
}

impl DRepUnRegistration {
pub fn new(cred: StakeCredential, slot: u64, deposit: u64) -> Self {
pub fn new(drep_id: Vec<u8>, deposit: u64) -> Self {
Self {
cred,
slot,
drep_id,
deposit,
prev_voting_power: None,
}
Expand All @@ -126,8 +120,7 @@ impl dolos_core::EntityDelta for DRepUnRegistration {
type Entity = DRepState;

fn key(&self) -> NsKey {
let enc = minicbor::to_vec(&self.cred).unwrap();
NsKey::from((DRepState::NS, enc))
NsKey::from((DRepState::NS, self.drep_id.clone()))
}

fn apply(&mut self, entity: &mut Option<DRepState>) {
Expand All @@ -148,6 +141,46 @@ impl dolos_core::EntityDelta for DRepUnRegistration {
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DRepActivity {
drep_id: Vec<u8>,
slot: u64,
previous_last_active_slot: Option<u64>,
}

impl DRepActivity {
pub fn new(drep_id: Vec<u8>, slot: u64) -> Self {
Self {
drep_id,
slot,
previous_last_active_slot: None,
}
}
}

impl dolos_core::EntityDelta for DRepActivity {
type Entity = DRepState;

fn key(&self) -> NsKey {
NsKey::from((DRepState::NS, self.drep_id.clone()))
}

fn apply(&mut self, entity: &mut Option<DRepState>) {
let entity = entity.get_or_insert_default();

// save undo info
self.previous_last_active_slot = entity.last_active_slot;

// apply changes
entity.last_active_slot = Some(self.slot);
}
Comment on lines +168 to +176

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

🧩 Analysis chain

Consider initializing drep_id in the entity.

When applying DRepActivity, the entity is created with default values if it doesn't exist. However, the drep_id field in the entity is not being set from the delta's drep_id.


🏁 Script executed:

#!/bin/bash
# Check if drep_id is set elsewhere when creating DRepState
echo "Checking where drep_id is initialized in DRepState..."
ast-grep --pattern 'impl $_ for DRepRegistration {
  $$$
  fn apply($$$) {
    $$$
  }
  $$$
}'

# Check the DRepState structure definition
echo -e "\nChecking DRepState structure..."
rg -A 10 "struct DRepState" --type rust

Length of output: 2922


Initialize entity.drep_id when creating a DRepState

Both DRepRegistration::apply (crates/cardano/src/roll/dreps.rs:76–90) and DRepActivity::apply (crates/cardano/src/roll/dreps.rs:168–176) call entity.get_or_insert_default() but never set entity.drep_id; DRepState defines pub drep_id: Vec in crates/cardano/src/model.rs — set it when inserting the default (e.g. entity.drep_id = self.drep_id.clone()).

🤖 Prompt for AI Agents
In crates/cardano/src/roll/dreps.rs around lines 76–90 and 168–176, both
DRepRegistration::apply and DRepActivity::apply call
entity.get_or_insert_default() but never populate the DRepState.drep_id field;
update each apply to set entity.drep_id = self.drep_id.clone() immediately after
inserting the default (i.e., when get_or_insert_default() returns the newly
inserted state) so the drep_id is initialized correctly on creation.


fn undo(&self, entity: &mut Option<DRepState>) {
let entity = entity.get_or_insert_default();
entity.last_active_slot = self.previous_last_active_slot;
}
}

#[derive(Default, Clone)]
pub struct DRepStateVisitor;

Expand All @@ -159,26 +192,25 @@ impl BlockVisitor for DRepStateVisitor {
_: &MultiEraTx,
cert: &MultiEraCert,
) -> Result<(), ChainError> {
if let MultiEraCert::Conway(conway) = &cert {
match conway.deref().deref() {
conway::Certificate::RegDRepCert(cred, deposit, anchor) => {
deltas.add_for_entity(DRepRegistration::new(
cred.clone(),
block.slot(),
*deposit,
anchor.clone(),
));
if let Some(drep_id) = cert_to_id(cert) {
deltas.add_for_entity(DRepActivity::new(drep_id.clone(), block.slot()));
if let MultiEraCert::Conway(conway) = &cert {
match conway.deref().deref() {
conway::Certificate::RegDRepCert(_, deposit, anchor) => {
deltas.add_for_entity(DRepRegistration::new(
drep_id.clone(),
block.slot(),
*deposit,
anchor.clone(),
));
}
conway::Certificate::UnRegDRepCert(_, coin) => {
deltas.add_for_entity(DRepUnRegistration::new(drep_id.clone(), *coin));
}
_ => (),
}
conway::Certificate::UnRegDRepCert(cred, coin) => {
deltas.add_for_entity(DRepUnRegistration::new(
cred.clone(),
block.slot(),
*coin,
));
}
_ => (),
}
};
};
}

Ok(())
}
Expand Down
Loading