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

Correct swap claim height check #4239

Merged
merged 1 commit into from
Apr 25, 2024

Conversation

cronokirby
Copy link
Contributor

@cronokirby cronokirby commented Apr 18, 2024

Describe your changes

This changes the circuit check in swap claims to check that the exact epoch and block where a swap was made match that output data for the batch swap of that epoch and block. Previously were effectively only checking that the intra-block value was the same, but not the epoch.

TODO: Write migration for batch swap output datas

Checklist before requesting a review

  • If this code contains consensus-breaking changes, I have added the "consensus-breaking" label. Otherwise, I declare my belief that there are not consensus-breaking changes, for the following reason:

    A migration will be needed to augment batch swap output data

@cronokirby cronokirby added consensus-breaking breaking change to execution of on-chain data state-breaking breaking change to on-chain data labels Apr 18, 2024
@cronokirby
Copy link
Contributor Author

Not quite sure why the tests aren't passing, will pick back up tomorrow morning.

@erwanor erwanor self-requested a review April 19, 2024 00:04
@conorsch
Copy link
Contributor

These changes should be based on v0.71.0, so that the fix is compatible with the existing testnet. Because the changes are consensus-breaking, we should bump the minor version in order to release. To that end, I've pushed a release/v0.72.x branch, branched from the v0.71.0, that should be targeted with this PR.

@redshiftzero redshiftzero self-requested a review April 19, 2024 16:22
@cratelyn cratelyn added this to the Sprint 4 milestone Apr 19, 2024
Comment on lines 159 to 160
pub epoch: FqVar,
pub block: FqVar,
Copy link
Member

Choose a reason for hiding this comment

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

What's the rationale behind making these an FqVar rather than an alternate representation?

Also, could we give them different names to clarify that they're not standalone values, but components of a Position? Like

pub position_epoch_component: FqVar,
pub position_block_component: FqVar,

or some other name? I'm just worried that calling it block could suggest it's the block height, which it isn't.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to store a PositionVar now

Copy link
Member

Choose a reason for hiding this comment

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

No I meant, what's the rationale for the representation? I'm not opposed to using an FqVar, I'm just wondering how we decide one or the other. Can we write up a brief rationale for why we picked one or the other?

Copy link
Member

Choose a reason for hiding this comment

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

A PositionVar has a position stored internally as both an FqVar and a series of 48 bit constraints - 16 bits each for the epoch, block, and commitment segment of the position. Since we need to compare the epoch and block from the position from the state commitment proof with the epoch and block from the BSOD, and we're already bit constraining to make two FqVars for the epoch and block in both cases, another (I think cheaper in constraints) option is to compare as bits directly. Comparing as FqVars also works though.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, in that case wouldn't making the two prefix components FqVars be cheaper? Since we already have the bit-constrained components of the actual position, we can check that they're equal to the provided prefix components without needing to bit-constrain the prefix components, right?

Copy link
Member

Choose a reason for hiding this comment

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

yep, you're right. That seems like the way to go to save the additional bit constraints

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah my thinking initially was that using FqVars avoids some overhead; I think using PositionVar is clearer though since it directly matches the domain type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure that comparing bits is cheaper in constraints: checking that (x0 + 2 * x1 + ...) =? (y0 + 2 * y1 + ...) can be done in a single R1CS constraint. Checking x0 =? y0, x1 =? y1 would require several

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, that seems like a good reason to use FqVars as in the original design, I think it's clearer than using a Position because it means we don't add any instance variables that don't have meaning but could be (mis)used in the circuit.

@cronokirby cronokirby changed the base branch from main to release/v0.72.x April 19, 2024 18:27
@cronokirby cronokirby force-pushed the batch-swap-output-correct-position branch from 50b1d7c to 0571414 Compare April 19, 2024 18:52
@cronokirby cronokirby force-pushed the batch-swap-output-correct-position branch from 0571414 to 873b1c7 Compare April 19, 2024 18:56
@cronokirby cronokirby force-pushed the batch-swap-output-correct-position branch from d0f12bd to 5962448 Compare April 19, 2024 20:03
@cronokirby cronokirby changed the title WIP Correct swap claim height check Apr 19, 2024
@cronokirby cronokirby force-pushed the batch-swap-output-correct-position branch from 676864a to 65407f4 Compare April 22, 2024 16:31
@cronokirby cronokirby force-pushed the batch-swap-output-correct-position branch from 65407f4 to 3acf558 Compare April 22, 2024 16:51
Copy link
Member

@redshiftzero redshiftzero left a comment

Choose a reason for hiding this comment

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

I know there is a migration to do, but the other changes LGTM

