diff --git a/dapps/valuetransfers/packages/tangle/events.go b/dapps/valuetransfers/packages/tangle/events.go index 73c81755e4ea7a3774af3a4fd9fb89eb6248a3cb..8194f08f1e9d8e2fe71bc17b0627e41cd276cf84 100644 --- a/dapps/valuetransfers/packages/tangle/events.go +++ b/dapps/valuetransfers/packages/tangle/events.go @@ -83,7 +83,7 @@ func newEvents() *Events { PayloadInvalid: events.NewEvent(cachedPayloadErrorEvent), PayloadUnsolidifiable: events.NewEvent(payloadIDEvent), TransactionReceived: events.NewEvent(cachedTransactionAttachmentEvent), - TransactionInvalid: events.NewEvent(cachedTransactionEvent), + TransactionInvalid: events.NewEvent(cachedTransactionErrorEvent), TransactionSolid: events.NewEvent(cachedTransactionEvent), TransactionBooked: events.NewEvent(transactionBookedEvent), TransactionPreferred: events.NewEvent(cachedTransactionEvent), @@ -141,6 +141,14 @@ func cachedTransactionEvent(handler interface{}, params ...interface{}) { ) } +func cachedTransactionErrorEvent(handler interface{}, params ...interface{}) { + handler.(func(*transaction.CachedTransaction, *CachedTransactionMetadata, error))( + params[0].(*transaction.CachedTransaction).Retain(), + params[1].(*CachedTransactionMetadata).Retain(), + params[2].(error), + ) +} + func cachedTransactionAttachmentEvent(handler interface{}, params ...interface{}) { handler.(func(*transaction.CachedTransaction, *CachedTransactionMetadata, *CachedAttachment))( params[0].(*transaction.CachedTransaction).Retain(), diff --git a/dapps/valuetransfers/packages/tangle/tangle.go b/dapps/valuetransfers/packages/tangle/tangle.go index 30482cd932047805bdb901381f793307f762009b..36ff6ad32096704a523428c88746c4c5e685b7a1 100644 --- a/dapps/valuetransfers/packages/tangle/tangle.go +++ b/dapps/valuetransfers/packages/tangle/tangle.go @@ -50,15 +50,15 @@ func New(store kvstore.KVStore) (tangle *Tangle) { tangle = &Tangle{ branchManager: branchmanager.New(store), - payloadStorage: osFactory.New(osPayload, osPayloadFactory, objectstorage.CacheTime(time.Second)), - payloadMetadataStorage: osFactory.New(osPayloadMetadata, osPayloadMetadataFactory, objectstorage.CacheTime(time.Second)), - missingPayloadStorage: osFactory.New(osMissingPayload, osMissingPayloadFactory, objectstorage.CacheTime(time.Second)), - approverStorage: osFactory.New(osApprover, osPayloadApproverFactory, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IDLength, payload.IDLength), objectstorage.KeysOnly(true)), - transactionStorage: osFactory.New(osTransaction, osTransactionFactory, objectstorage.CacheTime(time.Second), osLeakDetectionOption), - transactionMetadataStorage: osFactory.New(osTransactionMetadata, osTransactionMetadataFactory, objectstorage.CacheTime(time.Second), osLeakDetectionOption), - attachmentStorage: osFactory.New(osAttachment, osAttachmentFactory, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(transaction.IDLength, payload.IDLength), osLeakDetectionOption), - outputStorage: osFactory.New(osOutput, osOutputFactory, OutputKeyPartitions, objectstorage.CacheTime(time.Second), osLeakDetectionOption), - consumerStorage: osFactory.New(osConsumer, osConsumerFactory, ConsumerPartitionKeys, objectstorage.CacheTime(time.Second), osLeakDetectionOption), + payloadStorage: osFactory.New(osPayload, osPayloadFactory, objectstorage.CacheTime(1*time.Second)), + payloadMetadataStorage: osFactory.New(osPayloadMetadata, osPayloadMetadataFactory, objectstorage.CacheTime(1*time.Second)), + missingPayloadStorage: osFactory.New(osMissingPayload, osMissingPayloadFactory, objectstorage.CacheTime(1*time.Second)), + approverStorage: osFactory.New(osApprover, osPayloadApproverFactory, objectstorage.CacheTime(1*time.Second), objectstorage.PartitionKey(payload.IDLength, payload.IDLength), objectstorage.KeysOnly(true)), + transactionStorage: osFactory.New(osTransaction, osTransactionFactory, objectstorage.CacheTime(1*time.Second), osLeakDetectionOption), + transactionMetadataStorage: osFactory.New(osTransactionMetadata, osTransactionMetadataFactory, objectstorage.CacheTime(1*time.Second), osLeakDetectionOption), + attachmentStorage: osFactory.New(osAttachment, osAttachmentFactory, objectstorage.CacheTime(1*time.Second), objectstorage.PartitionKey(transaction.IDLength, payload.IDLength), osLeakDetectionOption), + outputStorage: osFactory.New(osOutput, osOutputFactory, OutputKeyPartitions, objectstorage.CacheTime(1*time.Second), osLeakDetectionOption), + consumerStorage: osFactory.New(osConsumer, osConsumerFactory, ConsumerPartitionKeys, objectstorage.CacheTime(1*time.Second), osLeakDetectionOption), Events: *newEvents(), } @@ -1140,7 +1140,7 @@ func (tangle *Tangle) processSolidificationStackEntry(solidificationStack *list. // abort if the transaction is not solid or invalid transactionSolid, consumedBranches, transactionSolidityErr := tangle.checkTransactionSolidity(currentTransaction, currentTransactionMetadata) if transactionSolidityErr != nil { - tangle.Events.TransactionInvalid.Trigger(solidificationStackEntry.CachedTransaction, solidificationStackEntry.CachedTransactionMetadata) + tangle.Events.TransactionInvalid.Trigger(solidificationStackEntry.CachedTransaction, solidificationStackEntry.CachedTransactionMetadata, transactionSolidityErr) tangle.deleteTransactionFutureCone(currentTransaction.ID()) @@ -1403,28 +1403,21 @@ func (tangle *Tangle) checkPayloadSolidity(p *payload.Payload, payloadMetadata * return } - if solid = payloadMetadata.IsSolid(); solid { + if payloadMetadata.IsSolid() { + solid = payloadMetadata.BranchID() != branchmanager.UndefinedBranchID return } combinedBranches := transactionBranches trunkBranchID := tangle.payloadBranchID(p.TrunkID()) - tangle.PayloadMetadata(p.TrunkID()).Consume(func(metadata *PayloadMetadata) { solid = metadata.IsSolid() }) - if p.TrunkID() == payload.GenesisID { - solid = true - } - if trunkBranchID == branchmanager.UndefinedBranchID || !solid { + if trunkBranchID == branchmanager.UndefinedBranchID { return false, nil } combinedBranches = append(combinedBranches, trunkBranchID) branchBranchID := tangle.payloadBranchID(p.BranchID()) - tangle.PayloadMetadata(p.BranchID()).Consume(func(metadata *PayloadMetadata) { solid = metadata.IsSolid() }) - if p.BranchID() == payload.GenesisID { - solid = true - } - if branchBranchID == branchmanager.UndefinedBranchID || !solid { + if branchBranchID == branchmanager.UndefinedBranchID { return false, nil } combinedBranches = append(combinedBranches, branchBranchID) @@ -1451,8 +1444,10 @@ func (tangle *Tangle) checkTransactionSolidity(tx *transaction.Transaction, meta } // abort if we have previously determined the solidity status of the transaction already - if solid = metadata.Solid(); solid { - consumedBranches = []branchmanager.BranchID{metadata.BranchID()} + if metadata.Solid() { + if solid = metadata.BranchID() != branchmanager.UndefinedBranchID; solid { + consumedBranches = []branchmanager.BranchID{metadata.BranchID()} + } return } diff --git a/dapps/valuetransfers/packages/tangle/tangle_concurrency_test.go b/dapps/valuetransfers/packages/tangle/tangle_concurrency_test.go index ff3562497372f5b3ee391b11191e6ad97d23088d..f9b8402db5745edcffa80fc14872f47b57d5bcc5 100644 --- a/dapps/valuetransfers/packages/tangle/tangle_concurrency_test.go +++ b/dapps/valuetransfers/packages/tangle/tangle_concurrency_test.go @@ -1,6 +1,7 @@ package tangle import ( + "fmt" "sync" "testing" @@ -10,8 +11,10 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload" "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/tipmanager" "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" + "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/kvstore/mapdb" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestConcurrency(t *testing.T) { @@ -215,12 +218,28 @@ func TestReverseTransactionSolidification(t *testing.T) { // Builds a UTXO-DAG with `txChains` spending outputs from the corresponding chain. // All value objects reference the previous value object, effectively creating a chain. // The test attaches the prepared value objects concurrently in reverse order. + //name, err := ioutil.TempDir("", "example") + //require.NoError(t, err) + //bDB, err := database.NewDB(name) + //require.NoError(t, err) + // + //tangle := New(bDB.NewStore()) tangle := New(mapdb.NewMapDB()) - defer tangle.Shutdown() + + tangle.Events.Error.Attach(events.NewClosure(func(err error) { + fmt.Println(err) + })) + + tangle.Events.TransactionInvalid.Attach(events.NewClosure(func(_ *transaction.CachedTransaction, _ *CachedTransactionMetadata, err error) { + panic(err) + })) + tangle.Events.PayloadInvalid.Attach(events.NewClosure(func(_ *payload.CachedPayload, _ *CachedPayloadMetadata, err error) { + panic(err) + })) tipManager := tipmanager.New() - txChains := 5 + txChains := 1 count := 100 threads := 10 countTotal := txChains * threads * count @@ -279,6 +298,12 @@ func TestReverseTransactionSolidification(t *testing.T) { valueObjects[i] = valueObject } + //TODO: + //for i := 0; i < countTotal; i++ { + // fmt.Println(i, "ValueObject", valueObjects[i].ID()) + // fmt.Println(i, "Transaction", valueObjects[i].Transaction().ID()) + //} + // attach value objects in reverse order var wg sync.WaitGroup for thread := 0; thread < threads; thread++ { @@ -294,24 +319,26 @@ func TestReverseTransactionSolidification(t *testing.T) { } wg.Wait() + fmt.Println("finished attaching") + // verify correctness for i := 0; i < countTotal; i++ { // check if transaction metadata is found in database - assert.True(t, tangle.TransactionMetadata(transactions[i].ID()).Consume(func(transactionMetadata *TransactionMetadata) { + require.Truef(t, tangle.TransactionMetadata(transactions[i].ID()).Consume(func(transactionMetadata *TransactionMetadata) { assert.Truef(t, transactionMetadata.Solid(), "the transaction %s is not solid", transactions[i].ID().String()) assert.Equalf(t, branchmanager.MasterBranchID, transactionMetadata.BranchID(), "the transaction was booked into the wrong branch") - })) + }), "transaction metadata %s not found in database", transactions[i].ID()) - // check if payload metadata is found in database - assert.True(t, tangle.PayloadMetadata(valueObjects[i].ID()).Consume(func(payloadMetadata *PayloadMetadata) { - assert.Truef(t, payloadMetadata.IsSolid(), "the payload is not solid") + // check if value object metadata is found in database + require.Truef(t, tangle.PayloadMetadata(valueObjects[i].ID()).Consume(func(payloadMetadata *PayloadMetadata) { + assert.Truef(t, payloadMetadata.IsSolid(), "the payload %s is not solid", valueObjects[i].ID()) assert.Equalf(t, branchmanager.MasterBranchID, payloadMetadata.BranchID(), "the payload was booked into the wrong branch") - })) + }), "value object metadata %s not found in database", valueObjects[i].ID()) // check if outputs are found in database transactions[i].Outputs().ForEach(func(address address.Address, balances []*balance.Balance) bool { cachedOutput := tangle.TransactionOutput(transaction.NewOutputID(address, transactions[i].ID())) - assert.True(t, cachedOutput.Consume(func(output *Output) { + assert.Truef(t, cachedOutput.Consume(func(output *Output) { // only the last outputs in chain should not be spent if i+txChains >= countTotal { assert.Equalf(t, 0, output.ConsumerCount(), "the output should not be spent") @@ -321,7 +348,7 @@ func TestReverseTransactionSolidification(t *testing.T) { assert.Equal(t, []*balance.Balance{balance.New(balance.ColorIOTA, 1)}, output.Balances()) assert.Equalf(t, branchmanager.MasterBranchID, output.BranchID(), "the output was booked into the wrong branch") assert.Truef(t, output.Solid(), "the output is not solid") - })) + }), "output not found in database for tx %s", transactions[i]) return true }) }