Skip to content
Merged
13 changes: 2 additions & 11 deletions Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,14 @@ generate-keys:
SAVE ARTIFACT --if-exists secrets/keys-aws.json AS LOCAL secrets/$NETWORK-keys-aws.json

subxt:
FROM public.ecr.aws/amazonlinux/amazonlinux:2023-minimal@sha256:13bffb7de7ef4836742a6be2b09642e819aaec50ceed1d7961424e19a95da0de

# Install curl for rust installation
RUN microdnf -y install curl-minimal ca-certificates gcc gcc-c++ make jq docker && \
microdnf clean all && rm -rf /var/cache/dnf /var/cache/yum

# Install rust with complete profile for profiler runtime support
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.93 --profile complete
ENV PATH="/root/.cargo/bin:${PATH}"

FROM rust:1.92-trixie
RUN rustup component add rustfmt
# Install cargo binstall:
# RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
# RUN cargo install cargo-binstall --version 1.6.9
COPY Cargo.toml deps.toml
LET SUBXT_VERSION = "$(cat deps.toml | grep -m 1 subxt | sed 's/subxt *= *"\([^\"]*\)".*/\1/')"
RUN cargo install subxt-cli@${SUBXT_VERSION}
RUN cp /root/.cargo/bin/subxt /usr/local/bin/subxt
ENTRYPOINT ["subxt"]
SAVE IMAGE localhost/subxt

Expand Down Expand Up @@ -824,6 +814,7 @@ check-metadata:
ARG NODE_IMAGE
#=ghcr.io/midnight-ntwrk/midnight-node:latest
FROM +subxt
DO github.com/EarthBuild/lib+INSTALL_DIND
COPY local-environment/check-health.sh /usr/local/bin/check-health.sh

WITH DOCKER --pull ${NODE_IMAGE}
Expand Down
10 changes: 10 additions & 0 deletions changes/changed/remove-explicit-redemption-contract-tracking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#cnight-observation
# Remove explicit redemption contract tracking from cnight-observation

Redemption UTxOs already have the correct stake credentials in their address, so the dedicated redemption queries (which decode datums) are unnecessary. The standard asset_create/asset_spend queries catch redemption UTxOs via their cNIGHT policy ID.

Analysing the mainnet data as of 30/01/2025, all of the redemption utxos where the user address has a stake part (>98% of all redemption utxos) also has a stake part == user's stake on the utxo itself.

This property is guaranteed by all redemption contracts generated by the Redemption supply contract.

PR: https://github.com/midnightntwrk/midnight-node/pull/576
Binary file modified metadata/static/midnight_metadata.scale
Binary file not shown.
Binary file modified metadata/static/midnight_metadata_0.20.0.scale
Binary file not shown.
2 changes: 0 additions & 2 deletions pallets/cnight-observation/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ mod tests {
let my_json = r#"{
"addresses": {
"mapping_validator_address": "addr_test1wplxjzranravtp574s2wz00md7vz9rzpucu252je68u9a8qzjheng",
"redemption_validator_address": "addr_test1wz3t0v4r0kwdfnh44m87z4rasp4nj0rcplfpmwxvhhrzhdgl45vx4",
"auth_token_asset_name": "",
"cnight_policy_id": "d2dbff622e509dda256fedbd31ef6e9fd98ed49ad91d5c0e07f68af1",
"cnight_asset_name": ""
Expand Down Expand Up @@ -183,7 +182,6 @@ mod tests {
let my_json = r#"{
"addresses": {
"mapping_validator_address": "nonsense",
"redemption_validator_address": "addr_test1wz3t0v4r0kwdfnh44m87z4rasp4nj0rcplfpmwxvhhrzhdgl45vx4",
"auth_token_asset_name": "",
"cnight_policy_id": "d2dbff622e509dda256fedbd31ef6e9fd98ed49ad91d5c0e07f68af1",
"cnight_asset_name": ""
Expand Down
105 changes: 1 addition & 104 deletions pallets/cnight-observation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub mod pallet {
};
use midnight_primitives_mainchain_follower::{
CreateData, DeregistrationData, ObservedUtxo, ObservedUtxoData, ObservedUtxoHeader,
RedemptionCreateData, RedemptionSpendData, RegistrationData, SpendData,
RegistrationData, SpendData,
};
use scale_info::prelude::vec::Vec;
use sidechain_domain::McTxHash;
Expand Down Expand Up @@ -168,11 +168,6 @@ pub mod pallet {
pub type MainChainAuthTokenAssetName<T: Config> =
StorageValue<_, BoundedVec<u8, ConstU32<32>>, ValueQuery>;

#[pallet::storage]
// Script address for executing Glacier Drop redemptions on Cardano
pub type MainChainRedemptionValidatorAddress<T: Config> =
StorageValue<_, BoundedCardanoAddress, ValueQuery>;

#[pallet::storage]
pub type Mappings<T: Config> =
StorageMap<_, Blake2_128Concat, CardanoRewardAddressBytes, Vec<MappingEntry>, ValueQuery>;
Expand Down Expand Up @@ -238,16 +233,6 @@ pub mod pallet {
.expect("Mapping Validator address longer than expected"),
);

MainChainRedemptionValidatorAddress::<T>::set(
self.config
.addresses
.redemption_validator_address
.as_bytes()
.to_vec()
.try_into()
.expect("Redemption Validator address longer than expected"),
);

CNightIdentifier::<T>::set((
self.config
.addresses
Expand Down Expand Up @@ -504,82 +489,6 @@ pub mod pallet {
},
}
}

fn handle_redemption_create(
cur_time: u64,
data: RedemptionCreateData,
) -> Option<CNightGeneratesDustEventSerialized> {
let Some(ref dust_public_key) = Self::get_registration(&data.owner) else {
log::warn!("No valid dust registration for {:?}", &data.owner);
return None;
};

let nonce = T::Hashing::hash(
&[
b"redemption_create",
&data.utxo_tx_hash.0[..],
&data.utxo_tx_index.to_be_bytes()[..],
]
.concat(),
);

UtxoOwners::<T>::insert(nonce, dust_public_key.clone());

let event = LedgerApi::construct_cnight_generates_dust_event(
data.value,
&dust_public_key.0,
cur_time,
UtxoActionType::Create as u8,
nonce.0,
);

match event {
Ok(event_bytes) => Some(CNightGeneratesDustEventSerialized(event_bytes)),
Err(e) => {
log::error!("Fatal: Unable to construct CNightGeneratesDustEvent: {e:?}");
None
},
}
}

fn handle_redemption_spend(
cur_time: u64,
data: RedemptionSpendData,
) -> Option<CNightGeneratesDustEventSerialized> {
let nonce = T::Hashing::hash(
&[
b"redemption_create",
&data.utxo_tx_hash.0[..],
&data.utxo_tx_index.to_be_bytes()[..],
]
.concat(),
);

let Some(ref dust_public_key) = UtxoOwners::<T>::get(nonce) else {
log::warn!(
"No create event for UTXO: {}#{}",
hex::encode(data.utxo_tx_hash.0),
data.utxo_tx_index
);
return None;
};

let event = LedgerApi::construct_cnight_generates_dust_event(
data.value,
&dust_public_key.0,
cur_time,
UtxoActionType::Destroy as u8,
nonce.0,
);

match event {
Ok(event_bytes) => Some(CNightGeneratesDustEventSerialized(event_bytes)),
Err(e) => {
log::error!("Fatal: Unable to construct CNightGeneratesDustEvent: {e:?}");
None
},
}
}
}

#[pallet::call]
Expand All @@ -606,18 +515,6 @@ pub mod pallet {
let now = utxo.header.tx_position.block_timestamp.0 as u64 / 1000;

match utxo.data {
ObservedUtxoData::RedemptionCreate(data) => {
log::debug!("Processing Redemption Create: {data:?}");
if let Some(event) = Self::handle_redemption_create(now, data) {
events.push(event);
}
},
ObservedUtxoData::RedemptionSpend(data) => {
log::debug!("Processing Redemption Spend: {data:?}");
if let Some(event) = Self::handle_redemption_spend(now, data) {
events.push(event);
}
},
ObservedUtxoData::Registration(data) => {
log::debug!("Processing Registration: {data:?}");
Self::handle_registration(&utxo.header, data);
Expand Down
128 changes: 1 addition & 127 deletions pallets/cnight-observation/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use midnight_primitives_cnight_observation::{
};
use midnight_primitives_mainchain_follower::{
CreateData, DeregistrationData, ObservedUtxo, ObservedUtxoData, ObservedUtxoHeader,
RedemptionCreateData, RedemptionSpendData, RegistrationData, SpendData, UtxoIndexInTx,
RegistrationData, SpendData, UtxoIndexInTx,
};
use pallet_cnight_observation::*;
use pallet_cnight_observation_mock::mock::{
Expand Down Expand Up @@ -273,132 +273,6 @@ fn asset_destroy_should_emit_valid_event_if_registered() {
});
}

#[test]
fn redemption_create_should_emit_valid_event_if_registered() {
new_test_ext().execute_with(|| {
init_ledger_state();
let (cardano_reward_address, dust_public_key) = test_wallet_pairing();

let utxos = vec![
ObservedUtxo {
header: test_header(1, 2, 0, None),
data: ObservedUtxoData::Registration(RegistrationData {
cardano_reward_address,
dust_public_key: dust_public_key.clone(),
}),
},
ObservedUtxo {
header: test_header(2, 0, 0, None),
data: ObservedUtxoData::RedemptionCreate(RedemptionCreateData {
value: 100,
owner: cardano_reward_address,
utxo_tx_hash: tx_hash(1, 3),
utxo_tx_index: 0,
}),
},
];

let inherent_data = create_inherent(utxos, test_position(3, 0));
let call = CNightObservation::create_inherent(&inherent_data)
.expect("Expected to create inherent call");
let call = RuntimeCall::CNightObservation(call);
assert_ok!(call.dispatch(frame_system::RawOrigin::None.into()));

// Confirm the expected SystemTxCreateUtxo event was emitted
let found = frame_system::Pallet::<Test>::events().iter().any(|record| {
println!("found event: {record:?}");
if let mock::RuntimeEvent::MidnightSystem(
pallet_midnight_system::Event::SystemTransactionApplied(e),
) = &record.event
{
println!("system tx detected: {e:?}");
println!("looking for owner: {:?}", &dust_public_key);
let dust_public_key_deser: DustPublicKey =
deserialize_untagged(&mut &dust_public_key.0[..]).unwrap();
let events = extract_events(&e.serialized_system_transaction);
for event in events.iter() {
if event.action == CNightGeneratesDustActionType::Create
&& event.owner == dust_public_key_deser
{
return true;
}
}
}
false
});

assert!(found, "Could not find SystemTx event with correct owner");
});
}

#[test]
fn redemption_destroy_should_emit_valid_event_if_registered() {
new_test_ext().execute_with(|| {
init_ledger_state();
let (cardano_reward_address, dust_public_key) = test_wallet_pairing();

let utxos = vec![
ObservedUtxo {
header: test_header(1, 2, 0, None),
data: ObservedUtxoData::Registration(RegistrationData {
cardano_reward_address,
dust_public_key: dust_public_key.clone(),
}),
},
ObservedUtxo {
header: test_header(2, 0, 0, None),
data: ObservedUtxoData::RedemptionCreate(RedemptionCreateData {
value: 100,
owner: cardano_reward_address,
utxo_tx_hash: tx_hash(2, 0),
utxo_tx_index: 0,
}),
},
ObservedUtxo {
header: test_header(2, 1, 0, None),
data: ObservedUtxoData::RedemptionSpend(RedemptionSpendData {
value: 100,
owner: cardano_reward_address,
utxo_tx_hash: tx_hash(2, 0),
utxo_tx_index: 0,
spending_tx_hash: tx_hash(2, 1),
}),
},
];

let inherent_data = create_inherent(utxos, test_position(3, 0));
let call = CNightObservation::create_inherent(&inherent_data)
.expect("Expected to create inherent call");
let call = RuntimeCall::CNightObservation(call);
assert_ok!(call.dispatch(frame_system::RawOrigin::None.into()));

// Confirm the expected SystemTxCreateUtxo event was emitted
let found = frame_system::Pallet::<Test>::events().iter().any(|record| {
println!("found event: {record:?}");
if let mock::RuntimeEvent::MidnightSystem(
pallet_midnight_system::Event::SystemTransactionApplied(e),
) = &record.event
{
println!("system tx detected: {e:?}");
println!("looking for owner: {:?}", &dust_public_key);
let dust_public_key_deser: DustPublicKey =
deserialize_untagged(&mut &dust_public_key.0[..]).unwrap();
let events = extract_events(&e.serialized_system_transaction);
for event in events.iter() {
if event.action == CNightGeneratesDustActionType::Destroy
&& event.owner == dust_public_key_deser
{
return true;
}
}
}
false
});

assert!(found, "Could not find SystemTx event with correct owner");
});
}

#[test]
fn process_tokens_should_not_emit_valid_utxo_event_if_not_registered() {
new_test_ext().execute_with(|| {
Expand Down
Loading
Loading