-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Add auto-confirm feature for Monero #4458
Add auto-confirm feature for Monero #4458
Conversation
Main part missing is the XMR proof service request processing. I did not get the service compiled yet, so could not test response data and error conditions. Further it is missing a "news badge" and popup to guide the user to the new feature. Only basic dev tested so far. Anyone welcome to pick the project up from here as I might not have time soon to continue.
* XMR seller is prompted to enter txId and viewkey. * looks up the XMR transaction to verify that it has confirmed * user can run their own validating service, or use the ones provided * 100% agreement of all chosen services is necessary for confirmation * feature can be configured and turned on/off from settings screen * feature can be globally turned off via admin filter * two code review passes from chimp1984 * one text review from m52go
Auto confirmed trades will be indicated as such on Trade details.
Co-authored-by: m52go <[email protected]>
Co-authored-by: m52go <[email protected]>
…sult instead which stores the stateName. [1] - Adjust protobuf methods - Add UNDEFINED to AutoConfirmResult.State to support cases where we get no data to set the enum. - Add NO_MATCH_FOUND (used in follow up commits) - Refactoring: Improve constructors [1] Enums in protobuf are not well supported. They are global so an enum with name (e.g. State) inside Trade conflicts with another enum inside Message with the same name. So they do not reflect encapsulation in the class like in java. We moved over time to the strategy to use strings (from enum.name()) instead of the enum, avoiding also cumbersome fromProto and toProto code and being more flexible with updates. The autoConfirmResultState enum inside Trade was a bit confusing to me as it was a different structure as in the java code. We try to mirror the structure as far as possible.
- Add case if no match is found -> NO_MATCH_FOUND. - Add test case for NO_MATCH_FOUND - Add curley brackets to one liners - Log improvements
- Replace httpClient.toString() with httpClient.getBaseUrl() as toString would deliver too much for those use cases. - Add @nullable - Log improvements
to add auto confirm for other currencies in the future. The generic part is only used where we would have issues with backward compatibility like in the protobuf objects. Most of the current classes are kept XMR specific and could be generalized once we add other assets, but that would be an internal refactoring without breaking any network or storage data. I think it would be premature to go further here as we don't know the details of other use cases. I added the methods used from clients to AutoConfirmResult, not sure if the API is well defined by that, but as said that could become subject of a future refactoring once another auto confirm feature gets added. Goal of that refactoring was to avoid that we need more fields for trade and the the UI would have to deal with lots of switch cases based on currency. Sorry that is a larger commit, would have been hard to break up...
classes and renamed package and adjusted access modifiers.
Move to convertToRawHex CryptoNoteUtils as well as the classes inside the validator.
getter from tradeManager. Avoids boilerplate code (I know there is more in the existing code to optimize here ;-))
For tradeStateListener that would cause a wrong state as we would get called after we have completed and do the isPayoutPublished check. Keeping it in sync does remove the listener before we complete the trade. For autoConfirmSettings it would probably not cause and issue but as we use a CopyOnWriteArrayList there the remove is safe anyway (to not cause a ConcurrentListModification exception).
Use the AssetTxProofHttpClient as injected param instead of parser. Helpful for dev testing with mocked json response.
to HttpClient. Use interface instead of class as type. Add default guice binding to HttpClientImpl for HttpClient (not singleton!)
Tested sequence: 1. waiting for response 2. receive TX_NOT_FOUND 3. receive PENDING_CONFIRMATIONS with 0 conf counting up to defined requiredConf 4. success once required confs reached - Fix bug with missing persist call - Revert PENDING results to null when read from persistence as we dont want to show latest pending state. - Remove unused API_FAILURE
I am complete with dev testing so far. Here an overview and hints for testing. Specification: There is a news badge and a popup informing about the new feature. By default it is disabled and filled with 1 BTC trade amount limit (auto confirm only used for trades up to 1 BTC), 5 required confirmations and the default service addresses (onion addresses for tor, clearnet for localhost dev testing). Atm there is only 1 service (from @Emzy) but @wiz has started to setup a service as well, so there will be 2 services soon. The user can change the service address (not containing 'http://') but cannot leave it empty, in that case it will be refilled with default values at focus out. The required confirmations are only written at focus out as well to avoid unintended values (those are read just in time at service response). The min number of success results it the number of services defined, so by default 2. The Seller will see a new text field in the trade screen with the auto-confirm status. Initially the expected state is "Proof requests started". After a response it will show either the number of confirmations or "Transaction not seen in mem-pool yet". Once number of confirmations are >= required the service has completed with success (assuming all data are valid and proof was valid). If anything is incorrect or a connection problem the auto-conf fails (1 error or failure of any servive will terminate all). Failures do not mean that the tx was invalid, the user need to check manually in that case. As long the tx is not in the mempool or the required confirmations are not reached we are in pending state and show how many services have succeeded and how many confirmations the tx has. It might be that both services report a diff. number of confirmations, in that case the last update is visible to the user. We do not have enough space in the UI to show the data per service but combine all in 1 text field. As long we are in that pending state the services get requested every 90 seconds for max. 12 hours. After 12 hous without success it has failed. There is a new entry in filter to block the auto-confirm feature. If that is set, no new service can be started and existing ones get terminated. The settings UI get disabled as well. If filter gets removed or the flag reset we do not restart the pending trades, only at restart they request again. How to test the feature? If devMode is enabled dev values for txId txKey, xmr receiver address and amount are fixed set. With that you will always receive a success result from the service. Those dev test data are in XmrTxProofModel and can be changed to different ones. To test different states is a bit tricky and requires hacking a bit into the code.
There is a unit test for the parser. No integration test for the whole feature, would be quite a bit of effort and challenge. EDIT: Just added support to listen on filter changes and adjusted text. |
disable settings UI if auto-conf is disabled in filter.
…-key-service-3 # Conflicts: # desktop/src/main/java/bisq/desktop/main/MainView.java # desktop/src/main/java/bisq/desktop/main/MainViewModel.java
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.
utACK/ACK
Tested it roughly on Regtest, but will test it in more detail during release testing.
@m52go Could you add the content to the wiki about auto-conf (https://bisq.wiki/Trading_Monero#Auto-confirming_trades)? |
Updated, feedback welcome: Will take it out of draft status shortly so it's online when the new release is available. |
Code review of onion-monero-blockchain-explorerThe purpose of this review is to determine if using this explorer to validate receipt of XMR funds poses any risk. The tldr;
BackgroundTwo instances of the explorer are hosted by Bisq ops team and queried from around the globe by Bisq clients that have opted-in to the XMR tx auto confirm feature. The feature removes the need for an XMR buyer to manually check that their wallet has received the funds, allowing those trades to complete automatically, paying out the BTC funds from the multisig. How could an attacker use this tool to defraud? An attacker in this case would be an XMR seller who does not actually send the funds or the correct amount of funds. The explorer could indicate that funds have been sent to the queried address when indeed they have not. But the explorer does not know what amount the user is expecting to receive so if it is to falsify the results it must have a way of knowing the amount to send in the response back to the client. (only an address, txId and viewkey are provided to the API call). So there would have to be a specific trigger to cause the fake result (expected amount) to be sent. The amount could be encoded into a fake txId/viewkey. The attacker would generate the txId/viewkey in such a way that they are recognizable as such by the explorer, encoding the correct amount inside. The explorer could extract the amount, returning a success status with amount back to the user. Or an old transaction could be used which has a matching amount, which the malicious explorer code would modify to look like a new transaction. Either way, if there was malicious code included in Code walk-through of the APIThe onion-monero-blockchain-explorer is built using the monero LMDB library for interfacing to the blockchain. Interface to the monero library is via MicroCore.h which provides methods: The
It calls xmreg::parse_str_secret_key with tx_hash_str and does the same with viewkey_str. parse_str_secret_key() calls parse_hash256 which is part of the monero library. It converts a hex string hash to binary data. It calls xmreg::parse_str_address with address_str which in turn calls get_account_address_from_str() in the monero library. Next it looks for the tx_hash in the mempool or blockchain ( If not found in the blockchain, the mempool is checked via Next, it calls Next, it iterates over each output from the transaction details (output_pub_keys). For each output, it includes in the json data returned to caller: "output_pubkey","amount","match","output_idx". "match" is set to true if the "output_pubkey" matches the supplied decoded address (i.e. is the user's address) The "tx_timestamp" is obtained from the transaction's block if present in a block, or the mempool. tx_hash", "address", "viewkey", and "tx_prove" are pulled from data structures used above and returned to the caller in the json. "tx_confirmations" is pulled from the transaction details object and returned in the json. ConclusionNo malicious code found. See tldr; above. |
@jmacxx I had a quick look through onion-monero-blockchain-explorer as well and came to the same conclusion. I think there is minimal risk using it right now. The main risk would be future updates to that code as it's now known how bisq uses it. Since auto confirm users won't rely on random explorers but rather federated bisq explorers, or better, their own, I see that as a small risk. Any update to the federated explorers would have to be reviewed though, and we should let users know which version is used by the federated node operators. That way they can have some confidence that it's a good version if they choose to install it themselves. |
Good point regarding updates. |
I am complete with dev testing so far. Here an overview and hints for testing.
Specification:
This feature is only visible for XMR trades.
BTC buyer gets a new popup at payment sent button click asking for entering the XMR tx ID and XMR tx key. He can either enter valid 32byte hex strings (input validation used) or leave the fields empty. If he leaves one or both empty another popup will ask him if he is sure and give info about the requirements to provide those date in dispute case and that the peer cannot do auto-confirm if he does not provide it. But we do not enforce it. There might be users who sent from a wallet not supporting tx keys but as reciver gets the XMR there is no dispute and no follow-up problems. If we would enforce it we would cause dispute cases for such situations.
The data is sent to the BTC seller inside the trade message. Once received he starts requesting from the service(s) for the tx proof if he has the feature enabled.
There is a news badge and a popup informing about the new feature. By default it is disabled and filled with 1 BTC trade amount limit (auto confirm only used for trades up to 1 BTC), 5 required confirmations and the default service addresses (onion addresses for tor, clearnet for localhost dev testing). Atm there is only 1 service (from @Emzy) but @wiz has started to setup a service as well, so there will be 2 services soon. The user can change the service address (not containing 'http://') but cannot leave it empty, in that case it will be refilled with default values at focus out. The required confirmations are only written at focus out as well to avoid unintended values (those are read just in time at service response). The min number of success results it the number of services defined, so by default 2.
The Seller will see a new text field in the trade screen with the auto-confirm status. Initially the expected state is "Proof requests started". After a response it will show either the number of confirmations or "Transaction not seen in mem-pool yet". Once number of confirmations are >= required the service has completed with success (assuming all data are valid and proof was valid). If anything is incorrect or a connection problem the auto-conf fails (1 error or failure of any servive will terminate all). Failures do not mean that the tx was invalid, the user need to check manually in that case.
As long the tx is not in the mempool or the required confirmations are not reached we are in pending state and show how many services have succeeded and how many confirmations the tx has. It might be that both services report a diff. number of confirmations, in that case the last update is visible to the user. We do not have enough space in the UI to show the data per service but combine all in 1 text field. As long we are in that pending state the services get requested every 90 seconds for max. 12 hours. After 12 hous without success it has failed.
Once all services have succeeded the auto confirmation will get triggered. The trade is closed and in the UI there is an auto-confirmed badge. The state of the auto conf is also visible in the trade details window. The state gets persisted with the trade but in case if PENDING we reset the state when reading the persisted file as it does not make sense to show PENDING in that case. At startup the service will get started automatically in case the trade has not completed in the meantime. If the user clicks manually the confirm button the service will get stopped and the trade completes normally.
If the user updates the required confirmations in settings, this new value will be used at the next response. Also disabling the service in settings cause terminating all services. They will not be restarted if the user enables again. Only after restart the service requests will start again.
All other values in the settings are not applied on running services and changes only have effect at new trades or at a restart.
There is a new entry in filter to block the auto-confirm feature. If that is set, no new service can be started and existing ones get terminated. The settings UI get disabled as well. If filter gets removed or the flag reset we do not restart the pending trades, only at restart they request again.
How to test the feature?
If devMode is enabled dev values for txId txKey, xmr receiver address and amount are fixed set. With that you will always receive a success result from the service. Those dev test data are in XmrTxProofModel and can be changed to different ones.
To test with real values you have to disable devMode.
To test different states is a bit tricky and requires hacking a bit into the code.
I will describe what I did for dev testing:
XmrTxProofRequest.REPEAT_REQUEST_PERIOD
from 90 sec to 5 secautoConfirmFiatPaymentReceived
inTradeManager
. This avoids that the trade gets completed and you don't need to create new trades all the time but can simply restart the app and test another scenario with the same trade.bind(AssetTxProofHttpClient.class).to(XmrTxProofHttpClient.class);
tobind(AssetTxProofHttpClient.class).to(DevTestXmrTxProofHttpClient.class);
There is a unit test for the parser. No integration test for the whole feature, would be quite a bit of effort and challenge.
EDIT: Just added support to listen on filter changes and adjusted text.