Skip to content
This repository has been archived by the owner on Aug 23, 2020. It is now read-only.

White flag #1806

Open
wants to merge 8 commits into
base: white-flag
Choose a base branch
from
Open

White flag #1806

wants to merge 8 commits into from

Conversation

acha-bill
Copy link
Contributor

@acha-bill acha-bill commented Mar 20, 2020

Description

Ability to confirm conflicting bundle while applying only the first to the ledger.
The order of bundles is determined by a topological sort via DFS preferring trunk first.

Fixes #1684

Type of change

  • Enhancement (a non-breaking change which adds functionality)

How Has This Been Tested?

  • Existing unit and regression tests pass
  • Added new regression test where a milestone approves 2 double-spend bundles and asserts that even though only 1 affects the ledger, they are both confirmed.

Checklist:

  • My code follows the style guidelines for this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

return null;
}
if (!milestoneService.isTransactionConfirmed(transactionViewModel, milestoneIndex)) {
Stack<Hash> stack = new Stack<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Please implement stack with a Deque
It is a much more efficient implementation...
Stack relies on Vector which is quite obsolete

See the javadocs of the Stack class:

* <p>A more complete and consistent set of LIFO stack operations is
 * provided by the {@link Deque} interface and its implementations, which
 * should be used in preference to this class.  For example:
 * <pre>   {@code
 *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>

if(isConsistent){
state = currentState;
}else{
transactionViewModel.isConflicting(tangle, initialSnapshot, true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you change to setConflicting

is is the prefix of a boolean java getter

final Hash address = bundleTransactionViewModel.getAddressHash();
final Long value = currentState.get(address);
currentState.put(address, value == null ? bundleTransactionViewModel.value()
: Math.addExact(value, bundleTransactionViewModel.value()));
Copy link
Contributor

Choose a reason for hiding this comment

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

If an overflow exception is thrown here then we would like to make sure the bundle is ignored

/**
* This flag indicates whether the transaction is conflicting and was ignored in balance computation
*/
public boolean conflicting = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Since you branched off dev this is correct
But we know that soon this should turn Atomic or volatile
So might as well do it now so we won't forget...

Technically volatile suffices here but since in 1.9.0 we made everything Atomic we made as well make it atomic


boolean approvedTrunk = (trunk.snapshotIndex() > 0) && (trunk.snapshotIndex() != milestoneIndex);
boolean approvedBranch = (branch.snapshotIndex() > 0) && (branch.snapshotIndex() != milestoneIndex);
if ((trunk.isEmpty() || visitedTransactions.contains(trunk.getHash()) || approvedTrunk) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

One should note that an empty transaction is the same as the genesis transaction (genesis transaction has all 9's trytes, and all 9s Hash). Then it is fine...

If the transaction was empty because the trunk tx is simply missing (not solid) then we have a problem...

I know you went according to the RFC, I just added a comment on it as well...

Comment on lines 882 to 889
/**
* Checks if a transaction is empty.
* @return True if empty. False otherwise.
*/
public boolean isEmpty(){
return Arrays.equals(getBytes(), new byte[SIZE]);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Currently we are just check for TransactionViewModel.PREFILLED_SLOT
I am not saying that this is smart (I didn't make this weird design)

But it will be more awful if we have more than one way to do this check...
So I wouldn't have this method now

Copy link
Contributor

@DyrellC DyrellC left a comment

Choose a reason for hiding this comment

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

Just the one comment about labelling/commenting, otherwise it looks like it passes muster. The updated regression test is a nice touch as well.


boolean approvedTrunk = (trunkTransactionViewModel.snapshotIndex() > 0) && (trunkTransactionViewModel.snapshotIndex() != milestoneIndex);
boolean approvedBranch = (branchTransactionViewModel.snapshotIndex() > 0) && (branchTransactionViewModel.snapshotIndex() != milestoneIndex);
if ((trunkTransactionViewModel.getType() == TransactionViewModel.PREFILLED_SLOT || visitedTransactions.contains(trunkTransactionViewModel.getHash()) || approvedTrunk) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps providing labels for these conditions as booleans instead of rewriting them in the if and else statements here could help to declutter this section. There are a lot of conditions being thrown around very close together here that could make it harder to follow. For example another boolean for each the trunk and branch types to be reused below in the else statement. More descriptive labels or a few extra comments could go a long way towards making the logic easier for others to follow.

Copy link
Contributor

@GalRogozinski GalRogozinski left a comment

Choose a reason for hiding this comment

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

Some more changes please

Comment on lines 180 to 181
boolean isLeafTrunk = isEmptyTrunk || visitedTransactions.contains(trunkTransactionViewModel.getHash()) || isApprovedTrunk;
boolean isLeafBranch = isEmptyBranch || visitedTransactions.contains(branchTransactionViewModel.getHash()) || isApprovedBranch;
Copy link
Contributor

Choose a reason for hiding this comment

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

hmm I think that here we let way for confirming non solids...
I am pretty sure that if we reach an empty trunk it means we have a non-valid subtangle

The exception here is that if it is the genesis transaction, then it should be fine (but tip-sel should not allow it and we should test for it)

@@ -87,3 +87,47 @@ Feature: Test transaction confirmation
| keys | values | type |
| states | False | boolListMixed |

Scenario: Conflicting bundles are ignored
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a scenario for invalid bundles

Copy link
Contributor

Choose a reason for hiding this comment

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

Already done in my PR, theyre in the disabled regression tests file in machine 3

Copy link
Contributor

Choose a reason for hiding this comment

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

was just about to tag you here @kwek20 but I see you are very alert :-)

Comment on lines 179 to 189
//Don't confirm non-solid txs.
Hash genesisHash = Hash.NULL_HASH;
if(isEmptyTrunk && !allowGenesisReference){
return null;
}
//proceed only if empty trunk or branch is genesis
if((isEmptyTrunk && !trunkTransactionViewModel.getHash().equals(genesisHash))||
(isEmptyBranch && !branchTransactionViewModel.getHash().equals(genesisHash))){
return null;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. In the event that trunk or branch have a non 9s hash then this is wrong
  2. I believe (I think I missed it in the last review so my bad) that the 9s genesis hash is in the solidEntryPointsSet

So I think the flag is unnecessary (because we should always allow genesis reference)
I think we should always return null if it is PREFILLED_SLOT

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since we return null if branch or trunk is PREFILLED_SLOT.
Is this the only definition of a leaf?

boolean isLeafTrunk = visitedTransactions.contains(trunkTransactionViewModel.getHash()) || isApprovedTrunk;

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, when visitedTransactions contain all SEPs and genesis

Copy link
Contributor

@GalRogozinski GalRogozinski left a comment

Choose a reason for hiding this comment

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

I was having one last look before publishing this on Discord.

I think you can still take the opportunity to:

  1. Extract private methods to make generateBalanceDiff more readable
  2. Add a unit test that mocks a tangle with conflicts and generates the balance diff

No need to rush to do it this sprint because we might get external feedback

}else if(!isLeafBranch) {
stack.addFirst(branchTransactionViewModel.getHash());
}
}catch(Exception e){
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
}catch(Exception e){
} catch(Exception e) {

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants