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

Introduce TxInput::OrderAccountCommand without nonces #1888

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

azarovh
Copy link
Member

@azarovh azarovh commented Feb 28, 2025

  • Filled amount is now calculated based on the original ask/give price. This makes fill operations commutative. Though it has a negative consequence as potential remainder amounts, resulting in dust utxos produced on conclude, I don't think it's a major problem.

  • It is forbidden to fill order with 0 to enforce spending utxo in a tx making it unique and not replayable.

  • Nonce for AccountCommand::FillOrder is ignored. This is a bit hacky because nonce is still present making it confusing. But I think that this is more like an exception and refactoring out nonce from TxInput::AccountCommand seems like not worth it.

  • Nonce for AccountCommand::ConcludeOrder is kept. Also I'm planning to keep it for the upcoming AccountCommand::FreezeOrder. Though it seems like it can be removed I don't see a point in doing it.

  • Ignoring nonce forced me to add fork logic to TransactionVerifier::disconnect_transaction function because we don't need to decrement nonce for fill orders after the fork.

  • Same fork logic goes into api-server and wallet. Though for wallet it required changing OutputCache logic which looks messy and I'm don't quite like it (alternative solution below can fix that).

UPDATE:

  • Introduced new TxInput::OrderAccountCommand with FillOrder and ConcludeOrder commands.
  • Nonces for OrderAccountCommand are completely removed.
  • OrderAccountCommand::ConcludeOrder now contains remaining amounts that can be withdrawn from an account so that these amount can be used by hw wallet and also get into a signature. Also these amounts are checked in TransactionVerifier

@azarovh azarovh force-pushed the fix/fill_order_no_nonce branch from fcf7fc6 to b6d9b5d Compare March 4, 2025 15:58
@azarovh azarovh force-pushed the fix/fill_order_no_nonce branch from 6e4bf6f to 461b8fa Compare March 5, 2025 10:44
@azarovh azarovh changed the title Ignore nonces in fill order operations Introduce TxInput::OrderAccountCommand without nonces Mar 5, 2025
@azarovh azarovh force-pushed the fix/fill_order_no_nonce branch from b558f29 to 8c03c73 Compare March 5, 2025 13:35
@azarovh azarovh marked this pull request as ready for review March 5, 2025 13:45
@azarovh azarovh force-pushed the fix/fill_order_no_nonce branch from 8c03c73 to 816b30b Compare March 5, 2025 15:41
@azarovh azarovh force-pushed the fix/fill_order_no_nonce branch from 7791573 to b8a6529 Compare March 10, 2025 14:05
Comment on lines +201 to +202
filled_amount: Amount,
remaining_give_amount: Amount,
Copy link
Member Author

@azarovh azarovh Mar 18, 2025

Choose a reason for hiding this comment

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

I will remove these fields if we go with OrderData in the signature

Copy link
Member Author

Choose a reason for hiding this comment

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

Seems like I cannot do that because OrderData does not contain current balances

Copy link
Contributor

@ImplOfAnImpl ImplOfAnImpl left a comment

Choose a reason for hiding this comment

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

Do we have a test for the case when an order is created and partially filled before the upgrade and then filled again and concluded after?

Comment on lines +870 to +881
let ask = match order.ask_currency {
CoinOrTokenId::Coin => OutputValue::Coin(order.initially_asked),
CoinOrTokenId::TokenId(token_id) => {
OutputValue::TokenV1(token_id, order.initially_asked)
}
};
let give = match order.give_currency {
CoinOrTokenId::Coin => OutputValue::Coin(order.initially_given),
CoinOrTokenId::TokenId(token_id) => {
OutputValue::TokenV1(token_id, order.initially_given)
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Add method fn from_output_value(&self, Amount) to CoinOrTokenId?

Comment on lines +642 to +647
match order.ask_currency {
CoinOrTokenId::Coin => {}
CoinOrTokenId::TokenId(id) => {
token_ids.insert(id);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

This match is repeated in many places. Maybe add a method CoinOrTokenId::token_id(&self) -> Option<TokenId>?

Or maybe 2 separate ones: token_id(&self) -> Option<&TokenId> and into_token_id(self) -> Option<TokenId>.

@@ -646,6 +646,7 @@ fn update_statistics(
}
AccountCommand::ConcludeOrder(_) | AccountCommand::FillOrder(_, _, _) => {}
},
TxInput::OrderAccountCommand(..) => {}
Copy link
Contributor

Choose a reason for hiding this comment

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

So I guess these tests don't currently use OrderAccountCommand?

Comment on lines 70 to +72
.add_input(
TxInput::AccountCommand(
AccountNonce::new(0),
AccountCommand::FillOrder(
order_id,
Amount::from_atoms(1),
Destination::AnyoneCanSpend,
),
),
TxInput::OrderAccountCommand(OrderAccountCommand::FillOrder(
order_id,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not parameterize this test to check both old and new commands?

"command": "FillOrder",
"order_id": Address::new(chain_config, *id).expect("addressable").to_string(),
"fill_atoms": json!({"atoms": fill.into_atoms().to_string()}),
"destination": Address::new(chain_config, dest.clone()).expect("no error").as_str(),
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO we should try to get rid of all these optimistic expects in the API server and propagate errors correctly.
A good rule might be that if you're going to add a new "expect", you should consider changing the function to return a proper Result and fix the existing "expect"s as well.

I'm not insisting on doing it right now, just a thing to consider.

(If you keep the "expect"s, plz at least use consistent messages)

@@ -47,6 +47,8 @@ pub enum Error {
OrderOverflow(OrderId),
#[error("Order `{0}` can provide `{1:?}` amount; but attempted to fill `{2:?}`")]
OrderOverbid(OrderId, Amount, Amount),
#[error("Order `{0}` provides amount `{1:?}` that is not enough to fill even a single coin")]
Copy link
Contributor

Choose a reason for hiding this comment

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

coin -> atom?

@@ -146,6 +146,10 @@ impl From<chain::TxInput> for crate::TxInput {
chain::TxInput::AccountCommand(nonce, command) => {
Self::AccountCommand(nonce.value(), command.into())
}
chain::TxInput::OrderAccountCommand(_) => {
//TODO: support OrdersVersion::V1
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess this should be put into #1887

Or maybe some other issue

Comment on lines +986 to +992
let version = self
.chain_config
.chainstate_upgrades()
.version_at_height(self.account_info.best_block_height())
.1
.orders_version();

Copy link
Contributor

Choose a reason for hiding this comment

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

Tecnically, this can be "best_block_height + 1", because when the tx is mined, the upgrade height will be reached. (Unless a reorg occurs and the tx gets mined at a lower height, but I guess this is always possible).

Comment on lines +2597 to +2598
let filled_amount = orders_accounting::calculate_filled_amount(
order_info.ask_balance,
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably it's better to use initially_asked/initially_given here and/or assert that they equal ask_balance/give_balance?

@@ -291,42 +291,13 @@ async fn into_utxo_and_destination<T: NodeInterface, B: storage::Backend>(
(None, TxAdditionalInfo::new(), dest)
}
TxInput::AccountCommand(_, cmd) => {
// find authority of the token
// find authority of the order
Copy link
Contributor

Choose a reason for hiding this comment

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

The comment is still weird.

"find a destination associated with the order" would make more sense (not sure if it's useful though)

@azarovh azarovh marked this pull request as draft March 25, 2025 08:10
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.

None yet

2 participants