-
Notifications
You must be signed in to change notification settings - Fork 1k
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
"Conflicts" transaction attribute type #1991
Comments
There is a prototype now in nspcc-dev/neo-go#1507. The logic has been adjusted a bit to solve an attack possible with the following scenario: Alice signs transaction A and sends it to the network, then Bob sees this transaction in the mempool and immediately creates transaction B conflicting with A and paying higher fee. The original logic described here allowed to accept B in favor of A and if Bob has enough GAS he can effectively DoS Alice for as long as he wants to. So B has to be signed by Alice to prevent this, if it's not then B is invalid and A stays in the pool irrespective of B's fee. And we also effectively reserved version 255 for dummy conflicting transactions to check for conflicts/presence in the DB with one DB access (it can be done without that, but for now it's simpler this way). |
I think this is an interesting problem... instead of attributes, I'd always prefer to keep standard features, such as cosigners. |
This would mean that we have to reverify any non-standard script of any mempooled transaction for any transaction added to the pool. And functionally it only allows for transaction B to be invalid in presence of A, which is not enough, we need preemption guarantees if some conditions are met (like this doesn't allow to override any already sent but not yet accepted into block transaction).
Backup CNs will request txA from their peers and this transaction doesn't have to go through the mempool, so if it'll manage to arrive in time it's not a problem (at least for neo-go, but IIRC C# is also fine wrt this in the |
This is the same as current, will not increase number of validations: only new transactions would be validated, and previously validated are kept assumed as validated. Example: txA enters mempool (validation ok!); txB tries to enter mempool (validation fails because txA exists). From what you mentioned, some txC enters mempool, that is fine (no conflicts) with txA; but maybe txA is against existence of txC (not symmetric), is that the case? So, yes, in this case, both txA and txC would be on mempool, and only when puting to block, txA would "realize" that txC is also a candidate, thus being rejected (if txC has entered before). |
Consider txA and txB, txB does
Back to txA and txB from above, even if you're to do this block-level check, block B1{txA, txB} would be considered invalid, but block B2{txB, txA} is perfectly valid again, although it shouldn't be. All of this is not a problem when using Conflicts attribute.
Except they're not as we've discussed in #2017. Fees are being checked, but not witnesses. |
I hadn't realized that... so my final argument there may not be correct. For me, all witnesses are being rechecked in batch-mode before tx invocations. Anyway, if tx witness is currently stateless, there's really no need to re-check (but this proposal makes them stateful, so recheck is needed during block proposal/acceptance). I agree there are many challenging points here, because I'd much prefer having standard cosigners checks doing the job, than a new attribute for the same behavior. I'll try to better understand the expected behavior in your proposal, to try to sketch the same without a new attribute. |
We just need to check for conflicts (kinda similar to UTXO double spend check) and it's feasible, already implemented in neo-go.
That was one of the main conflicts to resolve for #1573, whether to leverage some witness script powers or to add attributes. Given the constraints we have I don't think it's possible to do that via witness scripts (and especially given that we don't want to parse scripts for some data we need), thus we've resorted to attributes and they're working fine for now. Though if you manage to do that it'd be interesting, of course. |
So, I think we may have a general strategy / pattern to follow in these situations... since transaction validation is intended to be stateless, we may resort to attributes in order to execute these stateful computation, but in quite constrained scenario. So, with this strategy in mind, I agree with you, it's better to have it as attribute then as cosigner script. |
* Payloads: implement Conflicts attribute Closes #1991. * Update src/Neo/Ledger/MemoryPool.cs * Fix conflicting tx fees accounting Fix the comment #2818 (comment). * Reformat code and improve variables naming Fix Vitor's comments. * Make comments more clear and adjust variables naming Fix Owen's feedback. * Fix Conflicts attribute verification Consider the case when transaction B has the hash of transaction A in the Conflicts attribute and transaction B is on-chain. Let the transaction C has the hash of transaction A in the Conflicts attribute. Then transaction C still should be able to pass verification and should be accepted to the subsequent block, because transaction A isn't on chain and transaction A will never be accepted. Thanks to Owen for testing, this case is described at the #2818 (review). The expected behaviour in the described case is that TXID-D and TXID-E will be successfully accepted to the mempool and to chain, because the conflicting TXID-A is not on chain (and it's OK that the hash of TXID-A is on-chain as the conflicting hash). * Fix formatting, comments and add a testcase for conflicting mempool txs * Add one more testcase for conflicting transactions Testcase provided by Vitor in #2818 (comment). * Implement economic adjustments for Conflicts attribute Transaction that conflicts with mempooled transactions have to pay larger network fee than the sum of all conflicting transactions in the pool that have the same sender as the newcomer. Port the nspcc-dev/neo-go#3031. * Remove Trimmed value * Check signers of on-chained conflict during new tx verification Fix the problem described in #2818 (review). During new transaction verification if there's an on-chain conflicting transaction, we should check the signers of this conflicting transaction. If the signers contain payer of the incoming transaction, then the conflict is treated as valid and verification for new incoming transaction should fail. Otherwise, the conflict is treated as the malicious attack attempt and will not be taken into account; verification for the new incoming transaction should continue in this case. * Properly handle duplicating Conflicts hashes from the persisted transactions * Store signers of all conflicting on-chain transactions with the same Conflicts attribute Store not only signers of the latest conflicting on-chain transaction, but signers of all conflicting transactions with the same attribute. * MemoryPool: consider signers intersection on Conflicts check This patch should be a part of fd1748d, but was accidentally skipped. This patch matches exactly the NeoGo behaviour that was added in nspcc-dev/neo-go#3061 and that was discussed earlier in #2818 (comment). Fix the issue described in #2818 (comment). Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> * MemoryPool: add test for on-chain conflict Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> * Clean using * Refactor Malicious_OnChain_Conflict test Move it to the UT_Blockchain.cs file and refactor it a bit to make it actually pass as expected. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> * Use Distinct to filter out duplicating conflicting on-chain signers Co-authored-by: Shargon <shargon@gmail.com> * Use HashSet as a container of conflicting hashes in the mempool Fix #2818 (comment). Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> --------- Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru> Co-authored-by: Shargon <shargon@gmail.com> Co-authored-by: Vitor Nazário Coelho <vncoelho@gmail.com> Co-authored-by: Jimmy <jinghui@wayne.edu>
Proposed attribute
This attribute makes the chain only accept one transaction of the two conflicting and adds an ability to give a priority to any of the two if needed. It's useful for solving such problems as:
User sending transactions like in Use consecutive tx.nonce, like counter #1502 (comment) would add "Conflicts Tx1" attribute to Tx2, "Conflicts Tx1, Conflicts Tx2" to Tx3 and "Conflicts Tx1, Conflicts Tx2, Conflicts Tx3" to Tx4, no matter which one is going to be relayed and added to the chain any of the other couldn't be reused because of the conflict
There is a short time window between transaction relaying and transaction acceptance, in some cases it could be used to cancel the transaction before it's accepted, to do that one sends new transaction that conflicts with the previous one, but has a higher network fee.
This is going to leveraged by P2P signature collection service from Network assistance for multisignature transaction forming #1573.
The attribute has Uint256 data inside of it containing the hash of conflicting transaction. It is allowed to have multiple attributes of this type.
During transaction processing additional actions are to be done for transactions containing attributes of this type:
if conflicting transaction is already on-chain, the transaction is rejected as invalid
if conflicting transaction is present in the mempool, then two transactions are compared for their network fees, the one with a bigger network fee wins, so the other one is either rejected as invalid (if it's not in the mempool) or evicted from the mempool and replaced by the new one
store dummy conflicting transactions in the DB to prevent conflicting ones from being accepted
Since this attribute incurs some additional processing overhead it may have an additional network fee.
Neo Version
Where in the software does this update applies to?
The text was updated successfully, but these errors were encountered: