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

[gateway api] Replace TransactionSigner with two steps call #897

Merged
merged 4 commits into from
Mar 23, 2022

Conversation

patrickkuo
Copy link
Contributor

@patrickkuo patrickkuo commented Mar 17, 2022

We are replacing TransactionSigner with two steps call.

The reason of this change is to simply the mechanism of acquiring signatures, TransactionSigner's signature callback is hard to implement for the rest server without using rest server callback. The new 2 steps structure will be much easier to implement across the rest boundaries.

Changes to the Gateway API

  • Instead of passing in a transaction signer, we have now split the transaction process into 2 parts.
  • All of the function in GatewayAPI which require signature will return TransactionSignatureRequest instead of executing the transaction, the function call will create the TransactionData, register it in the GatewayState and return a TransactionSignatureRequest object to the client.
  • The client is expected to create a signature using their key, with the TransactionData or TransactionDigest included in the TransactionSignatureRequest and return it to the GatewayAPI using the execute_transaction function
  • A new API method execute_transaction is added to execute the registered transaction.
  • Added enum TransactionResponse, for different response type for different transaction kind.
  • Added SplitCoin and MergeCoin to TransactionKind, so they can have their own response type.

@patrickkuo patrickkuo requested a review from arun-koshy March 17, 2022 16:06
@patrickkuo patrickkuo force-pushed the pat/gateway_api_signature_request branch from 3f7bd11 to 3cb73e4 Compare March 17, 2022 16:35
@patrickkuo patrickkuo self-assigned this Mar 17, 2022
@patrickkuo patrickkuo marked this pull request as ready for review March 17, 2022 16:59
let signature = tx_signer.sign(&owner, sig_req.data).await?;
Ok(state
.gateway
.execute_transaction(sig_req.digest, signature)
Copy link
Contributor

Choose a reason for hiding this comment

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

We will be passing this from the wallet application to the rest server. So just want to confirm, are both the signature and the sig_req.digest safe to transfer over the wire?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes it's cryptographically safe

@patrickkuo patrickkuo requested a review from oxade March 18, 2022 11:28
@patrickkuo patrickkuo force-pushed the pat/gateway_api_signature_request branch from 3cb73e4 to 0725325 Compare March 18, 2022 19:55
@lxfind
Copy link
Contributor

lxfind commented Mar 19, 2022

Sorry for the late review! Thanks for looking into simplifying the signature process.
I have two high-level questions about this change:

  1. Can we live without adding two new variants in TransactionKind that's essentially special cases of MoveCall? It seems like you want to distinguish among the different request intent called on the GatewayAPI. For that, I believe the proper approach would be to introduce enums just for the various request types, which wraps the transaction data in it, so that you can keep the request kinds and transaction kinds separate (they can map to each other in arbitrary ways).
  2. Given the direction we are going, it seems less and less meaningful for the GatewayAPI to actually receive requests on each individual kinds (move_call, transfer, publish and etc.) just to package them up and return the transaction for the caller to sign. Should the caller just package a transaction themselves, sign them and send to GatewayAPI? We could add a library for applications to use to package transactions through a list of standard APIs, so they could package the transaction locally. This is just a thought, may be something worth asking/flagging in the slack channel to get more eyes on this (and if we go this route, we don't even need to discuss (1)).

@patrickkuo
Copy link
Contributor Author

Sorry for the late review! Thanks for looking into simplifying the signature process. I have two high-level questions about this change:

  1. Can we live without adding two new variants in TransactionKind that's essentially special cases of MoveCall? It seems like you want to distinguish among the different request intent called on the GatewayAPI. For that, I believe the proper approach would be to introduce enums just for the various request types, which wraps the transaction data in it, so that you can keep the request kinds and transaction kinds separate (they can map to each other in arbitrary ways).

I try not to introduce yet another enum and layer, hence the changes in TransactionKind; If this is not desirable, I can add a new GatewayRequestType enum for this.

  1. Given the direction we are going, it seems less and less meaningful for the GatewayAPI to actually receive requests on each individual kinds (move_call, transfer, publish and etc.) just to package them up and return the transaction for the caller to sign. Should the caller just package a transaction themselves, sign them and send to GatewayAPI? We could add a library for applications to use to package transactions through a list of standard APIs, so they could package the transaction locally. This is just a thought, may be something worth asking/flagging in the slack channel to get more eyes on this (and if we go this route, we don't even need to discuss (1)).

I have suggested this approach last time we discuss Gateway architecture, the conclusions I had after some thoughts are:

1, All of the transaction require ObjectRef as input, if we build the transaction on the application side, the application will need to do multiple calls to fetch the latest ObjectRef to build the transaction.

2, We will need to provide and maintain libs, potentially for many different languages to creating the transaction locally to ensure the serialisation will create the same bytes (we use BCS), otherwise it will result in different hash and invalid signature. In this PR I have included TransactionDigest in TransactionSignatureRequest, the application can use the digest bytes to create signature without BCS or Sui lib via rest.

@patrickkuo patrickkuo force-pushed the pat/gateway_api_signature_request branch from 2261a44 to 7eddb72 Compare March 20, 2022 00:23
address_states: BTreeMap<SuiAddress, AccountState>,
unsigned_tx: BTreeMap<TransactionDigest, (TransactionData, GatewayRequestType)>,
Copy link
Contributor

Choose a reason for hiding this comment

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

This worries me. It creates a way for people to DDos our storage: just keep sending tx without signing it, this table will continue to grow.
I assume this is added as an optimization to reduce the size of the second request? Although we will need to optimize it in some way, it may be better to leave that out for simplicity at the moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not just an optimisation to reduce size, it also make the rest request a lot simpler, malicious actor will need to try different combination of objects to create unique transactions with different digest, so the grow of this map should be limited, having said that, I am happy to remove it for now to make it safer.

Thinking more about DDoS... current implementation of gateway will allow read access without proof of key ownership, which will allow DDoS and address_states can grow infinitely, we need to think about authentication in the gateway service.

Copy link
Contributor

Choose a reason for hiding this comment

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

A user can submit a Move Call request, and simply mutating one pure argument from 0,1,... and can easily create infinite number of unique transactions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh of cause, I was only thinking about transfers 🤦🏻‍♂️, thanks!

@patrickkuo patrickkuo force-pushed the pat/gateway_api_signature_request branch 2 times, most recently from 5315417 to aa125d0 Compare March 21, 2022 16:15
Copy link
Contributor

@lxfind lxfind left a comment

Choose a reason for hiding this comment

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

Also, you may consider moving the to_response functions to the gateway_responses.rs

* Instead of passing in a transaction signer, we have now split the transaction process into 2 part.
* the first call will create the `TransactionData`, register it in the `GatewayState` and return a `TransactionSignatureRequest` object to the client
* The client is expected to create a signature using their key, with the `TransactionData` or `TransactionDigest` included in the `TransactionSignatureRequest`
* A new API method `execute_transaction` is added to execute the registered transaction.
* removed TransactionSignatureRequest
* removed AsyncTransactionSigner
* removed unsigned_tx from GatewayState
@patrickkuo patrickkuo force-pushed the pat/gateway_api_signature_request branch from a9a645c to 6714d9c Compare March 22, 2022 22:41
@patrickkuo
Copy link
Contributor Author

I have further simplified the changes!

  • execute_transaction now takes Transaction object as input, which can be constructed on the client side.

  • removed unsigned_tx from GatewayState as it is unsafe

  • transfer_coin, publish ... methods in GatewayAPI now returns TransactionData
    (we don't really need these apis anymore as suggested by @lxfind , application can use TransactionData::new_transfer etc to create transaction data, will leave the refactoring to next PR as there are a lot of effort refactoring all the tests)

  • Removed GatewayRequestType enum, request types can be determined by examining the TransactionData

  • removed TransactionSigner

Copy link
Contributor

@lxfind lxfind left a comment

Choose a reason for hiding this comment

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

Looking good. Thanks!

@patrickkuo patrickkuo merged commit 17f2056 into main Mar 23, 2022
@patrickkuo patrickkuo deleted the pat/gateway_api_signature_request branch March 23, 2022 01:25
stella3d pushed a commit that referenced this pull request Mar 23, 2022
* Changes to the Gateway API
* Instead of passing in a transaction signer, we have now split the transaction process into 2 part.
* the first call will create the `TransactionData`, register it in the `GatewayState` and return a `TransactionSignatureRequest` object to the client
* The client is expected to create a signature using their key, with the `TransactionData` or `TransactionDigest` included in the `TransactionSignatureRequest`
* A new API method `execute_transaction` is added to execute the registered transaction.

* * simplified GatewayAPI
* removed TransactionSignatureRequest
* removed AsyncTransactionSigner
* removed unsigned_tx from GatewayState

* fixup after rebase

* minor refactoring
mwtian pushed a commit that referenced this pull request Sep 12, 2022
We generally set a special logging level for networking libraries in
both production and tests. This PR puts quinn messages (including
somewhat verbose spans) under that logging level.
mwtian pushed a commit to mwtian/sui that referenced this pull request Sep 29, 2022
…tenLabs#897)

We generally set a special logging level for networking libraries in
both production and tests. This PR puts quinn messages (including
somewhat verbose spans) under that logging level.
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.

3 participants