Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: packet-forward-middleware #1562

Merged
merged 77 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
937fbfc
feat(ucs01-relay-api): added ForwardMemo struct
PoisonPhang Mar 19, 2024
84071d4
feat(ucs01-relay-api): restructured pfm types
PoisonPhang Mar 20, 2024
4a121d6
feat(ucs01-relay-api): parsed forward memo into type
PoisonPhang Mar 20, 2024
0804008
feat(ucs01-relay-api): added workspace deps
PoisonPhang Mar 21, 2024
c797fb5
feat(ucs01-relay-api): pfm message parsing
PoisonPhang Mar 21, 2024
abf2cb8
feat(ucs01-relay-api): added cosmos account hasher
PoisonPhang Mar 25, 2024
f84d336
feat(ucs01-relay-api): added middleware and pfm
PoisonPhang Apr 9, 2024
7598ba1
feat(ucs01-relay): added pfm for UCS01
PoisonPhang Apr 9, 2024
6989db9
feat(ucs01-relay): forward packet and store refund
PoisonPhang Apr 11, 2024
06d6d53
feat(ucs01-relay): pfm handling for ack
PoisonPhang Apr 25, 2024
868f2f9
feat(uniond): added differedack protos
PoisonPhang Apr 29, 2024
a2716b7
chore: gen proto
PoisonPhang Apr 29, 2024
e340783
chore(uniond): add differedack module
PoisonPhang May 1, 2024
8a5838d
chore: remove anti-pattern
PoisonPhang May 2, 2024
eb8a4b8
fix(uniond): update diffack message proto
PoisonPhang May 2, 2024
5f3ed71
feat(uniond): diffack module
PoisonPhang May 3, 2024
6cac7ed
fix(uniond): move away from legacy params
PoisonPhang May 3, 2024
b2dd2ba
chore(ucs01-relay): remove pfm fees
PoisonPhang May 3, 2024
95045ac
feat(ucs01-relay): timeout forward
PoisonPhang May 3, 2024
6577123
chore: ics20 pfm
PoisonPhang May 6, 2024
50b1f38
chore: differed -> diferred
PoisonPhang May 8, 2024
055b857
chore: gen proto
PoisonPhang May 8, 2024
f5bb4d9
feat(uniond): added wasm bindings for diferredack
PoisonPhang May 9, 2024
f0f7730
chore: differed -> diferred
PoisonPhang May 9, 2024
e012b67
feat(ucs01-relay): return no ack
PoisonPhang May 9, 2024
55edef2
feat(uniond): add diferredack module to app
PoisonPhang May 9, 2024
5a284d3
feat: added diferred-ack-api
PoisonPhang May 9, 2024
d2446c5
chore: cosmwasm 2.0 fixes
PoisonPhang May 15, 2024
3573a03
feat(ucs01-relay): process pfm refund
PoisonPhang May 15, 2024
65fe4fe
chore: gen rust protos
PoisonPhang May 15, 2024
dc53bdd
chore(ucs01-relay): add protos to ucs01-relay
PoisonPhang May 15, 2024
a7c8bb1
chore(uniond): remove unused params from diffack
PoisonPhang May 16, 2024
444bb07
chore(uniond): gen proto
PoisonPhang May 16, 2024
fb8d508
chore: gen proto
PoisonPhang May 16, 2024
6c4442b
fix(uniond): difack nullable timeout
PoisonPhang May 16, 2024
557740f
chore: gen proto
PoisonPhang May 16, 2024
8ad725b
chore(uniond): remove unused protos
PoisonPhang May 20, 2024
f6cab93
chore: gen proto
PoisonPhang May 20, 2024
9fbff02
chore: gen proto
PoisonPhang May 20, 2024
08897f4
feat(diferred-ack-api): updated api to reflect protos
PoisonPhang May 21, 2024
5b5515e
feat(ucs01-relay): call into diferredack module
PoisonPhang May 21, 2024
b5bdfd9
chore(uniond): go mod vendor
PoisonPhang May 23, 2024
eb050c0
feat(unionlabs): feature gate cosmwasm usage
PoisonPhang May 23, 2024
94fbf82
fix: add cosmwasm feature to unionlabs
PoisonPhang May 23, 2024
66a258c
fix: lol
PoisonPhang May 23, 2024
e53d976
fix(unionlabs): gate custom_query
PoisonPhang May 23, 2024
9958aca
feat(ethereum-verifier): enable cosmwasm
PoisonPhang May 23, 2024
cba7aaf
feat(ucs01-relay): use sequence for indexing pfm
PoisonPhang May 23, 2024
1861657
fix(unionlabs): add cosmwasm to stargate feat
PoisonPhang May 24, 2024
e11af5a
chore(ucs01-relay-api): remove unused
PoisonPhang May 24, 2024
40e852b
chore: propagate errors
aeryz May 24, 2024
cd8f0cc
chore: remove debug
PoisonPhang May 27, 2024
9c7219d
fix(uniond): temporarily alter vendor
PoisonPhang May 28, 2024
2ba8b74
fix(ucs01-relay-api): correctly cast data and ack
PoisonPhang May 29, 2024
951058b
fix(ucs01-relay): use ack type
PoisonPhang May 29, 2024
c2ced52
feat(ucs01-relay): use sequence to create key
PoisonPhang May 29, 2024
6524f02
fix(ucs01-relay): expect rather than silent fail
PoisonPhang May 29, 2024
32dbf87
chore(diferred-ack-api): update cosmwasm-std
PoisonPhang May 30, 2024
b91f3af
fix(ucs01-relay): expect msg inclusion
PoisonPhang May 30, 2024
c58f919
feat(ucs01-relay): error on no submsg
PoisonPhang May 30, 2024
48b09af
fix(ucs01-relay): use proto struct when calling go
PoisonPhang May 31, 2024
2bff111
fix(uniond): create diferred ack keeper correctly
PoisonPhang Jun 2, 2024
373a498
feat(ucs01-relay): correctly forward ack
PoisonPhang Jun 2, 2024
f771d5b
chore: sqlx offline in devshell
PoisonPhang Jun 2, 2024
ebe81be
feat(ucs01-relay): remove pfm store on ack
PoisonPhang Jun 3, 2024
01223e0
chore: nix fmt
PoisonPhang Jun 3, 2024
374f76e
chore(uniond): diferredack -> deferredack
PoisonPhang Jun 3, 2024
8e4b71c
chore: generate rust protos
PoisonPhang Jun 3, 2024
324031f
chore(ucs01-relay): diferred -> deferred
PoisonPhang Jun 3, 2024
01573c8
feat(uniond): added da cv to vm
PoisonPhang Jun 3, 2024
8d10452
feat: added da key to storage upgrades
PoisonPhang Jun 4, 2024
95cc231
feat(ucs01-relay): support memo extensions
PoisonPhang Jun 4, 2024
1031870
feat(ucs01-relay): support memo extension from sol
PoisonPhang Jun 4, 2024
7ffd2ba
chore: generate rust sol bindings
PoisonPhang Jun 5, 2024
82d1332
feat(ucli): support memo when submitting eth txs
PoisonPhang Jun 5, 2024
7651186
chore(ucs01): handle memo for ucs01 transfer packet
aeryz Jun 5, 2024
7347141
chore: fmt
aeryz Jun 5, 2024
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
17 changes: 17 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ ethabi = { version = "18.0.0", default-features = false }
frame-support-procedural = { version = "22.0.0", default-features = false }
frunk = { version = "0.4.2", default-features = false }
futures = { version = "0.3.28", default-features = false }
go-parse-duration = { version = "0.1.1", default-features = false }
hex = { version = "0.4.3", default-features = false }
hex-literal = { version = "0.4.1", default-features = false }
lazy_static = { version = "1.4.0", default-features = false }
Expand Down
7 changes: 7 additions & 0 deletions cosmwasm/ucs01-relay-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ workspace = true
cosmwasm-schema = { version = "2.0.0" }
cosmwasm-std = { version = "2.0.0", features = ["stargate"] }
ethabi = { workspace = true }
go-parse-duration = { workspace = true }
prost = { workspace = true }
protos = { workspace = true }
serde = { workspace = true }
serde-json-wasm = { workspace = true }
serde-utils = { workspace = true }
sha2 = { workspace = true }
thiserror = { workspace = true }
token-factory-api = { workspace = true }
unionlabs = { workspace = true }
1 change: 1 addition & 0 deletions cosmwasm/ucs01-relay-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod middleware;
pub mod protocol;
pub mod types;
175 changes: 175 additions & 0 deletions cosmwasm/ucs01-relay-api/src/middleware.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use cosmwasm_std::{Addr, Binary, IbcPacket, IbcTimeout};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use unionlabs::{
id::{ChannelId, PortId},
validated::{Validate, Validated},
};

pub const DEFAULT_PFM_TIMEOUT: &str = "1m";
pub const DEFAULT_PFM_RETRIES: u8 = 0;
pub const PFM_MODULE_NAME: &str = "packetforwardmiddleware";

#[derive(Error, Debug, PartialEq)]
pub enum MiddlewareError {
#[error("{0}")]
PacketForward(#[from] PacketForwardError),
}

#[derive(Error, Debug, PartialEq)]
pub enum PacketForwardError {
#[error("A packet returned via timeout or ack did not contain a refund index")]
NoPacketRefundInformation,
#[error("Unable to find a packet with the given refund index")]
PacketNotInRefundStore,
#[error("Unable to encode/decode packet")]
InvalidEncoding,
#[error("Unable to index for reply message in stack")]
NoReplyMessageInStack,
}

pub fn default_pfm_timeout() -> String {
DEFAULT_PFM_TIMEOUT.to_owned()
}

pub fn default_pfm_retries() -> u8 {
DEFAULT_PFM_RETRIES
}

#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub enum PacketReturnInfo {
InFlight(Box<InFlightPfmPacket>),
NewPacket(PacketId),
}

/// Given that we can't know the IBC packet sequence of a new packet before it's sent, we instead construct and store this information about a packet to index it.
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct PacketId {
pub height: u64,
pub index: u64,
}

