Skip to content

Conversation

@alexwoods
Copy link
Collaborator

@alexwoods alexwoods commented Nov 19, 2025

Description

This PR adds some of the txs endpoints to the REST Blockfrost module.

Related Issue(s)

Relates to #137, #164.

How was this tested?

Manual comparison against dbsync (mainnet) :-(
Example requests that should work on mainnet:

  • info: /txs/95763c53b485088608edfc95a0ef3d512cf5c7727f09e046d80eda0ed437cbe8 (note: utxo info not present - requires historic utxo lookup by hash)
  • stakes: /txs/3485af236ba4776a95cefe5d6b4400dff6129c5753521e3774a950766c3c8359/stakes
  • delegations: /txs/3485af236ba4776a95cefe5d6b4400dff6129c5753521e3774a950766c3c8359/delegations
  • withdrawals: /txs/9efef43f1d8ae696877c29be676055adfcc116510e57439c8a841eb991aa3886/withdrawals
  • mirs: /txs/35d2728ea6ad89bf809565c9ed698bb1c5cddf83591ba2e8bba951cb8fee0035/mirs
  • pool updates: /txs/841cca81da918feb9fa7257a34630eac95794be712ed3faae6df64f215ce25f2/pool_updates
  • pool retirements: /txs/896cf8fefad1eaf0fa056ba3adf28bfb26b06d1beed64cf790deb595dcb2687a/pool_retires
  • metadata: /c220e20cc480df9ce7cd871df491d7390c6a004b9252cf20f45fc3c968535b4a/metadata

Checklist

  • My code builds and passes local tests
  • I added/updated tests for my changes, where applicable
  • I updated documentation (if applicable)
  • CI is green for this PR

Impact / Side effects

There shouldn't be any side-effects.

Reviewer notes / Areas to focus

I've made custom serialisers within the blockfrost code. I'm unsure if there's a nicer way to do what I was trying to do, which was to keep serialisation out of the common library because in many cases this serialisation is quite peculiar to blockfrost and should not be a default.

@alexwoods alexwoods requested review from SupernaviX, sandtreader and whankinsiv and removed request for whankinsiv November 19, 2025 18:39
Copy link
Collaborator

@whankinsiv whankinsiv left a comment

Choose a reason for hiding this comment

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

Looks great! Just a few fields whose names don't align with the BF schema.

Comment on lines 50 to 56
#[derive(Debug, Clone, serde::Deserialize)]
pub enum TransactionOutputAmount {
Lovelace(Lovelace),
Asset(NativeAsset),
}

impl Serialize for TransactionOutputAmount {
Copy link
Collaborator

Choose a reason for hiding this comment

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

If a type implements both Serialize and Deserialize, they should match; otherwise the data can't round-trip. Would be better to either

  • have a different struct specifically in rest_blockfrost which deserializes correctly
  • make TransactionOutputAmount into a struct with unit and amount fields, so (de)serialization works right
  • not implement Deserialize here (and we make caryatid not depend on it [obvs lots of extra work there])

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm going for a 4th option, which is to apply the standard Serialize derive in common, and move the special serialization into rest_blockfrost. This is one of the cases where the serialization for blockfrost is kind of unusual due to the numerics being serialized to strings. It makes some sense for JSON, but for CBOR it's not good. I think we would benefit from picking a default serialization target for common structs, and I think it should probably be CBOR. Shout if you think this is the wrong approach

Copy link
Collaborator

@lowhung lowhung Nov 20, 2025

Choose a reason for hiding this comment

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

I should probably refactor these to return Result<N> at some point 😓

@alexwoods
Copy link
Collaborator Author

Looks great! Just a few fields whose names don't align with the BF schema.

@whankinsiv Do you have a tool for checking these?

Copy link
Collaborator

@sandtreader sandtreader left a comment

Choose a reason for hiding this comment

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

Massive piece of work, good job!

Only queries are about possible missing Conway certs where you can register and delegate at the same time, and whether counting PoolRegistrations is enough for deposits.

stake_cert_count += 1;
}
conway::Certificate::StakeDelegation { .. } => delegation_count += 1,
_ => (),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think there are a bunch of other Conway cert types that need to be counted here - Reg/UnReg/StakeRegDeleg etc.

registration: false,
});
}
_ => (),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also here, there are combined register and delegate certs like StakeRegDeleg, VoteRegDeleg, StakeVoteRegDeleg (see handling in map_parameters.rs)

});
}
}
_ => (),
Copy link
Collaborator

Choose a reason for hiding this comment

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

... and here...

network_id.clone(),
false,
)?,
active_epoch: tx.block.extra.epoch + 1,
Copy link
Collaborator

Choose a reason for hiding this comment

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

If valid (I assume it is!) needs a comment as to why incremented


match param {
None => handle_transaction_query(context, tx_hash, handlers_config).await,
Some("utxo") => Ok(RESTResponse::with_text(501, "Not implemented")),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a ticket to do this?

}
}

/// Handle `/txs/{hash}`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually /txs/{hash}[/param][/param2]] I think? (to differentiate from the next fn)

}
Some("metadata") => match param2 {
None => handle_transaction_metadata_query(context, tx_hash, handlers_config).await,
Some("cbor") => Ok(RESTResponse::with_text(501, "Not implemented")),
Copy link
Collaborator

Choose a reason for hiding this comment

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

TODO or ticket

// TODO: calc from outputs and inputs if recorded_fee is None
let fee = txs_info.recorded_fee.unwrap_or_default();
let deposit = match calculate_deposit(
txs_info.pool_update_count,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Worried about this - check if deposit is paid for subsequent updates of the same pool reg.

Copy link
Collaborator

Choose a reason for hiding this comment

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

(I have no idea what to do if it isn't, since it requires SPO state)

Err(e) => return Some(Err(e)),
};
// TODO: calc from outputs and inputs if recorded_fee is None
let fee = txs_info.recorded_fee.unwrap_or_default();
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is code to do this in common/transactions I think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants