diff --git a/dapps/valuetransfers/packages/tangle/output.go b/dapps/valuetransfers/packages/tangle/output.go index b2685d712930ba37fc59a26de829a109d46d24dc..3771a853ca8a912057c5a5e0afe6dfc5c25c3bcd 100644 --- a/dapps/valuetransfers/packages/tangle/output.go +++ b/dapps/valuetransfers/packages/tangle/output.go @@ -236,7 +236,7 @@ func (output *Output) ConsumerCount() int { return output.consumerCount } -// Preferred returns true if the output is considered to be the first valid spender of all of its Inputs. +// Preferred returns true if the output belongs to a preferred transaction. func (output *Output) Preferred() (result bool) { output.preferredMutex.RLock() defer output.preferredMutex.RUnlock() @@ -295,7 +295,7 @@ func (output *Output) setFinalized(finalized bool) (modified bool) { return } -// Finalized returns true, if the decision if this output is liked or not has been finalized by consensus already. +// Finalized returns true, if the decision if this output is preferred or not has been finalized by consensus already. func (output *Output) Finalized() bool { output.finalizedMutex.RLock() defer output.finalizedMutex.RUnlock() @@ -428,12 +428,17 @@ func (output *Output) ObjectStorageValue() []byte { balanceCount := len(output.balances) // initialize helper - marshalUtil := marshalutil.New(branchmanager.BranchIDLength + marshalutil.BOOL_SIZE + marshalutil.TIME_SIZE + transaction.IDLength + marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + balanceCount*balance.Length) + marshalUtil := marshalutil.New(branchmanager.BranchIDLength + 6*marshalutil.BOOL_SIZE + marshalutil.TIME_SIZE + transaction.IDLength + marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + balanceCount*balance.Length) marshalUtil.WriteBytes(output.branchID.Bytes()) marshalUtil.WriteBool(output.solid) marshalUtil.WriteTime(output.solidificationTime) marshalUtil.WriteBytes(output.firstConsumer.Bytes()) marshalUtil.WriteUint32(uint32(output.consumerCount)) + marshalUtil.WriteBool(output.Preferred()) + marshalUtil.WriteBool(output.Finalized()) + marshalUtil.WriteBool(output.Liked()) + marshalUtil.WriteBool(output.Confirmed()) + marshalUtil.WriteBool(output.Rejected()) marshalUtil.WriteUint32(uint32(balanceCount)) for _, balanceToMarshal := range output.balances { marshalUtil.WriteBytes(balanceToMarshal.Bytes()) @@ -462,6 +467,21 @@ func (output *Output) UnmarshalObjectStorageValue(data []byte) (consumedBytes in if err != nil { return } + if output.preferred, err = marshalUtil.ReadBool(); err != nil { + return + } + if output.finalized, err = marshalUtil.ReadBool(); err != nil { + return + } + if output.liked, err = marshalUtil.ReadBool(); err != nil { + return + } + if output.confirmed, err = marshalUtil.ReadBool(); err != nil { + return + } + if output.rejected, err = marshalUtil.ReadBool(); err != nil { + return + } output.consumerCount = int(consumerCount) balanceCount, err := marshalUtil.ReadUint32() if err != nil { diff --git a/dapps/valuetransfers/packages/tangle/tangle.go b/dapps/valuetransfers/packages/tangle/tangle.go index a6666558791b50333cc0a26e3d7a44664f05ff07..33772a148e94c7c492bc7f7efee450acf452d0b6 100644 --- a/dapps/valuetransfers/packages/tangle/tangle.go +++ b/dapps/valuetransfers/packages/tangle/tangle.go @@ -1264,6 +1264,7 @@ func (tangle *Tangle) bookTransaction(cachedTransaction *transaction.CachedTrans conflictingInputs := make([]transaction.OutputID, 0) conflictingInputsOfFirstConsumers := make(map[transaction.ID][]transaction.OutputID) + finalizedConflictingSpenderFound := false if !transactionToBook.Inputs().ForEach(func(outputID transaction.OutputID) bool { cachedOutput := tangle.TransactionOutput(outputID) defer cachedOutput.Release() @@ -1294,6 +1295,17 @@ func (tangle *Tangle) bookTransaction(cachedTransaction *transaction.CachedTrans conflictingInputsOfFirstConsumers[firstConsumerID] = append(conflictingInputsOfFirstConsumers[firstConsumerID], outputID) } + // check if any of the consumers were finalized already + if !finalizedConflictingSpenderFound { + tangle.Consumers(outputID).Consume(func(consumer *Consumer) { + if !finalizedConflictingSpenderFound { + tangle.TransactionMetadata(consumer.TransactionID()).Consume(func(metadata *TransactionMetadata) { + finalizedConflictingSpenderFound = metadata.Preferred() && metadata.Finalized() + }) + } + }) + } + // mark input as conflicting conflictingInputs = append(conflictingInputs, outputID) @@ -1357,16 +1369,18 @@ func (tangle *Tangle) bookTransaction(cachedTransaction *transaction.CachedTrans return true }) - // fork the conflicting transactions into their own branch - for consumerID, conflictingInputs := range conflictingInputsOfFirstConsumers { - _, decisionFinalized, forkedErr := tangle.Fork(consumerID, conflictingInputs) - if forkedErr != nil { - err = forkedErr + // fork the conflicting transactions into their own branch if a decision is still pending + if decisionPending = !finalizedConflictingSpenderFound; decisionPending { + for consumerID, conflictingInputs := range conflictingInputsOfFirstConsumers { + _, decisionFinalized, forkedErr := tangle.Fork(consumerID, conflictingInputs) + if forkedErr != nil { + err = forkedErr - return - } + return + } - decisionPending = decisionPending || !decisionFinalized + decisionPending = decisionPending || !decisionFinalized + } } transactionBooked = true diff --git a/dapps/valuetransfers/packages/tangle/tangle_test.go b/dapps/valuetransfers/packages/tangle/tangle_test.go index 8f5c8d26c46ebfd34206e925cfae33883a725ad9..5ee63e0fa7cef7b2c2dd9044c71588da49d77aef 100644 --- a/dapps/valuetransfers/packages/tangle/tangle_test.go +++ b/dapps/valuetransfers/packages/tangle/tangle_test.go @@ -106,7 +106,7 @@ func TestBookTransaction(t *testing.T) { transactionBooked, decisionPending, err := tangle.bookTransaction(cachedTransaction, cachedTransactionMetadata) require.NoError(t, err) assert.True(t, transactionBooked, "transactionBooked") - assert.False(t, decisionPending, "decisionPending") + assert.True(t, decisionPending, "decisionPending") // assert that branchID is the same as the MasterBranchID assert.Equal(t, branchmanager.MasterBranchID, txMetadata.BranchID())