/// Information about an in flight packet, used to process retries and refunds.
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct InFlightPfmPacket {
pub original_sender_addr: Addr,
pub packet_data: Binary,
pub packet_src_channel_id: String,
pub packet_src_port_id: String,
pub refund_channel_id: String,
pub refund_port_id: String,
pub packet_sequence: u64,
pub timeout: u64,
pub src_packet_timeout: IbcTimeout,
pub forward_channel_id: String,
pub forward_port_id: String,
}

impl InFlightPfmPacket {
pub fn new(
original_sender_addr: Addr,
original_packet: IbcPacket,
timeout: u64,
forward_channel_id: String,
forward_port_id: String,
) -> Self {
Self {
original_sender_addr,
packet_data: original_packet.data,
packet_src_channel_id: original_packet.src.channel_id,
packet_src_port_id: original_packet.src.port_id,
refund_channel_id: original_packet.dest.channel_id,
refund_port_id: original_packet.dest.port_id,
timeout,
src_packet_timeout: original_packet.timeout,
packet_sequence: original_packet.sequence,
forward_channel_id,
forward_port_id,
}
}
}

#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Memo {
Forward { forward: PacketForward },
None {},
}

#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct PacketForward {
pub receiver: PfmReceiver,
pub port: PortId,
pub channel: ChannelId,
#[serde(default = "default_pfm_timeout")]
pub timeout: String,
#[serde(default = "default_pfm_retries")]
pub retries: u8,
pub next: Option<Box<PacketForward>>,
pub return_info: Option<PacketId>,
}

impl PacketForward {
/// Effective timeout is equivalent to `timeout * retries`.
///
/// If the `timeout` is invalid or cannot be parsed, the default timeout is used.
/// Timeouts are considered invalid if they are less than or equal to zero.
pub fn get_effective_timeout(&self) -> u64 {
let retries = self.retries as i64 + 1;
let default_timeout = go_parse_duration::parse_duration(&default_pfm_timeout())
.expect("default timeout is correctly formatted")
* retries;

(match go_parse_duration::parse_duration(&self.timeout) {
Ok(timeout) => {
if timeout <= 0 {
default_timeout
} else {
timeout * retries
}
}
Err(_error) => default_timeout,
}) as u64
}
}

pub type PfmReceiverValidator = NotEmptyString;
pub type PfmReceiver = Validated<String, PfmReceiverValidator>;

pub struct NotEmptyString;

// TODO: Not specific to receiver
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
#[error("failed to validate metadata. receiver cannot be empty")]
pub struct EmptyStringError;

impl<T: Into<String> + From<String>> Validate<T> for NotEmptyString {
type Error = EmptyStringError;

fn validate(t: T) -> Result<T, Self::Error> {
let s = t.into();

if s.is_empty() {
Err(EmptyStringError)
} else {
Ok(s.into())
}
}
}

#[cfg(test)]
mod tests {
use super::Memo;

#[test]
fn serde_parses_memo() {
// let memo = "\"balls\": \"string\"";
let memo = "{\"forward\": {\"receiver\": \"[eth_addr]\",\"port\": \"[union-eth port]\",\"channel\": \"[union-eth channel]\",\"timeout\": \"1000000\",\"retries\": 0}}";

let parsed = serde_json_wasm::from_str::<Memo>(memo).expect("works");

dbg!(parsed);

// panic!()
}
}
Loading
Loading