🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

lexe-common

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lexe-common - cargo Package Compare versions

Comparing version
0.1.16
to
0.1.17
+1
-1
.cargo_vcs_info.json
{
"git": {
"sha1": "64d6f049576247f7e48a0ef09d191999b14272b9"
"sha1": "553d66ebde3e8ba9e951f94c11a4075f4351c912"
},
"path_in_vcs": "public/lexe-common"
}

@@ -505,5 +505,5 @@ # This file is automatically @generated by Cargo.

name = "lexe-byte-array"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc728990c344e970e15ef71db3c7ae165b1cb6168d3e772849622e4b9a70f648"
checksum = "fee3d67908f9aa7ac9f07dd3114b51a4bfd09759eb2b4c6bb6df83faab0bb21c"
dependencies = [

@@ -515,3 +515,3 @@ "lexe-hex",

name = "lexe-common"
version = "0.1.16"
version = "0.1.17"
dependencies = [

@@ -564,5 +564,5 @@ "anyhow",

name = "lexe-crypto"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9318ef44606022ff7ca7798a747ad126805ad9054a073e3378aaa5a1d5bcd5ec"
checksum = "4488af261b1481a2fdb7f01fd0e1972990c9739b1012afce6974db977b344114"
dependencies = [

@@ -585,5 +585,5 @@ "bcs",

name = "lexe-enclave"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff757e0c4d9f0ba7f5c635f2ce53c25cf2aee8cd3dab63acb5cc2eecb0bdb46e"
checksum = "a9692fc4a8b45b4811b8404dd59357c8ae442923a96ce660f2a1b30d4b226d05"
dependencies = [

@@ -605,11 +605,11 @@ "cfg-if",

name = "lexe-hex"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c08f90b258615b4ada83e4ed35d596cbe6af69cb35512e78460ac8a11b5d753"
checksum = "4f7211357af2a696cefba7b0860471824eabe310e08eedd361e65b4612feed13"
[[package]]
name = "lexe-serde"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5841cf7e9d34aa855ba6a077886980d3a9971a885afd527dfef6a525de009d8"
checksum = "6e222e3f705327b7aa55c4ed0791c18b42c315d2216ea714ef4a7f56adbb36a7"
dependencies = [

@@ -623,5 +623,5 @@ "base64",

name = "lexe-sha256"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fb14bba432279681424729b4ed9ab153dad35f760bc744a634e7e31287db461"
checksum = "1b8f46023da11d8241a1b6f942f1f3623614cf428e581de6a6d02d24e91c5ea5"
dependencies = [

@@ -636,5 +636,5 @@ "lexe-byte-array",

name = "lexe-std"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77db2d58961be8209cacea384e9c62c56bb447e6c52e36fb79ba017dd3b82763"
checksum = "4f10fc9fbd043dd6170b19ee0a48ff210800c212e458f8d24fe3262c928568cd"
dependencies = [

@@ -641,0 +641,0 @@ "ref-cast",

@@ -16,3 +16,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

name = "lexe-common"
version = "0.1.16"
version = "0.1.17"
authors = [

@@ -105,21 +105,21 @@ "Max Fang <max@lexe.app>",

[dependencies.lexe-byte-array]
version = "0.1.16"
version = "0.1.17"
[dependencies.lexe-crypto]
version = "0.1.16"
version = "0.1.17"
[dependencies.lexe-enclave]
version = "0.1.16"
version = "0.1.17"
[dependencies.lexe-hex]
version = "0.1.16"
version = "0.1.17"
[dependencies.lexe-serde]
version = "0.1.16"
version = "0.1.17"
[dependencies.lexe-sha256]
version = "0.1.16"
version = "0.1.17"
[dependencies.lexe-std]
version = "0.1.16"
version = "0.1.17"
features = ["ref-cast"]

@@ -213,7 +213,7 @@

[dev-dependencies.lexe-crypto]
version = "0.1.16"
version = "0.1.17"
features = ["test-utils"]
[dev-dependencies.lexe-enclave]
version = "0.1.16"
version = "0.1.17"
features = ["test-utils"]

@@ -220,0 +220,0 @@

@@ -14,3 +14,3 @@ // TODO(max): All of these modules should be moved to `lexe_api[_core]`.

pub mod provision;
/// Revocable clients.
/// The revocable clients interface for handshake-time revocation checks.
pub mod revocable_clients;

@@ -17,0 +17,0 @@ /// `TestEvent`.

@@ -196,3 +196,3 @@ // bearer auth v1

/// - a CONNECT tunnel to the user's own node, or
/// - a request the gateway makes to the backend (`AppBackendApi`) on the
/// - a request the gateway makes to the backend (`UserBackendApi`) on the
/// user's behalf, using its own backend credentials.

@@ -199,0 +199,0 @@ ///

@@ -1,320 +0,38 @@

//! Information about a client
//! The `GetRevocableClientStatus` interface for handshake-time revocation
//! checks.
use std::collections::HashMap;
use std::fmt;
use anyhow::anyhow;
use lexe_crypto::ed25519;
use lexe_serde::{
base64_or_bytes,
optopt::{self, none},
};
#[cfg(any(test, feature = "test-utils"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};
use crate::{
api::{
auth::{BearerAuthToken, LexeScope},
user::UserPk,
},
time::TimestampMs,
};
use crate::time::TimestampMs;
/// All revocable clients which have ever been created.
/// A handshake-time validity check for a revocable client cert.
///
/// This struct must be persisted in a rollback-resistant data store.
// We don't *really* need to persist revoked clients but might as well keep them
// around for historical reference. We can prune them later if needed.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RevocableClients {
pub clients: HashMap<ed25519::PublicKey, RevocableClient>,
}
impl RevocableClients {
/// A user shouldn't need more than 100 clients.
pub const MAX_LEN: usize = 100;
/// An iterator over all clients which are valid right now.
pub fn iter_valid(
/// This trait exists mainly so `RevocableClients` can live in `lexe-api-core`
/// rather than `lexe-common`.
///
/// Implemented by `lexe_api_core::revocable_clients::RevocableClientsHandle`.
pub trait GetRevocableClientStatus: fmt::Debug + Send + Sync {
/// The status of the revocable client identified by `client_pk` at `now`,
/// or [`None`] if no client with this pubkey exists.
fn get_client_status(
&self,
) -> impl Iterator<Item = (&ed25519::PublicKey, &RevocableClient)> {
self.iter_valid_at(TimestampMs::now())
}
/// An iterator over all clients which are valid at the given time.
pub fn iter_valid_at(
&self,
client_pk: &ed25519::PublicKey,
now: TimestampMs,
) -> impl Iterator<Item = (&ed25519::PublicKey, &RevocableClient)> {
self.clients
.iter()
.filter(|(_k, v)| !v.is_revoked)
.filter(move |(_k, v)| !v.is_expired_at(now))
}
) -> Option<RevocableClientStatus>;
}
/// Information about a revocable client.
/// Each client is issued a `RevocableClientCert` whose pubkey is saved here.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
pub struct RevocableClient {
/// The client's cert pubkey.
// TODO(max): In the future, bearer auth tokens could be issued to this pk.
pub pubkey: ed25519::PublicKey,
/// When we first issued the client cert and created this client.
pub created_at: TimestampMs,
/// The time after which the server will no longer accept this client.
/// [`None`] indicates that the client will never expire (use carefully!).
/// This expiration time can be extended at any time.
pub expires_at: Option<TimestampMs>,
/// Optional user-provided label for this client.
#[cfg_attr(
any(test, feature = "test-utils"),
proptest(strategy = "arb::any_label()")
)]
pub label: Option<String>,
/// The authorization scopes allowed for this client.
// TODO(max): This scope is currently ineffective.
pub scope: LexeScope,
/// Whether this client has been revoked. Revocation is permanent.
pub is_revoked: bool,
// TODO(phlip9): add "pausing" a client's access temporarily?
}
impl RevocableClient {
/// Limit label length to 64 bytes
pub const MAX_LABEL_LEN: usize = 64;
/// Whether the client is valid at a given time (not revoked, not expired).
#[must_use]
pub fn is_valid_at(&self, now: TimestampMs) -> bool {
!self.is_revoked && !self.is_expired_at(now)
}
/// Whether the client is expired at the given time.
#[must_use]
pub fn is_expired_at(&self, now: TimestampMs) -> bool {
if let Some(expiration) = self.expires_at
&& now > expiration
{
return true;
}
false
}
}
/// A request to list all revocable clients.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "test-utils"), derive(Eq, PartialEq, Arbitrary))]
pub struct GetRevocableClients {
/// Whether to return only clients which are currently valid.
pub valid_only: bool,
}
/// A request to create a new revocable client.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CreateRevocableClientRequest {
/// The expiration after which the node should reject this client.
/// [`None`] indicates that the client will never expire (use carefully!).
pub expires_at: Option<TimestampMs>,
/// Optional user-provided label for this client.
pub label: Option<String>,
/// The authorization scopes allowed for this client.
pub scope: LexeScope,
}
/// The response to [`CreateRevocableClientRequest`].
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CreateRevocableClientResponse {
/// The user public key associated with these credentials.
/// Always `Some` since `node-v0.8.11`.
#[serde(skip_serializing_if = "Option::is_none")]
pub user_pk: Option<UserPk>,
/// The client cert pubkey.
pub pubkey: ed25519::PublicKey,
/// When this client was created.
pub created_at: TimestampMs,
/// The DER-encoded ephemeral issuing CA cert that the client should trust.
/// The handshake-time status of a revocable client cert.
pub enum RevocableClientStatus {
/// Not revoked and not expired — accept the cert.
///
/// This is just packaged alongside the rest for convenience.
// NOTE: This client cert goes *last* in the cert chain given to rustls.
#[serde(with = "base64_or_bytes")]
pub eph_ca_cert_der: Vec<u8>,
/// The DER-encoded client cert to present when connecting to the node.
// NOTE: This client cert goes *first* in the cert chain given to rustls.
#[serde(with = "base64_or_bytes")]
pub rev_client_cert_der: Vec<u8>,
/// The DER-encoded client cert key.
#[serde(with = "base64_or_bytes")]
pub rev_client_cert_key_der: Vec<u8>,
/// A long-lived [`LexeScope::GatewayProxy`] token for connecting to the
/// user's node via the gateway proxy. Always `Some` for user nodes.
#[serde(skip_serializing_if = "Option::is_none")]
pub gateway_proxy_token: Option<BearerAuthToken>,
/// NOTE: This only means that the client is allowed to connect; it does NOT
/// mean that the client is *authorized* to do whatever it is asking to do.
/// Client scopes and budgets must still be enforced at a higher level.
Valid,
/// The client was revoked. Revocation is permanent.
Revoked,
/// The client is expired as of the queried time.
Expired,
}
/// A request to update a single [`RevocableClient`].
///
/// All fields except `pubkey` are optional. If a field is `None`, it will not
/// be updated. For example:
///
/// * `expires_at: None` -> don't change
/// * `expires_at: Some(None)` -> set to never expire
/// * `expires_at: Some(TimestampMs(..))` -> set to expire at that time
#[derive(Serialize, Deserialize)]
#[cfg_attr(test, derive(Debug, Eq, PartialEq, Arbitrary))]
pub struct UpdateClientRequest {
/// The pubkey of the client to update.
pub pubkey: ed25519::PublicKey,
/// Set this client's expiration (`Some(None)` means never expire).
#[serde(default, skip_serializing_if = "none", with = "optopt")]
pub expires_at: Option<Option<TimestampMs>>,
/// Set this client's label.
#[serde(default, skip_serializing_if = "none", with = "optopt")]
#[cfg_attr(test, proptest(strategy = "arb::any_label_update()"))]
pub label: Option<Option<String>>,
/// Set the authorization scopes allowed for this client.
#[serde(skip_serializing_if = "none")]
pub scope: Option<LexeScope>,
/// Set this to revoke or unrevoke the client. Revocation is permanent, so
/// you cannot unrevoke a client once it is revoked.
#[serde(skip_serializing_if = "none")]
pub is_revoked: Option<bool>,
}
/// The updated [`RevocableClient`] after a successful update.
#[derive(Serialize, Deserialize)]
pub struct UpdateClientResponse {
pub client: RevocableClient,
}
impl RevocableClient {
/// Apply an update to this client, returning a copy with updates applied.
pub fn update(&self, req: UpdateClientRequest) -> anyhow::Result<Self> {
let UpdateClientRequest {
pubkey: req_pubkey,
expires_at: req_expires_at,
label: req_label,
scope: req_scope,
is_revoked: req_is_revoked,
} = req;
let mut out = self.clone();
if self.pubkey != req_pubkey {
debug_assert!(false);
return Err(anyhow!("Cannot update a different client"));
}
if let Some(expires_at) = req_expires_at {
// TODO(max): Maybe need some validation here
out.expires_at = expires_at;
}
if let Some(maybe_label) = req_label {
if let Some(label) = &maybe_label
&& label.len() > Self::MAX_LABEL_LEN
{
return Err(anyhow!(
"Label must not be longer than {} bytes",
Self::MAX_LABEL_LEN,
));
}
out.label = maybe_label;
}
if let Some(scope) = req_scope {
// TODO(max): Need some validation here; can't request broader
// scope, only some clients can call, etc.
out.scope = scope;
}
if let Some(revoke) = req_is_revoked {
if self.is_revoked && !revoke {
return Err(anyhow!("Cannot unrevoke a client"));
}
out.is_revoked = revoke;
}
Ok(out)
}
}
#[cfg(any(test, feature = "test-utils"))]
mod arb {
use std::ops::RangeInclusive;
use proptest::{collection::vec, option, strategy::Strategy};
use super::*;
use crate::test_utils::arbitrary;
pub fn any_label() -> impl Strategy<Value = Option<String>> {
static RANGES: &[RangeInclusive<char>] =
&['0'..='9', 'A'..='Z', 'a'..='z'];
let any_alphanum_char = proptest::char::ranges(RANGES.into());
option::of(
vec(any_alphanum_char, 0..=RevocableClient::MAX_LABEL_LEN)
.prop_map(String::from_iter),
)
}
#[allow(dead_code)]
pub fn any_label_update() -> impl Strategy<Value = Option<Option<String>>> {
option::of(arbitrary::any_option_simple_string())
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{root_seed::RootSeed, test_utils::roundtrip};
#[test]
fn rev_client_ser_basic() {
let client1 = RevocableClient {
pubkey: *RootSeed::from_u64(1).derive_user_key_pair().public_key(),
created_at: TimestampMs::from_secs_u32(69),
expires_at: Some(TimestampMs::from_secs_u32(420)),
label: Some("deez".to_string()),
scope: LexeScope::All,
is_revoked: false,
};
let client_json = serde_json::to_string_pretty(&client1).unwrap();
// println!("{client_json}");
let client_json_snapshot = r#"{
"pubkey": "aa8e3e1a9bffdb073507f23474100619fdd4e392ef0ff1e89348252f287a06fc",
"created_at": 69000,
"expires_at": 420000,
"label": "deez",
"scope": "All",
"is_revoked": false
}"#;
assert_eq!(client_json, client_json_snapshot);
let client2 =
serde_json::from_str::<RevocableClient>(&client_json).unwrap();
assert_eq!(client1, client2);
}
#[test]
fn test_update_request_serde() {
roundtrip::json_string_roundtrip_proptest::<UpdateClientRequest>();
}
#[test]
fn test_get_revocable_clients_serde() {
roundtrip::query_string_roundtrip_proptest::<GetRevocableClients>();
}
}

@@ -9,6 +9,3 @@ use std::{fmt, str::FromStr};

use lexe_std::Apply;
use lightning::{
chain::transaction::OutPoint,
ln::{channel_state::ChannelDetails, types::ChannelId},
};
use lightning::ln::channel_state::ChannelDetails;
#[cfg(any(test, feature = "test-utils"))]

@@ -28,2 +25,4 @@ use proptest_derive::Arbitrary;

/// A newtype for [`lightning::ln::types::ChannelId`].
//
// NOTE: This is exposed in the Rust SDK.
#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]

@@ -33,15 +32,15 @@ #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]

#[repr(transparent)]
pub struct LxChannelId(#[serde(with = "hexstr_or_bytes")] pub [u8; 32]);
pub struct ChannelId(#[serde(with = "hexstr_or_bytes")] pub [u8; 32]);
lexe_byte_array::impl_byte_array!(LxChannelId, 32);
lexe_byte_array::impl_fromstr_fromhex!(LxChannelId, 32);
lexe_byte_array::impl_debug_display_as_hex!(LxChannelId);
lexe_byte_array::impl_byte_array!(ChannelId, 32);
lexe_byte_array::impl_fromstr_fromhex!(ChannelId, 32);
lexe_byte_array::impl_debug_display_as_hex!(ChannelId);
impl From<ChannelId> for LxChannelId {
fn from(cid: ChannelId) -> Self {
impl From<lightning::ln::types::ChannelId> for ChannelId {
fn from(cid: lightning::ln::types::ChannelId) -> Self {
Self(cid.0)
}
}
impl From<LxChannelId> for ChannelId {
fn from(cid: LxChannelId) -> Self {
impl From<ChannelId> for lightning::ln::types::ChannelId {
fn from(cid: ChannelId) -> Self {
Self(cid.0)

@@ -51,17 +50,21 @@ }

/// See: [`lightning::ln::channel_state::ChannelDetails::user_channel_id`]
///
/// The user channel id lets us consistently identify a channel through its
/// whole lifecycle.
///
/// The main issue is that we don't know the [`LxChannelId`] until we've
/// actually talked to the remote node and agreed to open a channel. The second
/// issue is that we can't easily observe and correlate any errors from channel
/// negotiation beyond some basic checks before we send any messages.
/// A client-generated id that identifies a channel throughout its entire
/// lifecycle, including before the channel is confirmed on-chain and assigned
/// its [`ChannelId`].
//
// See: `lightning::ln::channel_state::ChannelDetails::user_channel_id`
//
// The user channel id lets us consistently identify a channel through its whole
// lifecycle. The main issue is that we don't know the `ChannelId` until we've
// actually talked to the remote node and agreed to open a channel. The second
// issue is that we can't easily observe and correlate any errors from channel
// negotiation beyond some basic checks before we send any messages.
//
// NOTE: This is exposed in the Rust SDK.
#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
#[derive(Copy, Clone, Eq, PartialEq, Hash, RefCast, Serialize, Deserialize)]
#[repr(transparent)]
pub struct LxUserChannelId(#[serde(with = "hexstr_or_bytes")] pub [u8; 16]);
pub struct UserChannelId(#[serde(with = "hexstr_or_bytes")] pub [u8; 16]);
impl LxUserChannelId {
impl UserChannelId {
#[inline]

@@ -76,12 +79,12 @@ pub fn to_u128(self) -> u128 {

pub fn derive_temporary_channel_id(&self) -> LxChannelId {
LxChannelId(sha256::digest(&self.0).to_array())
pub fn derive_temporary_channel_id(&self) -> ChannelId {
ChannelId(sha256::digest(&self.0).to_array())
}
}
lexe_byte_array::impl_byte_array!(LxUserChannelId, 16);
lexe_byte_array::impl_fromstr_fromhex!(LxUserChannelId, 16);
lexe_byte_array::impl_debug_display_as_hex!(LxUserChannelId);
lexe_byte_array::impl_byte_array!(UserChannelId, 16);
lexe_byte_array::impl_fromstr_fromhex!(UserChannelId, 16);
lexe_byte_array::impl_debug_display_as_hex!(UserChannelId);
impl From<u128> for LxUserChannelId {
impl From<u128> for UserChannelId {
fn from(value: u128) -> Self {

@@ -92,4 +95,4 @@ Self(value.to_le_bytes())

impl From<LxUserChannelId> for u128 {
fn from(value: LxUserChannelId) -> Self {
impl From<UserChannelId> for u128 {
fn from(value: UserChannelId) -> Self {
value.to_u128()

@@ -104,4 +107,4 @@ }

// --- Basic info --- //
pub channel_id: LxChannelId,
pub user_channel_id: LxUserChannelId,
pub channel_id: ChannelId,
pub user_channel_id: UserChannelId,
/// The position of the funding transaction in the chain.

@@ -125,3 +128,3 @@ /// - Used as a short identifier in many places.

pub outbound_payment_scid: Option<Scid>,
pub funding_txo: Option<LxOutPoint>,
pub funding_txo: Option<OutPoint>,
// Introduced in node-v0.6.16, lsp-v0.6.32

@@ -272,6 +275,6 @@ pub counterparty_alias: Option<String>,

let channel_id = LxChannelId::from(channel_id);
let user_channel_id = LxUserChannelId::from(user_channel_id);
let channel_id = ChannelId::from(channel_id);
let user_channel_id = UserChannelId::from(user_channel_id);
let scid = short_channel_id.map(Scid);
let funding_txo = funding_txo.map(LxOutPoint::from);
let funding_txo = funding_txo.map(OutPoint::from);
let counterparty_node_id = NodePk(counterparty.node_id);

@@ -390,12 +393,16 @@ let channel_value = Amount::try_from_sats_u64(channel_value_satoshis)

/// A newtype for [`OutPoint`] that provides [`FromStr`] / [`fmt::Display`]
/// impls.
///
/// Since the persister relies on the string representation to identify
/// channels, having a newtype (instead of upstreaming these impls to LDK)
/// ensures that the serialization scheme does not change from beneath us.
/// A reference to a specific transaction output: the `txid` of the transaction
/// together with the `index` of the output within that transaction.
//
// A newtype for `lightning::chain::transaction::OutPoint` that provides
// `FromStr` / `fmt::Display` impls. Since the persister relies on the string
// representation to identify channels, having a newtype (instead of upstreaming
// these impls to LDK) ensures that the serialization scheme does not change
// from beneath us.
//
// NOTE: This is exposed in the Rust SDK.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(SerializeDisplay, DeserializeFromStr)]
#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
pub struct LxOutPoint {
pub struct OutPoint {
pub txid: Txid,

@@ -405,4 +412,4 @@ pub index: u16,

impl From<OutPoint> for LxOutPoint {
fn from(op: OutPoint) -> Self {
impl From<lightning::chain::transaction::OutPoint> for OutPoint {
fn from(op: lightning::chain::transaction::OutPoint) -> Self {
Self {

@@ -415,4 +422,4 @@ txid: Txid(op.txid),

impl From<LxOutPoint> for OutPoint {
fn from(op: LxOutPoint) -> Self {
impl From<OutPoint> for lightning::chain::transaction::OutPoint {
fn from(op: OutPoint) -> Self {
Self {

@@ -425,4 +432,4 @@ txid: op.txid.0,

impl From<LxOutPoint> for bitcoin::OutPoint {
fn from(op: LxOutPoint) -> Self {
impl From<OutPoint> for bitcoin::OutPoint {
fn from(op: OutPoint) -> Self {
bitcoin::OutPoint {

@@ -436,3 +443,3 @@ txid: op.txid.0,

/// Deserializes from `<txid>_<index>`
impl FromStr for LxOutPoint {
impl FromStr for OutPoint {
type Err = anyhow::Error;

@@ -458,3 +465,3 @@ fn from_str(outpoint_str: &str) -> anyhow::Result<Self> {

/// Serializes to `<txid>_<index>`
impl fmt::Display for LxOutPoint {
impl fmt::Display for OutPoint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

@@ -472,4 +479,4 @@ write!(f, "{}_{}", self.txid, self.index)

fn outpoint_fromstr_display_roundtrip() {
roundtrip::fromstr_display_roundtrip_proptest::<LxOutPoint>();
roundtrip::fromstr_display_roundtrip_proptest::<OutPoint>();
}
}

Sorry, the diff of this file is not supported yet