-
Notifications
You must be signed in to change notification settings - Fork 76
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(sequencer): support IbcAction
s and implement ICS20 incoming transfer application logic
#579
Conversation
IbcAction
s and implement ICS20 transfer application logicIbcAction
s and implement ICS20 transfer application logic
## Summary Replaces `buf generate` by `tonic_build` to generate rust code from protobuf. ## Background `buf generate` relies on the third party plugins `protoc-gen-prost` and `protoc-gen-tonic`, which are not yet updated to prost-build 0.12 and tonic-build 0.10 (and hence prost 0.12, tonic 0.10). This patch moves code generation away from the `buf generate` executable to the Rust `tonic-build` crate, because we need to update prost/tonic and because these projects do not guarantee that code generated with older versions work with newer versions. ## Changes - Replace invoking the `buf generate` executable by using `tonic_build` directly - Use `buf build` to create a file descriptor set that can be fed into `tonic_build` (the latter skips its own invocation of `protoc`) - Clean the generated code by removing all files that are not prefixed with `astria.` (tonic also creates client and server code for tendermint abci; I am not sure why, probably due to the descriptor set) ## Testing Not tested directly; this should not affect the actual code generated. Everything should still compile, all tests should pass. ## Related Issues PR requiring a newer version of penumbra and hence prost: #579 PR againast protoc-gen-prost: neoeinstein/protoc-gen-prost#78
@@ -21,6 +21,9 @@ use crate::{ | |||
state_ext::StateReadExt as _, | |||
}; | |||
|
|||
// TODO: use penumbra's `IBC_SUBSTORE_PREFIX` after they merge #3419 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if they merge this before this PR is merged (likely), i will update this PR, otherwise i'll do a follow-up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just quickly went over this to flag obvious issues, but didn't see anything big outside of implementation specific details.
I am going to do a second round to understand the logic.
@@ -41,6 +41,11 @@ once_cell = "1.17.1" | |||
sha2 = "0.10" | |||
serde = "1" | |||
serde_json = "1" | |||
penumbra-component = { git = "https://github.com/penumbra-zone/penumbra.git", rev = "11d3b524da750c16c376759b03e4bbb3474562d9" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we can wait until they make a new release?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i can ask them when that'll be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@noot The plan is to do a tagged release monday next week (Dec 4th) along with our new persistent testnet deployment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice, thanks!
tendermint-config = "0.34" | ||
tendermint-proto = "0.34" | ||
tendermint-rpc = "0.34" | ||
tendermint = "0.34.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why add the .0
? Doesn't change anything, just curios.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i just had this here before i merged your update in and didn't change it lol, so no reason in particular
crates/astria-proto/Cargo.toml
Outdated
@@ -25,6 +27,8 @@ tendermint-proto = { workspace = true } | |||
tonic = { workspace = true, optional = true } | |||
tracing = { workspace = true, optional = true } | |||
|
|||
anyhow = "1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use anyhow here but type the errors.
/// # Errors | ||
/// | ||
/// - if the denomination string is invalid, ie. does not contain any slashes. | ||
pub fn from_denomination(denom: &str) -> anyhow::Result<Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use an impl FromStr
here. Also two notes:
- you have the
Denom
type in a previous PR. It is surprising that this is calledfrom_denomation
but takes a string. Bettertry_from_str
or justimpl FromStr
. astria-proto
tries to usefrom_*
for infallible methods, andtry_from_*
for falllible- Please don't introduce anyhow here. The rest of the lib tries hard to type the errors
@@ -8,6 +8,7 @@ use ed25519_consensus::{ | |||
SigningKey, | |||
VerificationKey, | |||
}; | |||
use penumbra_ibc::IbcRelay as IbcAction; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please no alias, just use IbcRelay
// check if escrow account has enough balance to refund user | ||
let balance = state | ||
.get_ibc_channel_balance(source_channel, asset.id()) | ||
.await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add context
true, | ||
) | ||
.await | ||
.map_err(|e| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer if let Err(e) =
over map_err
. In the future we will have https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect_err
.await | ||
.map_err(|e| { | ||
tracing::error!( | ||
"failed to refund tokens during acknowledge_packet_execute: {}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't format, prefer this (assuming that e
is likely an anyhow::Error
):
let error: &dyn std::error::Error = e.as_ref();
tracing::error!(error, "failed to <your msg>");
) -> Result<()> { | ||
use prost::Message as _; | ||
|
||
let packet_data = FungibleTokenPacketData::decode(data)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context for this and the next lines
) | ||
.context("invalid receiver address")?; | ||
|
||
if is_source(source_port, source_channel, &asset, is_refund) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add error context for all the errors in here
Cargo.lock
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pulling some heavy dependencies, wow
crates/astria-proto/proto/buf.yaml
Outdated
@@ -1,7 +1,7 @@ | |||
version: v1 | |||
name: buf.build/astria/astria | |||
deps: | |||
- buf.build/tendermint/tendermint | |||
- buf.build/penumbra-zone/penumbra |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should pin the specific version of the penumbra proto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't it pinned in the buf.lock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not the same kind of pinning IMO. The lock file encodes code generation at the time buf was run, whereas pinning in the YAML shows author intent.
IbcAction
s and implement ICS20 transfer application logicIbcAction
s and implement ICS20 incoming transfer application logic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments re making it easier to understand, but looks good. Thank you!
crates/astria-proto/proto/buf.yaml
Outdated
@@ -1,7 +1,7 @@ | |||
version: v1 | |||
name: buf.build/astria/astria | |||
deps: | |||
- buf.build/tendermint/tendermint | |||
- buf.build/penumbra-zone/penumbra |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not the same kind of pinning IMO. The lock file encodes code generation at the time buf was run, whereas pinning in the YAML shows author intent.
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
Self::InvalidDenomination => { | ||
write!(f, "denomination must contain at least one slash") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
write!(f, "denomination must contain at least one slash") | |
f.write_str("denomination must contain at least one slash") |
@@ -0,0 +1,349 @@ | |||
use std::str::FromStr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to pull this in, use str::parse
, see below
|
||
let packet_data = FungibleTokenPacketData::decode(data) | ||
.context("failed to decode packet data into FungibleTokenPacketData")?; | ||
let asset = IbcAsset::from_str(&packet_data.denom).context("invalid denomination")?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once you have impl'ed FromStr
you can use str::parse
:
let asset = IbcAsset::from_str(&packet_data.denom).context("invalid denomination")?; | |
let asset = packet_data.denom.parse::<IbcAsset>().context("failed parsing `denom` field packet data as IbcAsset")?; |
.await | ||
.context("failed to get channel balance in refund_tokens_check")?; | ||
|
||
let packet_amount: u128 = packet_data.amount.parse()?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a module doc comment on this explaining (and linking) that the purpose of this module is to implement AppHandlerCheck
so that Ics20Transfer
can be used for penumbra's check_stateless
?
Lots of boiler plate to wire it up and it's tough to understand where the logic comes from.
act.clone() | ||
.with_handler::<crate::accounts::ics20_transfer::Ics20Transfer>() | ||
.check_stateless(()) | ||
.await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context
act.clone() | ||
.with_handler::<crate::accounts::ics20_transfer::Ics20Transfer>() | ||
.execute(&mut *state) | ||
.await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context
Action::Ibc(act) => { | ||
act.clone() | ||
.with_handler::<crate::accounts::ics20_transfer::Ics20Transfer>() | ||
.check_stateless(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's their (penumbra's) check_stateless
, right?
Yeah, I see the penumbra
action handler above. can we make this more obvious to the reader to disambiguate between our check_stateless
and theirs?
let the_action = act.clone().with_handler::<Ics20Transfer>();
penumbra_component::ActionHandler::check_stateless(&the_action);
pub(crate) struct Ics20Transfer; | ||
|
||
#[async_trait::async_trait] | ||
impl AppHandlerCheck for Ics20Transfer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is where the magic is: AppHandlerCheck
must be impl'ed to make with_handler
work.
Can we get that as a module doc comment?
## Summary Counterpart to #579 which supports incoming ICS20 transfers, this PR implements outgoing ICS20 transfers. ## Background required for IBC token transfer support. See https://github.com/cosmos/ibc/blob/fe150abb629de5c1a598e8c7896a7568f2083681/spec/app/ics-020-fungible-token-transfer/README.md `sendFungibleTokens` for spec. ## Changes - add `Ics20Withdrawal` proto and native type which is an action (maybe rename to `Ics20WithdrawalAction`?) - implement check logic (apart from IBC packet check, check the sender has enough balance) - implement execution logic (escrow tokens if native, or burn if not native) ## Testing not really - same issue as #579 ## Related Issues closes #597
Summary
Adds IBC support for ICS20 token transfers
Background
We want IBC support, specifically for token transfers (eg. using TIA as a gas token).
See the cosmos ICS20 spec: https://github.com/cosmos/ibc/blob/fe150abb629de5c1a598e8c7896a7568f2083681/spec/app/ics-020-fungible-token-transfer/README.md
Changes
AppHandler
s + substore supportIbcAsset
type which represents an IBC-transferred-tokenAction
proto and native enums to includeIbcAction
variants,IbcAction
is a type defined inpenumbra_ibc
sequencer::accounts::Ics20Transfer
which is the app handler forIbcAction
s, which is called into duringIbcAction::check_stateless
andIbcAction::execute
Ics20Transfer
contains the actual ICS20 transfer logic; namely, handling inbound IBC packets that are transfers. there are two main cases we handle for transfer logic: a token being received on Astria from another chain, or a notification of an outbound transfer failing, in which case we need to refund the escrowed tokens.Testing
can't really test the transfer functionality without heavier integration testing at the moment, due to the fact that it requires merkle proofs of state of the counterparty chain. in discussions with the penumbra team about a "mock tendermint" test harness we could use to test this in a unit-test-like environment.
Breaking Changelist
Related Issues
closes #79