trading_pair,
delta_1,
delta_2,
lambda_1,
lambda_2,
unfilled_1,
unfilled_2,
sct_position_prefix: (
u16::try_from(epoch.index).expect("epoch index should be small enough"),
u16::try_from(block_height - epoch.start_height)
Copy link
Member

Choose a reason for hiding this comment

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

Can we add a comment about relative block conversion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to re-pitch adding tct protos: #4118

so other systems like the web code doesn't have to manually re-create this serialization logic happening in the .into()'s

@cratelyn cratelyn modified the milestones: Sprint 4, Sprint 5 Apr 22, 2024
@conorsch
Copy link
Contributor

Took a stab at testing this in a pairing session with @cronokirby today. A few commits were pushed as part of that exploration. We want to do some more testing before we're ready to ship this.

// Translate inside compact block storage.
translate_compact_block_storage(ctx.clone(), &mut delta).await?;

delta.put_block_height(0u64);
Copy link
Member

Choose a reason for hiding this comment

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

Why do we reset the block height here?

Copy link
Member

Choose a reason for hiding this comment

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

This is so we can do an InitChain handshake with comet and allow it to initialize its internal view before block sync/proposals. The flow looks like this:

pd <-   info query   -- comet
pd --  app height=0  -> comet
pd <- init chain req -- comet
pd -- init chain resp -> comet

unfortunately, the CometBft spec seem to have been reorganized again, so it will take me a minute to fish out the link

Copy link
Member

Choose a reason for hiding this comment

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

Interesting. So the idea is that setting it to 0 signals that the app is ready for genesis, then once pd sends the init chain message, it will get set to h+1 as set in the genesis file?

Copy link
Member

@erwanor erwanor Apr 25, 2024

Choose a reason for hiding this comment

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

That's right, it will consume the genesis as a result of reading a zero app height, and then pull the specified initialHeight

let (key, compactblack_bytes): (String, Vec<u8>) = r?;
let block = pb::compact_block::v1::CompactBlock::decode(compactblack_bytes.as_slice())?;
let block = ctx.translate_compact_block(block).await?;
delta.put_proto(key, block);
Copy link
Member

Choose a reason for hiding this comment

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

Here the structure is correct, but we need to be reading from/writing to nonverifiable storage (the key looks correct).

let mut stream = delta.nonverifiable_prefix_raw("compactblock/".as_bytes());
while let Some(r) = stream.next().await {
let (key, compactblack_bytes) = r?;
let block = pb::compact_block::v1::CompactBlock::decode(compactblack_bytes.as_slice())?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: s/black/block/ in var names here.

@conorsch
Copy link
Contributor

Most recent round of testing on a private fork of the network showed good results. 👍 Let's make sure to squash this patch into a single commit, as we'll need to cherry-pick it back onto main post-release.

conorsch added a commit that referenced this pull request Apr 24, 2024
We recently removed mention of zeroing-out `priv_validator_state.json`
for CometBFT as part of the chain upgrade docs. During migration testing
on a private fork today, though, several of us observed that without
this change, the network would not resume. More research required to
understand the root cause here.

Refs #4245, #4239.
conorsch added a commit that referenced this pull request Apr 25, 2024
We recently removed mention of zeroing-out `priv_validator_state.json`
for CometBFT as part of the chain upgrade docs. During migration testing
on a private fork today, though, several of us observed that without
this change, the network would not resume. More research required to
understand the root cause here.

Refs #4245, #4239.
Make swap_claim check the exact epoch and block in circuit
Read epoch from state when creating batch swap output
This moves the epoch read directly to the route_and_fill method.
Depcrate epoch_starting_height in BSOD
Store epoch and block instead of position within BatchSwapOutputDataVar
Write migration
Add comments about relative block conversion
Fix warnings
Increment total halt count
Change which migration runs
Drop extra references to storage before releasing it
Use nonverifiable storage for compact block translation
This is where they actually are
@conorsch conorsch force-pushed the batch-swap-output-correct-position branch from 93a593a to 0b3f45e Compare April 25, 2024 15:59
@conorsch
Copy link
Contributor

Squashed into single commit, so it's cherry-pickable. Will wait on CI, then merge into release branch and get things moving.

Copy link
Member

@erwanor erwanor left a comment

Choose a reason for hiding this comment

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

ACK, thanks for your work on this @cronokirby @conorsch

@conorsch conorsch merged commit 3b0fa70 into release/v0.72.x Apr 25, 2024
5 checks passed
@conorsch conorsch deleted the batch-swap-output-correct-position branch April 25, 2024 17:02
conorsch added a commit that referenced this pull request Apr 25, 2024
conorsch added a commit that referenced this pull request Apr 25, 2024
erwanor pushed a commit that referenced this pull request Apr 29, 2024
This is a cherry-pick of PR #4239, by:
Author:    Lucas Meier <[email protected]>
Date:      Thu Apr 18 14:55:50 2024 -0700

This PR:
1. fix a bug in the swap claim circuit
2. includes a migration routine for testnet 71

Swap claim proofs take a `BatchSwapOutputData` as part of their
public inputs. This data is used to compute a user's pro-rated share
of a batch swap at a given block.

For that reason, it is important the output data used in the proof
be correct. A swap claim must be bound to the specific BSOD that
was produced by that user's swap.

The swap claim circuit's validation only checked that the supplied
BSOD was produced at the same relative block height as the user's
swap. It did not check that the epochs were the same.  As a result,
it was possible to generate swap claim proofs using a BSOD produced
during a different epoch, on potentially much more advantageous
terms.
@erwanor erwanor mentioned this pull request Apr 29, 2024
1 task
erwanor added a commit that referenced this pull request Apr 29, 2024
## Describe your changes

This is a cherry-pick of #4239, by:
Author:    Lucas Meier <[email protected]>
Date:      Thu Apr 18 14:55:50 2024 -0700

This PR:
1. fix a bug in the swap claim circuit
2. includes a migration routine for testnet 71

Swap claim proofs take a `BatchSwapOutputData` as part of their public
inputs. This data is used to compute a user's pro-rated share of a batch
swap at a given block.

For that reason, it is important the output data used in the proof be
correct. A swap claim must be bound to the specific BSOD that was
produced by that user's swap.

The swap claim circuit's validation only checked that the supplied BSOD
was produced at the same relative block height as the user's swap. It
did not check that the epochs were the same. As a result, it was
possible to generate swap claim proofs using a BSOD produced during a
different epoch, on potentially much more advantageous terms.


## Issue ticket number and link

## Checklist before requesting a review

- [x] If this code contains consensus-breaking changes, I have added the
"consensus-breaking" label. Otherwise, I declare my belief that there
are not consensus-breaking changes, for the following reason:

  > This is consensus breaking

---------

Co-authored-by: Lucas Meier <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
consensus-breaking breaking change to execution of on-chain data state-breaking breaking change to on-chain data
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

7 participants