Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
76f2922
Implement vertical slice of txs endpoint
Oct 24, 2025
b3d7548
Merge remote-tracking branch 'origin/main' into ajw/164-tx-blockfrost…
Oct 24, 2025
55a58b5
Merge branch 'main' into ajw/164-tx-blockfrost-api
Oct 29, 2025
9437176
Start fleshing out transaction info
Oct 29, 2025
b747f56
Fill in more of transaction info
Oct 31, 2025
5570ab2
Merge remote-tracking branch 'origin/main' into ajw/164-tx-blockfrost…
Nov 5, 2025
47dd9a4
Add deposit to transaction info
Nov 5, 2025
22c3193
Stub out handler switching for all txs endpoints
Nov 7, 2025
505112a
Merge remote-tracking branch 'origin/main' into ajw/164-tx-blockfrost…
Nov 7, 2025
c6850cf
Implement txs stakes endpoint
Nov 7, 2025
1155ba0
Implement txs delegations endpoint
Nov 7, 2025
c0b1c19
Implement txs withdrawals endpoint
Nov 7, 2025
0e97044
Merge remote-tracking branch 'origin/main' into ajw/164-tx-blockfrost…
Nov 12, 2025
129199e
Add txs mirs endpoint
Nov 12, 2025
95eeeae
WIP on txs pool_updates endpoint
Nov 12, 2025
4f1077d
Merge remote-tracking branch 'origin/main' into ajw/164-tx-blockfrost…
Nov 14, 2025
8ee8882
Implement txs pool_updates endpoint
Nov 14, 2025
6408af2
Add active epoch to txs pool_updates
Nov 14, 2025
b646955
Implement txs pool_retires endpoint
Nov 14, 2025
9324b64
WIP txs metadata endpoint
Nov 14, 2025
9892303
Add serialization for metadata in txs metadata endpoint
Nov 19, 2025
0869876
Merge remote-tracking branch 'origin/main' into ajw/164-tx-blockfrost…
Nov 19, 2025
49c7782
Code tidy ups
Nov 19, 2025
3a9d651
Field naming, order and omission corrections
Nov 21, 2025
2ef1970
Correct struct entry counts for TxRelay
Nov 21, 2025
140f31e
Move specialised serialisation of TransactionOutputAmount to rest_blo…
Nov 21, 2025
fe50c73
Merge remote-tracking branch 'origin/main' into ajw/164-tx-blockfrost…
Nov 21, 2025
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
41 changes: 15 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[workspace]
members = [
# Global message and common definitions
"cardano",
"codec",
"common",

Expand Down Expand Up @@ -51,6 +52,7 @@ config = "0.15.11"
dashmap = "6.1.0"
hex = "0.4"
imbl = { version = "5.0.0", features = ["serde"] }
minicbor = { version = "0.25.1", features = ["alloc", "std", "derive"] }
opentelemetry = { version = "0.30.0", features = ["trace"] }
opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic", "trace", "tls"] }
opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] }
Expand Down
8 changes: 8 additions & 0 deletions cardano/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "acropolis_cardano"
version = "0.1.0"
edition = "2024"

[dependencies]
acropolis_common = { version = "0.3.0", path = "../common" }
anyhow.workspace = true
1 change: 1 addition & 0 deletions cardano/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod transaction;
31 changes: 31 additions & 0 deletions cardano/src/transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use acropolis_common::{Lovelace, protocol_params::ProtocolParams};
use anyhow::{Error, anyhow};

pub fn calculate_transaction_fee(
recorded_fee: &Option<Lovelace>,
inputs: &[Lovelace],
outputs: &[Lovelace],
) -> Lovelace {
match recorded_fee {
Some(fee) => *fee,
None => inputs.iter().sum::<Lovelace>() - outputs.iter().sum::<Lovelace>(),
}
}

pub fn calculate_deposit(
pool_update_count: u64,
stake_cert_count: u64,
params: &ProtocolParams,
) -> Result<Lovelace, Error> {
match &params.shelley {
Some(shelley) => Ok(stake_cert_count * shelley.protocol_params.key_deposit
+ pool_update_count * shelley.protocol_params.pool_deposit),
None => {
if pool_update_count > 0 || stake_cert_count > 0 {
Err(anyhow!("No Shelley params, but deposits present"))
} else {
Ok(0)
}
}
}
}
159 changes: 96 additions & 63 deletions codec/src/map_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use acropolis_common::{
*,
};
use pallas_primitives::conway::PseudoScript;
use std::collections::{HashMap, HashSet};
use std::{
collections::{HashMap, HashSet},
net::{Ipv4Addr, Ipv6Addr},
};

/// Map Pallas Network to our NetworkId
pub fn map_network(network: addresses::Network) -> Result<NetworkId> {
Expand Down Expand Up @@ -204,19 +207,19 @@ fn map_constitution(constitution: &conway::Constitution) -> Constitution {
}

/// Map a Pallas Relay to ours
fn map_relay(relay: &PallasRelay) -> Relay {
pub fn map_relay(relay: &PallasRelay) -> Relay {
match relay {
PallasRelay::SingleHostAddr(port, ipv4, ipv6) => Relay::SingleHostAddr(SingleHostAddr {
port: match port {
Nullable::Some(port) => Some(*port as u16),
_ => None,
},
ipv4: match ipv4 {
Nullable::Some(ipv4) => ipv4.try_into().ok(),
Nullable::Some(ipv4) => <[u8; 4]>::try_from(ipv4).ok().map(Ipv4Addr::from),
_ => None,
},
ipv6: match ipv6 {
Nullable::Some(ipv6) => ipv6.try_into().ok(),
Nullable::Some(ipv6) => <[u8; 16]>::try_from(ipv6).ok().map(Ipv6Addr::from),
_ => None,
},
}),
Expand All @@ -236,6 +239,53 @@ fn map_relay(relay: &PallasRelay) -> Relay {
//
// Certificates
//
#[allow(clippy::too_many_arguments)]
pub fn to_pool_reg(
operator: &pallas_primitives::PoolKeyhash,
vrf_keyhash: &pallas_primitives::VrfKeyhash,
pledge: &pallas_primitives::Coin,
cost: &pallas_primitives::Coin,
margin: &pallas_primitives::UnitInterval,
reward_account: &pallas_primitives::RewardAccount,
pool_owners: &[pallas_primitives::AddrKeyhash],
relays: &[pallas_primitives::Relay],
pool_metadata: &Nullable<pallas_primitives::PoolMetadata>,
network_id: NetworkId,
force_reward_network_id: bool,
) -> Result<PoolRegistration> {
Ok(PoolRegistration {
operator: to_pool_id(operator),
vrf_key_hash: to_vrf_key(vrf_keyhash),
pledge: *pledge,
cost: *cost,
margin: Ratio {
numerator: margin.numerator,
denominator: margin.denominator,
},
reward_account: if force_reward_network_id {
StakeAddress::new(
StakeAddress::from_binary(reward_account)?.credential,
network_id.clone(),
)
} else {
StakeAddress::from_binary(reward_account)?
},
pool_owners: pool_owners
.iter()
.map(|v| {
StakeAddress::new(StakeCredential::AddrKeyHash(to_hash(v)), network_id.clone())
})
.collect(),
relays: relays.iter().map(map_relay).collect(),
pool_metadata: match pool_metadata {
Nullable::Some(md) => Some(PoolMetadata {
url: md.url.clone(),
hash: md.hash.to_vec(),
}),
_ => None,
},
})
}

/// Derive our TxCertificate from a Pallas Certificate
pub fn map_certificate(
Expand Down Expand Up @@ -277,34 +327,19 @@ pub fn map_certificate(
relays,
pool_metadata,
} => Ok(TxCertificateWithPos {
cert: TxCertificate::PoolRegistration(PoolRegistration {
operator: to_pool_id(operator),
vrf_key_hash: to_vrf_key(vrf_keyhash),
pledge: *pledge,
cost: *cost,
margin: Ratio {
numerator: margin.numerator,
denominator: margin.denominator,
},
reward_account: StakeAddress::from_binary(reward_account)?,
pool_owners: pool_owners
.iter()
.map(|v| {
StakeAddress::new(
StakeCredential::AddrKeyHash(to_hash(v)),
network_id.clone(),
)
})
.collect(),
relays: relays.iter().map(map_relay).collect(),
pool_metadata: match pool_metadata {
Nullable::Some(md) => Some(PoolMetadata {
url: md.url.clone(),
hash: md.hash.to_vec(),
}),
_ => None,
},
}),
cert: TxCertificate::PoolRegistration(to_pool_reg(
operator,
vrf_keyhash,
pledge,
cost,
margin,
reward_account,
pool_owners,
relays,
pool_metadata,
network_id,
false,
)?),
tx_identifier,
cert_index: cert_index as u64,
}),
Expand Down Expand Up @@ -397,41 +432,23 @@ pub fn map_certificate(
relays,
pool_metadata,
} => Ok(TxCertificateWithPos {
cert: TxCertificate::PoolRegistration(PoolRegistration {
operator: to_pool_id(operator),
vrf_key_hash: to_vrf_key(vrf_keyhash),
pledge: *pledge,
cost: *cost,
margin: Ratio {
numerator: margin.numerator,
denominator: margin.denominator,
},
cert: TxCertificate::PoolRegistration(to_pool_reg(
operator,
vrf_keyhash,
pledge,
cost,
margin,
reward_account,
pool_owners,
relays,
pool_metadata,
network_id,
// Force networkId - in mainnet epoch 208, one SPO (c63dab6d780a) uses
// an e0 (testnet!) address, and this then fails to match their actual
// reward account (e1). Feels like this should have been
// a validation failure, but clearly wasn't!
reward_account: StakeAddress::new(
StakeAddress::from_binary(reward_account)?.credential,
network_id.clone(),
),
pool_owners: pool_owners
.into_iter()
.map(|v| {
StakeAddress::new(
StakeCredential::AddrKeyHash(to_hash(v)),
network_id.clone(),
)
})
.collect(),
relays: relays.iter().map(map_relay).collect(),
pool_metadata: match pool_metadata {
Nullable::Some(md) => Some(PoolMetadata {
url: md.url.clone(),
hash: md.hash.to_vec(),
}),
_ => None,
},
}),
true,
)?),
tx_identifier,
cert_index: cert_index as u64,
}),
Expand Down Expand Up @@ -1119,3 +1136,19 @@ pub fn map_reference_script(script: &Option<conway::MintedScriptRef>) -> Option<
None => None,
}
}

pub fn map_metadata(metadata: &pallas_primitives::Metadatum) -> Metadata {
match metadata {
pallas_primitives::Metadatum::Int(pallas_primitives::Int(i)) => {
Metadata::Int(MetadataInt(*i))
}
pallas_primitives::Metadatum::Bytes(b) => Metadata::Bytes(b.to_vec()),
pallas_primitives::Metadatum::Text(s) => Metadata::Text(s.clone()),
pallas_primitives::Metadatum::Array(a) => {
Metadata::Array(a.iter().map(map_metadata).collect())
}
pallas_primitives::Metadatum::Map(m) => {
Metadata::Map(m.iter().map(|(k, v)| (map_metadata(k), map_metadata(v))).collect())
}
}
}
2 changes: 1 addition & 1 deletion common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ tempfile = "3"
tokio = { workspace = true }
tracing = { workspace = true }
futures = "0.3.31"
minicbor = { version = "0.26.0", features = ["std", "half", "derive"] }
minicbor = { workspace = true, features = ["std", "half", "derive"] }
num-traits = "0.2"
dashmap = { workspace = true }
rayon = "1.11.0"
Expand Down
2 changes: 2 additions & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod hash;
pub mod ledger_state;
pub mod math;
pub mod messages;
pub mod metadata;
pub mod params;
pub mod protocol_params;
pub mod queries;
Expand All @@ -28,4 +29,5 @@ pub mod validation;

// Flattened re-exports
pub use self::address::*;
pub use self::metadata::*;
pub use self::types::*;
Loading