From 490f10e3e0a55f1e7d8f503e681d052c525545b7 Mon Sep 17 00:00:00 2001 From: Hans Moog <hm@mkjc.net> Date: Mon, 23 Mar 2020 03:34:09 +0100 Subject: [PATCH] Feat: Refactor and cleanup some code (#301) * Feat: refactored the address * Feat: started adding solidification of transferOutputs * Feat: cleaned up checker code * Feat: going to bed - good night world * Feat: refactored transferoutput package * Fix: fixed a bug from refactoring * Refactor: removed old transferoutputmetadata package * Refactor: started refactoring transfer package * Refactor: refactored transfer/id package * Refactor: moved transfer struct to new package * Refactor: fixed issues after refactor * Refactor: fixed sth * Refactor: continued to move files * Refactor: commit before migration of last refactored files * Refactor: another refactor before move * Refactor: refactor test * Fix: fixed some bugs connected to refactor * Refactor: continued refactor * Refactor: fixed some bugs * Refactor: does it work now? * Feat: added a method to generate a random transferid * Feat: rename transfer to transaction * Refactor: refactor according to new names * Refactor: continued to refactor transaction package * Refactor: moved payload id to payload package * Refactor: moved signatures to transaction package * Refactor: moved signature to transaction * Fix: fixed bug due to refactor * Fix: fixed bugs due to refactor * Refactor: fixed some bugs after refactor * Fix: fixed additional bugs * Fix: bug fix * Refactor: moved signature to signaturescheme package * Fix: fixed signatures test * Fix: fixed bug in tangle * Fix: fixed payloadmetadata test * Fix: fixed payload test * Refactor: moved payloadmetadata to payload package * Fix: fixed some refactor bugs * Fix: fixed a bug due to refactor * Fix: fixed broken test * Refactor: moved approver to payload package * Refactor: moved missingpayload to payload package * Refactor: refactored coloredbalance package * Fix: fixed bug due to refactor * Refactor: moved address signaturescheme to address package * Fix: fixed refactor bug * Feat: added missing outputs to tangle * Fix: fixed issues due to refactor * Refactor: started moving tangle classes to tangle package * Refactor: moved payloadmetadata to tangle * Fix: fixed bugs due to refactor * Refactor: moved TransactionMetadata to tangle package * Refactor: moved some files to tangle * Fix: fixed bug due to refactor * Feat: added TransactionMetadata storage * Fix: fixed some issues * Fix: fixed some issues * Fix: fixed missing release --- .../datastructure/orderedmap/orderedmap.go | 6 +- packages/binary/spammer/spammer.go | 10 +- packages/binary/tangle/events.go | 8 +- .../binary/tangle/model/approver/approver.go | 22 +- .../cached_transaction.go | 2 +- .../model/{transaction => message}/id.go | 2 +- packages/binary/tangle/model/message/init.go | 10 + .../payload/data/data.go | 2 +- .../payload/data/init.go | 2 +- .../{transaction => message}/payload/id.go | 0 .../payload/payload.go | 0 .../{transaction => message}/payload/type.go | 0 .../payload/type_register.go | 0 .../test/transaction_test.go | 12 +- .../{transaction => message}/transaction.go | 4 +- .../missingtransaction/missingtransaction.go | 8 +- .../binary/tangle/model/transaction/init.go | 10 - .../transactionmetadata.go | 6 +- packages/binary/tangle/tangle.go | 58 +-- packages/binary/tangle/tangle_test.go | 26 +- packages/binary/tangle/tipselector/events.go | 4 +- .../binary/tangle/tipselector/tipselector.go | 16 +- .../tangle/tipselector/tipselector_test.go | 14 +- .../transaction_signature_filter.go | 16 +- .../transactionparser/transaction_filter.go | 8 +- .../transactionparser/transactionparser.go | 12 +- .../transactionparser_test.go | 12 +- .../transactionrequester.go | 12 +- .../binary/valuetransfer/address/address.go | 18 +- .../signaturescheme}/ed25519.go | 7 +- .../address/signaturescheme/signature.go | 15 + .../signaturescheme/signaturescheme.go | 17 + .../binary/valuetransfer/balance/balance.go | 79 ++++ .../valuetransfer/balance/balance_test.go | 24 ++ .../color => balance}/color.go | 16 +- .../coloredbalance/coloredbalance.go | 70 ---- .../valuetransfer/payload/cached_object.go | 39 -- .../valuetransfer/payload/{id => }/id.go | 30 +- .../valuetransfer/payload/{id => }/id_test.go | 6 +- .../binary/valuetransfer/payload/payload.go | 96 +++-- .../valuetransfer/payload/payload_test.go | 120 +++++++ .../valuetransfer/payload/transfer/id/id.go | 48 --- .../payload/transfer/signatures/interfaces.go | 27 -- .../payload/transfer/transfer.go | 296 --------------- .../binary/valuetransfer/tangle/attachment.go | 23 ++ .../binary/valuetransfer/tangle/events.go | 17 +- .../valuetransfer/tangle/missingoutput.go | 109 ++++++ .../{missingpayload => }/missingpayload.go | 26 +- .../valuetransfer/tangle/payloadapprover.go | 129 +++++++ .../tangle/payloadapprover/cached_object.go | 49 --- .../tangle/payloadapprover/payloadapprover.go | 85 ----- .../{payloadmetadata => }/payloadmetadata.go | 70 +++- .../tangle/payloadmetadata/cached_object.go | 39 -- .../payloadmetadata_test.go | 12 +- .../binary/valuetransfer/tangle/tangle.go | 153 +++++--- .../valuetransfer/tangle/tangle_test.go | 28 +- .../tangle/transactionmetadata.go | 213 +++++++++++ .../tangle/transactionoutputmetadata.go | 213 +++++++++++ .../binary/valuetransfer/test/payload_test.go | 124 ------- .../binary/valuetransfer/transaction/id.go | 86 +++++ .../transfer/inputs => transaction}/inputs.go | 76 ++-- .../valuetransfer/transaction/output.go | 126 +++++++ .../output_test.go} | 2 +- .../valuetransfer/transaction/outputid.go | 71 ++++ .../outputs => transaction}/outputs.go | 24 +- .../signatures => transaction}/signatures.go | 62 +++- .../signatures_test.go | 15 +- .../valuetransfer/transaction/transaction.go | 339 ++++++++++++++++++ .../valuetransfer/transferoutput/id/id.go | 43 --- .../transferoutput/transferoutput.go | 127 ------- packages/gossip/manager.go | 6 +- packages/gossip/manager_test.go | 4 +- plugins/gossip/gossip.go | 6 +- plugins/gossip/plugin.go | 8 +- plugins/metrics/plugin.go | 4 +- plugins/spa/explorer_routes.go | 12 +- plugins/spa/livefeed.go | 6 +- plugins/tangle/plugin.go | 10 +- plugins/webapi/gtta/plugin.go | 6 +- 79 files changed, 2159 insertions(+), 1354 deletions(-) rename packages/binary/tangle/model/{transaction => message}/cached_transaction.go (97%) rename packages/binary/tangle/model/{transaction => message}/id.go (98%) create mode 100644 packages/binary/tangle/model/message/init.go rename packages/binary/tangle/model/{transaction => message}/payload/data/data.go (96%) rename packages/binary/tangle/model/{transaction => message}/payload/data/init.go (56%) rename packages/binary/tangle/model/{transaction => message}/payload/id.go (100%) rename packages/binary/tangle/model/{transaction => message}/payload/payload.go (100%) rename packages/binary/tangle/model/{transaction => message}/payload/type.go (100%) rename packages/binary/tangle/model/{transaction => message}/payload/type_register.go (100%) rename packages/binary/tangle/model/{transaction => message}/test/transaction_test.go (65%) rename packages/binary/tangle/model/{transaction => message}/transaction.go (98%) delete mode 100644 packages/binary/tangle/model/transaction/init.go rename packages/binary/valuetransfer/{payload/transfer/signatures => address/signaturescheme}/ed25519.go (95%) create mode 100644 packages/binary/valuetransfer/address/signaturescheme/signature.go create mode 100644 packages/binary/valuetransfer/address/signaturescheme/signaturescheme.go create mode 100644 packages/binary/valuetransfer/balance/balance.go create mode 100644 packages/binary/valuetransfer/balance/balance_test.go rename packages/binary/valuetransfer/{coloredbalance/color => balance}/color.go (51%) delete mode 100644 packages/binary/valuetransfer/coloredbalance/coloredbalance.go delete mode 100644 packages/binary/valuetransfer/payload/cached_object.go rename packages/binary/valuetransfer/payload/{id => }/id.go (63%) rename packages/binary/valuetransfer/payload/{id => }/id_test.go (70%) create mode 100644 packages/binary/valuetransfer/payload/payload_test.go delete mode 100644 packages/binary/valuetransfer/payload/transfer/id/id.go delete mode 100644 packages/binary/valuetransfer/payload/transfer/signatures/interfaces.go delete mode 100644 packages/binary/valuetransfer/payload/transfer/transfer.go create mode 100644 packages/binary/valuetransfer/tangle/attachment.go create mode 100644 packages/binary/valuetransfer/tangle/missingoutput.go rename packages/binary/valuetransfer/tangle/{missingpayload => }/missingpayload.go (72%) create mode 100644 packages/binary/valuetransfer/tangle/payloadapprover.go delete mode 100644 packages/binary/valuetransfer/tangle/payloadapprover/cached_object.go delete mode 100644 packages/binary/valuetransfer/tangle/payloadapprover/payloadapprover.go rename packages/binary/valuetransfer/tangle/{payloadmetadata => }/payloadmetadata.go (59%) delete mode 100644 packages/binary/valuetransfer/tangle/payloadmetadata/cached_object.go rename packages/binary/valuetransfer/tangle/{payloadmetadata => }/payloadmetadata_test.go (80%) create mode 100644 packages/binary/valuetransfer/tangle/transactionmetadata.go create mode 100644 packages/binary/valuetransfer/tangle/transactionoutputmetadata.go delete mode 100644 packages/binary/valuetransfer/test/payload_test.go create mode 100644 packages/binary/valuetransfer/transaction/id.go rename packages/binary/valuetransfer/{payload/transfer/inputs => transaction}/inputs.go (50%) create mode 100644 packages/binary/valuetransfer/transaction/output.go rename packages/binary/valuetransfer/{transferoutput/transferoutput_test.go => transaction/output_test.go} (70%) create mode 100644 packages/binary/valuetransfer/transaction/outputid.go rename packages/binary/valuetransfer/{payload/transfer/outputs => transaction}/outputs.go (79%) rename packages/binary/valuetransfer/{payload/transfer/signatures => transaction}/signatures.go (66%) rename packages/binary/valuetransfer/{payload/transfer/signatures => transaction}/signatures_test.go (65%) create mode 100644 packages/binary/valuetransfer/transaction/transaction.go delete mode 100644 packages/binary/valuetransfer/transferoutput/id/id.go delete mode 100644 packages/binary/valuetransfer/transferoutput/transferoutput.go diff --git a/packages/binary/datastructure/orderedmap/orderedmap.go b/packages/binary/datastructure/orderedmap/orderedmap.go index fe055542..8bc97443 100644 --- a/packages/binary/datastructure/orderedmap/orderedmap.go +++ b/packages/binary/datastructure/orderedmap/orderedmap.go @@ -66,20 +66,22 @@ func (orderedMap *OrderedMap) Set(key interface{}, newValue interface{}) bool { return true } -func (orderedMap *OrderedMap) ForEach(consumer func(key, value interface{}) bool) { +func (orderedMap *OrderedMap) ForEach(consumer func(key, value interface{}) bool) bool { orderedMap.mutex.RLock() currentEntry := orderedMap.head orderedMap.mutex.RUnlock() for currentEntry != nil { if !consumer(currentEntry.key, currentEntry.value) { - return + return false } orderedMap.mutex.RLock() currentEntry = currentEntry.next orderedMap.mutex.RUnlock() } + + return true } func (orderedMap *OrderedMap) Delete(key interface{}) bool { diff --git a/packages/binary/spammer/spammer.go b/packages/binary/spammer/spammer.go index e59cf9df..ea0efc5a 100644 --- a/packages/binary/spammer/spammer.go +++ b/packages/binary/spammer/spammer.go @@ -7,8 +7,8 @@ import ( "github.com/iotaledger/hive.go/types" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload/data" "github.com/iotaledger/goshimmer/packages/binary/tangle/tipselector" "github.com/iotaledger/goshimmer/packages/binary/tangle/transactionparser" ) @@ -53,7 +53,7 @@ func (spammer *Spammer) run(tps int, processId int64) { trunkTransactionId, branchTransactionId := spammer.tipSelector.GetTips() spammer.transactionParser.Parse( - transaction.New(trunkTransactionId, branchTransactionId, spammingIdentity, time.Now(), 0, data.New([]byte("SPAM"))).Bytes(), + message.New(trunkTransactionId, branchTransactionId, spammingIdentity, time.Now(), 0, data.New([]byte("SPAM"))).Bytes(), nil, ) @@ -75,7 +75,7 @@ func (spammer *Spammer) run(tps int, processId int64) { func (spammer *Spammer) sendBurst(transactions int, processId int64) { spammingIdentity := ed25119.GenerateKeyPair() - previousTransactionId := transaction.EmptyId + previousTransactionId := message.EmptyId burstBuffer := make([][]byte, transactions) for i := 0; i < transactions; i++ { @@ -83,7 +83,7 @@ func (spammer *Spammer) sendBurst(transactions int, processId int64) { return } - spamTransaction := transaction.New(previousTransactionId, previousTransactionId, spammingIdentity, time.Now(), 0, data.New([]byte("SPAM"))) + spamTransaction := message.New(previousTransactionId, previousTransactionId, spammingIdentity, time.Now(), 0, data.New([]byte("SPAM"))) previousTransactionId = spamTransaction.GetId() burstBuffer[i] = spamTransaction.Bytes() } diff --git a/packages/binary/tangle/events.go b/packages/binary/tangle/events.go index ebf537c9..ec056169 100644 --- a/packages/binary/tangle/events.go +++ b/packages/binary/tangle/events.go @@ -3,7 +3,7 @@ package tangle import ( "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" ) @@ -29,12 +29,12 @@ func newEvents() *Events { } func transactionIdEvent(handler interface{}, params ...interface{}) { - handler.(func(transaction.Id))(params[0].(transaction.Id)) + handler.(func(message.Id))(params[0].(message.Id)) } func cachedTransactionEvent(handler interface{}, params ...interface{}) { - handler.(func(*transaction.CachedTransaction, *transactionmetadata.CachedTransactionMetadata))( - params[0].(*transaction.CachedTransaction).Retain(), + handler.(func(*message.CachedTransaction, *transactionmetadata.CachedTransactionMetadata))( + params[0].(*message.CachedTransaction).Retain(), params[1].(*transactionmetadata.CachedTransactionMetadata).Retain(), ) } diff --git a/packages/binary/tangle/model/approver/approver.go b/packages/binary/tangle/model/approver/approver.go index b08bf342..23c0842b 100644 --- a/packages/binary/tangle/model/approver/approver.go +++ b/packages/binary/tangle/model/approver/approver.go @@ -3,36 +3,36 @@ package approver import ( "github.com/iotaledger/hive.go/objectstorage" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" ) type Approver struct { objectstorage.StorableObjectFlags storageKey []byte - referencedTransaction transaction.Id - approvingTransaction transaction.Id + referencedTransaction message.Id + approvingTransaction message.Id } -func New(referencedTransaction transaction.Id, approvingTransaction transaction.Id) *Approver { +func New(referencedTransaction message.Id, approvingTransaction message.Id) *Approver { approver := &Approver{ - storageKey: make([]byte, transaction.IdLength+transaction.IdLength), + storageKey: make([]byte, message.IdLength+message.IdLength), referencedTransaction: referencedTransaction, approvingTransaction: approvingTransaction, } - copy(approver.storageKey[:transaction.IdLength], referencedTransaction[:]) - copy(approver.storageKey[transaction.IdLength:], approvingTransaction[:]) + copy(approver.storageKey[:message.IdLength], referencedTransaction[:]) + copy(approver.storageKey[message.IdLength:], approvingTransaction[:]) return approver } func FromStorage(id []byte) (result objectstorage.StorableObject) { approver := &Approver{ - storageKey: make([]byte, transaction.IdLength+transaction.IdLength), + storageKey: make([]byte, message.IdLength+message.IdLength), } - copy(approver.referencedTransaction[:], id[:transaction.IdLength]) - copy(approver.approvingTransaction[:], id[transaction.IdLength:]) + copy(approver.referencedTransaction[:], id[:message.IdLength]) + copy(approver.approvingTransaction[:], id[message.IdLength:]) copy(approver.storageKey, id) return approver @@ -42,7 +42,7 @@ func (approver *Approver) GetStorageKey() []byte { return approver.storageKey } -func (approver *Approver) GetApprovingTransactionId() transaction.Id { +func (approver *Approver) GetApprovingTransactionId() message.Id { return approver.approvingTransaction } diff --git a/packages/binary/tangle/model/transaction/cached_transaction.go b/packages/binary/tangle/model/message/cached_transaction.go similarity index 97% rename from packages/binary/tangle/model/transaction/cached_transaction.go rename to packages/binary/tangle/model/message/cached_transaction.go index d95494ed..8657ecb8 100644 --- a/packages/binary/tangle/model/transaction/cached_transaction.go +++ b/packages/binary/tangle/model/message/cached_transaction.go @@ -1,4 +1,4 @@ -package transaction +package message import ( "github.com/iotaledger/hive.go/objectstorage" diff --git a/packages/binary/tangle/model/transaction/id.go b/packages/binary/tangle/model/message/id.go similarity index 98% rename from packages/binary/tangle/model/transaction/id.go rename to packages/binary/tangle/model/message/id.go index c7a93190..40600315 100644 --- a/packages/binary/tangle/model/transaction/id.go +++ b/packages/binary/tangle/model/message/id.go @@ -1,4 +1,4 @@ -package transaction +package message import ( "fmt" diff --git a/packages/binary/tangle/model/message/init.go b/packages/binary/tangle/model/message/init.go new file mode 100644 index 00000000..15999765 --- /dev/null +++ b/packages/binary/tangle/model/message/init.go @@ -0,0 +1,10 @@ +package message + +import ( + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload/data" +) + +func init() { + payload.SetGenericUnmarshalerFactory(data.GenericPayloadUnmarshalerFactory) +} diff --git a/packages/binary/tangle/model/transaction/payload/data/data.go b/packages/binary/tangle/model/message/payload/data/data.go similarity index 96% rename from packages/binary/tangle/model/transaction/payload/data/data.go rename to packages/binary/tangle/model/message/payload/data/data.go index 3c971c20..70efdcfc 100644 --- a/packages/binary/tangle/model/transaction/payload/data/data.go +++ b/packages/binary/tangle/model/message/payload/data/data.go @@ -4,7 +4,7 @@ import ( "github.com/iotaledger/hive.go/stringify" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload" ) type Data struct { diff --git a/packages/binary/tangle/model/transaction/payload/data/init.go b/packages/binary/tangle/model/message/payload/data/init.go similarity index 56% rename from packages/binary/tangle/model/transaction/payload/data/init.go rename to packages/binary/tangle/model/message/payload/data/init.go index 547bca2c..f1ae7c9d 100644 --- a/packages/binary/tangle/model/transaction/payload/data/init.go +++ b/packages/binary/tangle/model/message/payload/data/init.go @@ -1,7 +1,7 @@ package data import ( - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload" ) func init() { diff --git a/packages/binary/tangle/model/transaction/payload/id.go b/packages/binary/tangle/model/message/payload/id.go similarity index 100% rename from packages/binary/tangle/model/transaction/payload/id.go rename to packages/binary/tangle/model/message/payload/id.go diff --git a/packages/binary/tangle/model/transaction/payload/payload.go b/packages/binary/tangle/model/message/payload/payload.go similarity index 100% rename from packages/binary/tangle/model/transaction/payload/payload.go rename to packages/binary/tangle/model/message/payload/payload.go diff --git a/packages/binary/tangle/model/transaction/payload/type.go b/packages/binary/tangle/model/message/payload/type.go similarity index 100% rename from packages/binary/tangle/model/transaction/payload/type.go rename to packages/binary/tangle/model/message/payload/type.go diff --git a/packages/binary/tangle/model/transaction/payload/type_register.go b/packages/binary/tangle/model/message/payload/type_register.go similarity index 100% rename from packages/binary/tangle/model/transaction/payload/type_register.go rename to packages/binary/tangle/model/message/payload/type_register.go diff --git a/packages/binary/tangle/model/transaction/test/transaction_test.go b/packages/binary/tangle/model/message/test/transaction_test.go similarity index 65% rename from packages/binary/tangle/model/transaction/test/transaction_test.go rename to packages/binary/tangle/model/message/test/transaction_test.go index 172e6509..357ec1ba 100644 --- a/packages/binary/tangle/model/transaction/test/transaction_test.go +++ b/packages/binary/tangle/model/message/test/transaction_test.go @@ -11,8 +11,8 @@ import ( "github.com/panjf2000/ants/v2" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload/data" ) func BenchmarkVerifyDataTransactions(b *testing.B) { @@ -21,7 +21,7 @@ func BenchmarkVerifyDataTransactions(b *testing.B) { transactions := make([][]byte, b.N) for i := 0; i < b.N; i++ { - tx := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("some data"))) + tx := message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("some data"))) if marshaledTransaction, err := tx.MarshalBinary(); err != nil { b.Error(err) @@ -35,7 +35,7 @@ func BenchmarkVerifyDataTransactions(b *testing.B) { for i := 0; i < b.N; i++ { currentIndex := i pool.Submit(func() { - if tx, err, _ := transaction.FromBytes(transactions[currentIndex]); err != nil { + if tx, err, _ := message.FromBytes(transactions[currentIndex]); err != nil { b.Error(err) } else { tx.VerifySignature() @@ -49,9 +49,9 @@ func BenchmarkVerifyDataTransactions(b *testing.B) { func BenchmarkVerifySignature(b *testing.B) { pool, _ := ants.NewPool(80, ants.WithNonblocking(false)) - transactions := make([]*transaction.Transaction, b.N) + transactions := make([]*message.Transaction, b.N) for i := 0; i < b.N; i++ { - transactions[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("test"))) + transactions[i] = message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("test"))) transactions[i].Bytes() } diff --git a/packages/binary/tangle/model/transaction/transaction.go b/packages/binary/tangle/model/message/transaction.go similarity index 98% rename from packages/binary/tangle/model/transaction/transaction.go rename to packages/binary/tangle/model/message/transaction.go index d2420224..ff3c9c36 100644 --- a/packages/binary/tangle/model/transaction/transaction.go +++ b/packages/binary/tangle/model/message/transaction.go @@ -1,4 +1,4 @@ -package transaction +package message import ( "sync" @@ -8,7 +8,7 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/marshalutil" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload" "github.com/iotaledger/hive.go/objectstorage" diff --git a/packages/binary/tangle/model/missingtransaction/missingtransaction.go b/packages/binary/tangle/model/missingtransaction/missingtransaction.go index ea1715c8..64baa95c 100644 --- a/packages/binary/tangle/model/missingtransaction/missingtransaction.go +++ b/packages/binary/tangle/model/missingtransaction/missingtransaction.go @@ -3,18 +3,18 @@ package missingtransaction import ( "time" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/hive.go/objectstorage" ) type MissingTransaction struct { objectstorage.StorableObjectFlags - transactionId transaction.Id + transactionId message.Id missingSince time.Time } -func New(transactionId transaction.Id) *MissingTransaction { +func New(transactionId message.Id) *MissingTransaction { return &MissingTransaction{ transactionId: transactionId, missingSince: time.Now(), @@ -28,7 +28,7 @@ func FromStorage(key []byte) objectstorage.StorableObject { return result } -func (missingTransaction *MissingTransaction) GetTransactionId() transaction.Id { +func (missingTransaction *MissingTransaction) GetTransactionId() message.Id { return missingTransaction.transactionId } diff --git a/packages/binary/tangle/model/transaction/init.go b/packages/binary/tangle/model/transaction/init.go deleted file mode 100644 index 5805588c..00000000 --- a/packages/binary/tangle/model/transaction/init.go +++ /dev/null @@ -1,10 +0,0 @@ -package transaction - -import ( - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" -) - -func init() { - payload.SetGenericUnmarshalerFactory(data.GenericPayloadUnmarshalerFactory) -} diff --git a/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go b/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go index a7730e62..1fcf1c25 100644 --- a/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go +++ b/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go @@ -6,13 +6,13 @@ import ( "github.com/iotaledger/hive.go/objectstorage" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" ) type TransactionMetadata struct { objectstorage.StorableObjectFlags - transactionId transaction.Id + transactionId message.Id receivedTime time.Time solid bool solidificationTime time.Time @@ -21,7 +21,7 @@ type TransactionMetadata struct { solidificationTimeMutex sync.RWMutex } -func New(transactionId transaction.Id) *TransactionMetadata { +func New(transactionId message.Id) *TransactionMetadata { return &TransactionMetadata{ transactionId: transactionId, receivedTime: time.Now(), diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go index 0e86da66..ac2418da 100644 --- a/packages/binary/tangle/tangle.go +++ b/packages/binary/tangle/tangle.go @@ -9,8 +9,8 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/storageprefix" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/approver" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/missingtransaction" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" "github.com/iotaledger/hive.go/async" @@ -41,9 +41,9 @@ type Tangle struct { func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) { result = &Tangle{ storageId: storageId, - transactionStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransaction...), transaction.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)), + transactionStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransaction...), message.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)), transactionMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransactionMetadata...), transactionmetadata.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)), - approverStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), approver.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(transaction.IdLength, transaction.IdLength), objectstorage.LeakDetectionEnabled(false)), + approverStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), approver.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(message.IdLength, message.IdLength), objectstorage.LeakDetectionEnabled(false)), missingTransactionsStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleMissingTransaction...), missingtransaction.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)), Events: *newEvents(), @@ -60,22 +60,22 @@ func (tangle *Tangle) GetStorageId() []byte { } // Attaches a new transaction to the tangle. -func (tangle *Tangle) AttachTransaction(transaction *transaction.Transaction) { +func (tangle *Tangle) AttachTransaction(transaction *message.Transaction) { tangle.storeTransactionsWorkerPool.Submit(func() { tangle.storeTransactionWorker(transaction) }) } // Retrieves a transaction from the tangle. -func (tangle *Tangle) GetTransaction(transactionId transaction.Id) *transaction.CachedTransaction { - return &transaction.CachedTransaction{CachedObject: tangle.transactionStorage.Load(transactionId[:])} +func (tangle *Tangle) GetTransaction(transactionId message.Id) *message.CachedTransaction { + return &message.CachedTransaction{CachedObject: tangle.transactionStorage.Load(transactionId[:])} } // Retrieves the metadata of a transaction from the tangle. -func (tangle *Tangle) GetTransactionMetadata(transactionId transaction.Id) *transactionmetadata.CachedTransactionMetadata { +func (tangle *Tangle) GetTransactionMetadata(transactionId message.Id) *transactionmetadata.CachedTransactionMetadata { return &transactionmetadata.CachedTransactionMetadata{CachedObject: tangle.transactionMetadataStorage.Load(transactionId[:])} } // GetApprovers retrieves the approvers of a transaction from the tangle. -func (tangle *Tangle) GetApprovers(transactionId transaction.Id) approver.CachedApprovers { +func (tangle *Tangle) GetApprovers(transactionId message.Id) approver.CachedApprovers { approvers := make(approver.CachedApprovers, 0) tangle.approverStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { approvers = append(approvers, &approver.CachedApprover{CachedObject: cachedObject}) @@ -87,8 +87,8 @@ func (tangle *Tangle) GetApprovers(transactionId transaction.Id) approver.Cached } // Deletes a transaction from the tangle (i.e. for local snapshots) -func (tangle *Tangle) DeleteTransaction(transactionId transaction.Id) { - tangle.GetTransaction(transactionId).Consume(func(currentTransaction *transaction.Transaction) { +func (tangle *Tangle) DeleteTransaction(transactionId message.Id) { + tangle.GetTransaction(transactionId).Consume(func(currentTransaction *message.Transaction) { trunkTransactionId := currentTransaction.GetTrunkTransactionId() tangle.deleteApprover(trunkTransactionId, transactionId) @@ -135,13 +135,13 @@ func (tangle *Tangle) Prune() error { } // Worker that stores the transactions and calls the corresponding storage events" -func (tangle *Tangle) storeTransactionWorker(tx *transaction.Transaction) { +func (tangle *Tangle) storeTransactionWorker(tx *message.Transaction) { // store transaction - var cachedTransaction *transaction.CachedTransaction + var cachedTransaction *message.CachedTransaction if _tmp, transactionIsNew := tangle.transactionStorage.StoreIfAbsent(tx); !transactionIsNew { return } else { - cachedTransaction = &transaction.CachedTransaction{CachedObject: _tmp} + cachedTransaction = &message.CachedTransaction{CachedObject: _tmp} } // store transaction metadata @@ -170,9 +170,9 @@ func (tangle *Tangle) storeTransactionWorker(tx *transaction.Transaction) { } // Worker that solidifies the transactions (recursively from past to present). -func (tangle *Tangle) solidifyTransactionWorker(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { - isTransactionMarkedAsSolid := func(transactionId transaction.Id) bool { - if transactionId == transaction.EmptyId { +func (tangle *Tangle) solidifyTransactionWorker(cachedTransaction *message.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { + isTransactionMarkedAsSolid := func(transactionId message.Id) bool { + if transactionId == message.EmptyId { return true } @@ -198,7 +198,7 @@ func (tangle *Tangle) solidifyTransactionWorker(cachedTransaction *transaction.C return true } - isTransactionSolid := func(transaction *transaction.Transaction, transactionMetadata *transactionmetadata.TransactionMetadata) bool { + isTransactionSolid := func(transaction *message.Transaction, transactionMetadata *transactionmetadata.TransactionMetadata) bool { if transaction == nil || transaction.IsDeleted() { return false } @@ -214,13 +214,13 @@ func (tangle *Tangle) solidifyTransactionWorker(cachedTransaction *transaction.C return isTransactionMarkedAsSolid(transaction.GetTrunkTransactionId()) && isTransactionMarkedAsSolid(transaction.GetBranchTransactionId()) } - popElementsFromStack := func(stack *list.List) (*transaction.CachedTransaction, *transactionmetadata.CachedTransactionMetadata) { + popElementsFromStack := func(stack *list.List) (*message.CachedTransaction, *transactionmetadata.CachedTransactionMetadata) { currentSolidificationEntry := stack.Front() currentCachedTransaction := currentSolidificationEntry.Value.([2]interface{})[0] currentCachedTransactionMetadata := currentSolidificationEntry.Value.([2]interface{})[1] stack.Remove(currentSolidificationEntry) - return currentCachedTransaction.(*transaction.CachedTransaction), currentCachedTransactionMetadata.(*transactionmetadata.CachedTransactionMetadata) + return currentCachedTransaction.(*message.CachedTransaction), currentCachedTransactionMetadata.(*transactionmetadata.CachedTransactionMetadata) } // initialize the stack @@ -261,9 +261,9 @@ func (tangle *Tangle) solidifyTransactionWorker(cachedTransaction *transaction.C } // Worker that Monitors the missing transactions (by scheduling regular checks). -func (tangle *Tangle) monitorMissingTransactionWorker(transactionId transaction.Id) { - var scheduleNextMissingCheck func(transactionId transaction.Id) - scheduleNextMissingCheck = func(transactionId transaction.Id) { +func (tangle *Tangle) monitorMissingTransactionWorker(transactionId message.Id) { + var scheduleNextMissingCheck func(transactionId message.Id) + scheduleNextMissingCheck = func(transactionId message.Id) { time.AfterFunc(MISSING_CHECK_INTERVAL, func() { tangle.missingTransactionsStorage.Load(transactionId[:]).Consume(func(object objectstorage.StorableObject) { missingTransaction := object.(*missingtransaction.MissingTransaction) @@ -288,24 +288,24 @@ func (tangle *Tangle) monitorMissingTransactionWorker(transactionId transaction. scheduleNextMissingCheck(transactionId) } -func (tangle *Tangle) deleteApprover(approvedTransaction transaction.Id, approvingTransaction transaction.Id) { - idToDelete := make([]byte, transaction.IdLength+transaction.IdLength) - copy(idToDelete[:transaction.IdLength], approvedTransaction[:]) - copy(idToDelete[transaction.IdLength:], approvingTransaction[:]) +func (tangle *Tangle) deleteApprover(approvedTransaction message.Id, approvingTransaction message.Id) { + idToDelete := make([]byte, message.IdLength+message.IdLength) + copy(idToDelete[:message.IdLength], approvedTransaction[:]) + copy(idToDelete[message.IdLength:], approvingTransaction[:]) tangle.approverStorage.Delete(idToDelete) } // Deletes a transaction and all of its approvers (recursively). -func (tangle *Tangle) deleteSubtangle(transactionId transaction.Id) { +func (tangle *Tangle) deleteSubtangle(transactionId message.Id) { cleanupStack := list.New() cleanupStack.PushBack(transactionId) - processedTransactions := make(map[transaction.Id]types.Empty) + processedTransactions := make(map[message.Id]types.Empty) processedTransactions[transactionId] = types.Void for cleanupStack.Len() >= 1 { currentStackEntry := cleanupStack.Front() - currentTransactionId := currentStackEntry.Value.(transaction.Id) + currentTransactionId := currentStackEntry.Value.(message.Id) cleanupStack.Remove(currentStackEntry) tangle.DeleteTransaction(currentTransactionId) diff --git a/packages/binary/tangle/tangle_test.go b/packages/binary/tangle/tangle_test.go index 6ba20cc7..9cf607e6 100644 --- a/packages/binary/tangle/tangle_test.go +++ b/packages/binary/tangle/tangle_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload/data" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" "github.com/iotaledger/goshimmer/packages/database" "github.com/iotaledger/goshimmer/plugins/config" @@ -34,9 +34,9 @@ func BenchmarkTangle_AttachTransaction(b *testing.B) { testIdentity := ed25119.GenerateKeyPair() - transactionBytes := make([]*transaction.Transaction, b.N) + transactionBytes := make([]*message.Transaction, b.N) for i := 0; i < b.N; i++ { - transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, testIdentity, time.Now(), 0, data.New([]byte("some data"))) + transactionBytes[i] = message.New(message.EmptyId, message.EmptyId, testIdentity, time.Now(), 0, data.New([]byte("some data"))) transactionBytes[i].Bytes() } @@ -63,36 +63,36 @@ func TestTangle_AttachTransaction(t *testing.T) { return } - tangle.Events.TransactionAttached.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { + tangle.Events.TransactionAttached.Attach(events.NewClosure(func(cachedTransaction *message.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { cachedTransactionMetadata.Release() - cachedTransaction.Consume(func(transaction *transaction.Transaction) { + cachedTransaction.Consume(func(transaction *message.Transaction) { fmt.Println("ATTACHED:", transaction.GetId()) }) })) - tangle.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { + tangle.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *message.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { cachedTransactionMetadata.Release() - cachedTransaction.Consume(func(transaction *transaction.Transaction) { + cachedTransaction.Consume(func(transaction *message.Transaction) { fmt.Println("SOLID:", transaction.GetId()) }) })) - tangle.Events.TransactionUnsolidifiable.Attach(events.NewClosure(func(transactionId transaction.Id) { + tangle.Events.TransactionUnsolidifiable.Attach(events.NewClosure(func(transactionId message.Id) { fmt.Println("UNSOLIDIFIABLE:", transactionId) })) - tangle.Events.TransactionMissing.Attach(events.NewClosure(func(transactionId transaction.Id) { + tangle.Events.TransactionMissing.Attach(events.NewClosure(func(transactionId message.Id) { fmt.Println("MISSING:", transactionId) })) - tangle.Events.TransactionRemoved.Attach(events.NewClosure(func(transactionId transaction.Id) { + tangle.Events.TransactionRemoved.Attach(events.NewClosure(func(transactionId message.Id) { fmt.Println("REMOVED:", transactionId) })) - newTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("some data"))) - newTransaction2 := transaction.New(newTransaction1.GetId(), newTransaction1.GetId(), ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("some other data"))) + newTransaction1 := message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("some data"))) + newTransaction2 := message.New(newTransaction1.GetId(), newTransaction1.GetId(), ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("some other data"))) tangle.AttachTransaction(newTransaction2) diff --git a/packages/binary/tangle/tipselector/events.go b/packages/binary/tangle/tipselector/events.go index 563e4a70..21f6276e 100644 --- a/packages/binary/tangle/tipselector/events.go +++ b/packages/binary/tangle/tipselector/events.go @@ -1,7 +1,7 @@ package tipselector import ( - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/hive.go/events" ) @@ -11,5 +11,5 @@ type Events struct { } func transactionIdEvent(handler interface{}, params ...interface{}) { - handler.(func(transaction.Id))(params[0].(transaction.Id)) + handler.(func(message.Id))(params[0].(message.Id)) } diff --git a/packages/binary/tangle/tipselector/tipselector.go b/packages/binary/tangle/tipselector/tipselector.go index 1b03500c..f98d1f50 100644 --- a/packages/binary/tangle/tipselector/tipselector.go +++ b/packages/binary/tangle/tipselector/tipselector.go @@ -2,7 +2,7 @@ package tipselector import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/hive.go/events" ) @@ -21,7 +21,7 @@ func New() *TipSelector { } } -func (tipSelector *TipSelector) AddTip(transaction *transaction.Transaction) { +func (tipSelector *TipSelector) AddTip(transaction *message.Transaction) { transactionId := transaction.GetId() if tipSelector.tips.Set(transactionId, transactionId) { tipSelector.Events.TipAdded.Trigger(transactionId) @@ -38,16 +38,16 @@ func (tipSelector *TipSelector) AddTip(transaction *transaction.Transaction) { } } -func (tipSelector *TipSelector) GetTips() (trunkTransaction, branchTransaction transaction.Id) { +func (tipSelector *TipSelector) GetTips() (trunkTransaction, branchTransaction message.Id) { tip := tipSelector.tips.RandomEntry() if tip == nil { - trunkTransaction = transaction.EmptyId - branchTransaction = transaction.EmptyId + trunkTransaction = message.EmptyId + branchTransaction = message.EmptyId return } - branchTransaction = tip.(transaction.Id) + branchTransaction = tip.(message.Id) if tipSelector.tips.Size() == 1 { trunkTransaction = branchTransaction @@ -55,9 +55,9 @@ func (tipSelector *TipSelector) GetTips() (trunkTransaction, branchTransaction t return } - trunkTransaction = tipSelector.tips.RandomEntry().(transaction.Id) + trunkTransaction = tipSelector.tips.RandomEntry().(message.Id) for trunkTransaction == branchTransaction && tipSelector.tips.Size() > 1 { - trunkTransaction = tipSelector.tips.RandomEntry().(transaction.Id) + trunkTransaction = tipSelector.tips.RandomEntry().(message.Id) } return diff --git a/packages/binary/tangle/tipselector/tipselector_test.go b/packages/binary/tangle/tipselector/tipselector_test.go index fe565bd1..f089f29d 100644 --- a/packages/binary/tangle/tipselector/tipselector_test.go +++ b/packages/binary/tangle/tipselector/tipselector_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload/data" ) func Test(t *testing.T) { @@ -17,11 +17,11 @@ func Test(t *testing.T) { // check if first tips point to genesis trunk1, branch1 := tipSelector.GetTips() - assert.Equal(t, transaction.EmptyId, trunk1) - assert.Equal(t, transaction.EmptyId, branch1) + assert.Equal(t, message.EmptyId, trunk1) + assert.Equal(t, message.EmptyId, branch1) // create a transaction and attach it - transaction1 := transaction.New(trunk1, branch1, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("testtransaction"))) + transaction1 := message.New(trunk1, branch1, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("testtransaction"))) tipSelector.AddTip(transaction1) // check if the tip shows up in the tip count @@ -33,7 +33,7 @@ func Test(t *testing.T) { assert.Equal(t, transaction1.GetId(), branch2) // create a 2nd transaction and attach it - transaction2 := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("testtransaction"))) + transaction2 := message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("testtransaction"))) tipSelector.AddTip(transaction2) // check if the tip shows up in the tip count @@ -41,7 +41,7 @@ func Test(t *testing.T) { // attach a transaction to our two tips trunk3, branch3 := tipSelector.GetTips() - transaction3 := transaction.New(trunk3, branch3, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("testtransaction"))) + transaction3 := message.New(trunk3, branch3, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("testtransaction"))) tipSelector.AddTip(transaction3) // check if the tip shows replaces the current tips diff --git a/packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go b/packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go index 132ca46e..f6d64f3e 100644 --- a/packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go +++ b/packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go @@ -7,14 +7,14 @@ import ( "github.com/iotaledger/hive.go/async" "github.com/iotaledger/hive.go/autopeering/peer" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" ) var ErrInvalidSignature = fmt.Errorf("invalid signature") type TransactionSignatureFilter struct { - onAcceptCallback func(tx *transaction.Transaction, peer *peer.Peer) - onRejectCallback func(tx *transaction.Transaction, err error, peer *peer.Peer) + onAcceptCallback func(tx *message.Transaction, peer *peer.Peer) + onRejectCallback func(tx *message.Transaction, err error, peer *peer.Peer) workerPool async.WorkerPool onAcceptCallbackMutex sync.RWMutex @@ -27,7 +27,7 @@ func NewTransactionSignatureFilter() (result *TransactionSignatureFilter) { return } -func (filter *TransactionSignatureFilter) Filter(tx *transaction.Transaction, peer *peer.Peer) { +func (filter *TransactionSignatureFilter) Filter(tx *message.Transaction, peer *peer.Peer) { filter.workerPool.Submit(func() { if tx.VerifySignature() { filter.getAcceptCallback()(tx, peer) @@ -37,13 +37,13 @@ func (filter *TransactionSignatureFilter) Filter(tx *transaction.Transaction, pe }) } -func (filter *TransactionSignatureFilter) OnAccept(callback func(tx *transaction.Transaction, peer *peer.Peer)) { +func (filter *TransactionSignatureFilter) OnAccept(callback func(tx *message.Transaction, peer *peer.Peer)) { filter.onAcceptCallbackMutex.Lock() filter.onAcceptCallback = callback filter.onAcceptCallbackMutex.Unlock() } -func (filter *TransactionSignatureFilter) OnReject(callback func(tx *transaction.Transaction, err error, peer *peer.Peer)) { +func (filter *TransactionSignatureFilter) OnReject(callback func(tx *message.Transaction, err error, peer *peer.Peer)) { filter.onRejectCallbackMutex.Lock() filter.onRejectCallback = callback filter.onRejectCallbackMutex.Unlock() @@ -53,7 +53,7 @@ func (filter *TransactionSignatureFilter) Shutdown() { filter.workerPool.ShutdownGracefully() } -func (filter *TransactionSignatureFilter) getAcceptCallback() (result func(tx *transaction.Transaction, peer *peer.Peer)) { +func (filter *TransactionSignatureFilter) getAcceptCallback() (result func(tx *message.Transaction, peer *peer.Peer)) { filter.onAcceptCallbackMutex.RLock() result = filter.onAcceptCallback filter.onAcceptCallbackMutex.RUnlock() @@ -61,7 +61,7 @@ func (filter *TransactionSignatureFilter) getAcceptCallback() (result func(tx *t return } -func (filter *TransactionSignatureFilter) getRejectCallback() (result func(tx *transaction.Transaction, err error, peer *peer.Peer)) { +func (filter *TransactionSignatureFilter) getRejectCallback() (result func(tx *message.Transaction, err error, peer *peer.Peer)) { filter.onRejectCallbackMutex.RLock() result = filter.onRejectCallback filter.onRejectCallbackMutex.RUnlock() diff --git a/packages/binary/tangle/transactionparser/transaction_filter.go b/packages/binary/tangle/transactionparser/transaction_filter.go index ac63d23c..c13d94ec 100644 --- a/packages/binary/tangle/transactionparser/transaction_filter.go +++ b/packages/binary/tangle/transactionparser/transaction_filter.go @@ -3,12 +3,12 @@ package transactionparser import ( "github.com/iotaledger/hive.go/autopeering/peer" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" ) type TransactionFilter interface { - Filter(tx *transaction.Transaction, peer *peer.Peer) - OnAccept(callback func(tx *transaction.Transaction, peer *peer.Peer)) - OnReject(callback func(tx *transaction.Transaction, err error, peer *peer.Peer)) + Filter(tx *message.Transaction, peer *peer.Peer) + OnAccept(callback func(tx *message.Transaction, peer *peer.Peer)) + OnReject(callback func(tx *message.Transaction, err error, peer *peer.Peer)) Shutdown() } diff --git a/packages/binary/tangle/transactionparser/transactionparser.go b/packages/binary/tangle/transactionparser/transactionparser.go index 8aa1c56d..d684efc3 100644 --- a/packages/binary/tangle/transactionparser/transactionparser.go +++ b/packages/binary/tangle/transactionparser/transactionparser.go @@ -5,7 +5,7 @@ import ( "github.com/iotaledger/hive.go/autopeering/peer" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/packages/binary/tangle/transactionparser/builtinfilters" "github.com/iotaledger/hive.go/events" @@ -33,10 +33,10 @@ func New() (result *TransactionParser) { handler.(func([]byte, error, *peer.Peer))(params[0].([]byte), params[1].(error), params[2].(*peer.Peer)) }), TransactionParsed: events.NewEvent(func(handler interface{}, params ...interface{}) { - handler.(func(*transaction.Transaction, *peer.Peer))(params[0].(*transaction.Transaction), params[1].(*peer.Peer)) + handler.(func(*message.Transaction, *peer.Peer))(params[0].(*message.Transaction), params[1].(*peer.Peer)) }), TransactionRejected: events.NewEvent(func(handler interface{}, params ...interface{}) { - handler.(func(*transaction.Transaction, error, *peer.Peer))(params[0].(*transaction.Transaction), params[1].(error), params[2].(*peer.Peer)) + handler.(func(*message.Transaction, error, *peer.Peer))(params[0].(*message.Transaction), params[1].(error), params[2].(*peer.Peer)) }), }, } @@ -121,13 +121,13 @@ func (transactionParser *TransactionParser) setupTransactionsFilterDataFlow() { numberOfTransactionFilters := len(transactionParser.transactionFilters) for i := 0; i < numberOfTransactionFilters; i++ { if i == numberOfTransactionFilters-1 { - transactionParser.transactionFilters[i].OnAccept(func(tx *transaction.Transaction, peer *peer.Peer) { + transactionParser.transactionFilters[i].OnAccept(func(tx *message.Transaction, peer *peer.Peer) { transactionParser.Events.TransactionParsed.Trigger(tx, peer) }) } else { transactionParser.transactionFilters[i].OnAccept(transactionParser.transactionFilters[i+1].Filter) } - transactionParser.transactionFilters[i].OnReject(func(tx *transaction.Transaction, err error, peer *peer.Peer) { + transactionParser.transactionFilters[i].OnReject(func(tx *message.Transaction, err error, peer *peer.Peer) { transactionParser.Events.TransactionRejected.Trigger(tx, err, peer) }) } @@ -136,7 +136,7 @@ func (transactionParser *TransactionParser) setupTransactionsFilterDataFlow() { } func (transactionParser *TransactionParser) parseTransaction(bytes []byte, peer *peer.Peer) { - if parsedTransaction, err, _ := transaction.FromBytes(bytes); err != nil { + if parsedTransaction, err, _ := message.FromBytes(bytes); err != nil { transactionParser.Events.BytesRejected.Trigger(bytes, err, peer) } else { transactionParser.transactionFilters[0].Filter(parsedTransaction, peer) diff --git a/packages/binary/tangle/transactionparser/transactionparser_test.go b/packages/binary/tangle/transactionparser/transactionparser_test.go index 85309414..9a5f6413 100644 --- a/packages/binary/tangle/transactionparser/transactionparser_test.go +++ b/packages/binary/tangle/transactionparser/transactionparser_test.go @@ -9,12 +9,12 @@ import ( "github.com/iotaledger/hive.go/events" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload/data" ) func BenchmarkTransactionParser_ParseBytesSame(b *testing.B) { - txBytes := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("Test"))).Bytes() + txBytes := message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("Test"))).Bytes() txParser := New() b.ResetTimer() @@ -29,7 +29,7 @@ func BenchmarkTransactionParser_ParseBytesSame(b *testing.B) { func BenchmarkTransactionParser_ParseBytesDifferent(b *testing.B) { transactionBytes := make([][]byte, b.N) for i := 0; i < b.N; i++ { - transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("Test"+strconv.Itoa(i)))).Bytes() + transactionBytes[i] = message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("Test"+strconv.Itoa(i)))).Bytes() } txParser := New() @@ -44,12 +44,12 @@ func BenchmarkTransactionParser_ParseBytesDifferent(b *testing.B) { } func TestTransactionParser_ParseTransaction(t *testing.T) { - tx := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("Test"))) + tx := message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("Test"))) txParser := New() txParser.Parse(tx.Bytes(), nil) - txParser.Events.TransactionParsed.Attach(events.NewClosure(func(tx *transaction.Transaction) { + txParser.Events.TransactionParsed.Attach(events.NewClosure(func(tx *message.Transaction) { fmt.Println("PARSED!!!") })) diff --git a/packages/binary/tangle/transactionrequester/transactionrequester.go b/packages/binary/tangle/transactionrequester/transactionrequester.go index 6f036e81..2016298c 100644 --- a/packages/binary/tangle/transactionrequester/transactionrequester.go +++ b/packages/binary/tangle/transactionrequester/transactionrequester.go @@ -7,11 +7,11 @@ import ( "github.com/iotaledger/hive.go/async" "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" ) type TransactionRequester struct { - scheduledRequests map[transaction.Id]*time.Timer + scheduledRequests map[message.Id]*time.Timer requestWorker async.NonBlockingWorkerPool options *Options Events Events @@ -21,11 +21,11 @@ type TransactionRequester struct { func New(optionalOptions ...Option) *TransactionRequester { requester := &TransactionRequester{ - scheduledRequests: make(map[transaction.Id]*time.Timer), + scheduledRequests: make(map[message.Id]*time.Timer), options: newOptions(optionalOptions), Events: Events{ SendRequest: events.NewEvent(func(handler interface{}, params ...interface{}) { - handler.(func(transaction.Id))(params[0].(transaction.Id)) + handler.(func(message.Id))(params[0].(message.Id)) }), }, } @@ -35,7 +35,7 @@ func New(optionalOptions ...Option) *TransactionRequester { return requester } -func (requester *TransactionRequester) ScheduleRequest(transactionId transaction.Id) { +func (requester *TransactionRequester) ScheduleRequest(transactionId message.Id) { var retryRequest func(bool) retryRequest = func(initialRequest bool) { requester.requestWorker.Submit(func() { @@ -58,7 +58,7 @@ func (requester *TransactionRequester) ScheduleRequest(transactionId transaction retryRequest(true) } -func (requester *TransactionRequester) StopRequest(transactionId transaction.Id) { +func (requester *TransactionRequester) StopRequest(transactionId message.Id) { requester.scheduledRequestsMutex.RLock() if timer, timerExists := requester.scheduledRequests[transactionId]; timerExists { requester.scheduledRequestsMutex.RUnlock() diff --git a/packages/binary/valuetransfer/address/address.go b/packages/binary/valuetransfer/address/address.go index 13e89793..265fbf0c 100644 --- a/packages/binary/valuetransfer/address/address.go +++ b/packages/binary/valuetransfer/address/address.go @@ -11,13 +11,13 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" ) -type AddressVersion = byte +type Version = byte -type AddressDigest = []byte +type Digest = []byte type Address [Length]byte -// Random create a random address, which can for example be used in unit tests. +// Random creates a random address, which can for example be used in unit tests. func Random() (address Address) { // generate a random sequence of bytes addressBytes := make([]byte, Length) @@ -31,7 +31,7 @@ func Random() (address Address) { return } -// FromBase58 creates an address from base58 encoded string. +// FromBase58 creates an address from a base58 encoded string. func FromBase58(base58String string) (address Address, err error) { // decode string bytes, err := base58.Decode(base58String) @@ -52,6 +52,7 @@ func FromBase58(base58String string) (address Address, err error) { return } +// FromED25519PubKey creates an address from an ed25519 public key. func FromED25519PubKey(key ed25119.PublicKey) (address Address) { digest := blake2b.Sum256(key[:]) @@ -75,7 +76,7 @@ func FromBytes(bytes []byte) (result Address, err error, consumedBytes int) { return } -// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +// Parse is a wrapper for simplified unmarshaling of a byte stream using the marshalUtil package. func Parse(marshalUtil *marshalutil.MarshalUtil) (Address, error) { if address, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { return Address{}, err @@ -84,11 +85,13 @@ func Parse(marshalUtil *marshalutil.MarshalUtil) (Address, error) { } } -func (address *Address) GetVersion() AddressVersion { +// Version returns the version of the address, which corresponds to the signature scheme that is used. +func (address *Address) Version() Version { return address[0] } -func (address *Address) GetDigest() AddressDigest { +// Digest returns the digest part of an address (i.e. the hashed version of the ed25519 public key)- +func (address *Address) Digest() Digest { return address[1:] } @@ -102,4 +105,5 @@ func (address Address) String() string { return base58.Encode(address.Bytes()) } +// Length contains the length of an address (digest length = 32 + version byte length = 1). const Length = 33 diff --git a/packages/binary/valuetransfer/payload/transfer/signatures/ed25519.go b/packages/binary/valuetransfer/address/signaturescheme/ed25519.go similarity index 95% rename from packages/binary/valuetransfer/payload/transfer/signatures/ed25519.go rename to packages/binary/valuetransfer/address/signaturescheme/ed25519.go index e7423f55..997de93a 100644 --- a/packages/binary/valuetransfer/payload/transfer/signatures/ed25519.go +++ b/packages/binary/valuetransfer/address/signaturescheme/ed25519.go @@ -1,4 +1,4 @@ -package signatures +package signaturescheme import ( "fmt" @@ -64,7 +64,7 @@ type ed25519Signature struct { // ed25519SignatureFromBytes unmarshals an ed25519 signatures from a sequence of bytes. // It either creates a new signature or fills the optionally provided object with the parsed information. -func ed25519SignatureFromBytes(bytes []byte, optionalTargetObject ...*ed25519Signature) (result *ed25519Signature, err error, consumedBytes int) { +func Ed25519SignatureFromBytes(bytes []byte, optionalTargetObject ...*ed25519Signature) (result *ed25519Signature, err error, consumedBytes int) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -128,7 +128,4 @@ func (signature *ed25519Signature) Address() address.Address { return address.FromED25519PubKey(signature.publicKey) } -// interface contract (allow the compiler to check if the implementation has all of the required methods). -var _ Signature = &ed25519Signature{} - // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/binary/valuetransfer/address/signaturescheme/signature.go b/packages/binary/valuetransfer/address/signaturescheme/signature.go new file mode 100644 index 00000000..1e89e733 --- /dev/null +++ b/packages/binary/valuetransfer/address/signaturescheme/signature.go @@ -0,0 +1,15 @@ +package signaturescheme + +import "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + +// Signature defines an interface for an address signature generated by the corresponding signature scheme. +type Signature interface { + // IsValid returns true if the signature is valid for the given data. + IsValid(signedData []byte) bool + + // Bytes returns a marshaled version of the signature. + Bytes() []byte + + // Address returns the address, that this signature signs. + Address() address.Address +} diff --git a/packages/binary/valuetransfer/address/signaturescheme/signaturescheme.go b/packages/binary/valuetransfer/address/signaturescheme/signaturescheme.go new file mode 100644 index 00000000..2abe2f6a --- /dev/null +++ b/packages/binary/valuetransfer/address/signaturescheme/signaturescheme.go @@ -0,0 +1,17 @@ +package signaturescheme + +import ( + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" +) + +// SignatureScheme defines an interface for different signature generation methods (i.e. ED25519, WOTS, and so on ...). +type SignatureScheme interface { + // Version returns the version byte that is associated to this signature scheme. + Version() byte + + // Address returns the address that this signature scheme instance is securing. + Address() address.Address + + // Sign creates a valid signature for the given data according to the signature scheme implementation. + Sign(data []byte) Signature +} diff --git a/packages/binary/valuetransfer/balance/balance.go b/packages/binary/valuetransfer/balance/balance.go new file mode 100644 index 00000000..e9e3acb2 --- /dev/null +++ b/packages/binary/valuetransfer/balance/balance.go @@ -0,0 +1,79 @@ +package balance + +import ( + "strconv" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" +) + +type Balance struct { + value int64 + color Color +} + +func New(color Color, balance int64) (result *Balance) { + result = &Balance{ + color: color, + value: balance, + } + + return +} + +func FromBytes(bytes []byte) (result *Balance, err error, consumedBytes int) { + result = &Balance{} + + marshalUtil := marshalutil.New(bytes) + + result.value, err = marshalUtil.ReadInt64() + if err != nil { + return + } + + if coinColor, colorErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + return ColorFromBytes(data) + }); colorErr != nil { + return nil, colorErr, marshalUtil.ReadOffset() + } else { + result.color = coinColor.(Color) + } + + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func Parse(marshalUtil *marshalutil.MarshalUtil) (*Balance, error) { + if address, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { + return nil, err + } else { + return address.(*Balance), nil + } +} + +// Value returns the numeric value of the balance. +func (balance *Balance) Value() int64 { + return balance.value +} + +// Color returns the Color of the balance. +func (balance *Balance) Color() Color { + return balance.color +} + +func (balance *Balance) Bytes() []byte { + marshalUtil := marshalutil.New(Length) + + marshalUtil.WriteInt64(balance.value) + marshalUtil.WriteBytes(balance.color.Bytes()) + + return marshalUtil.Bytes() +} + +func (balance *Balance) String() string { + return strconv.FormatInt(balance.value, 10) + " " + balance.color.String() +} + +// Length encodes the length of a marshaled Balance (the length of the color + 8 bytes for the balance). +const Length = 8 + ColorLength diff --git a/packages/binary/valuetransfer/balance/balance_test.go b/packages/binary/valuetransfer/balance/balance_test.go new file mode 100644 index 00000000..98fbd6bb --- /dev/null +++ b/packages/binary/valuetransfer/balance/balance_test.go @@ -0,0 +1,24 @@ +package balance + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMarshalUnmarshal(t *testing.T) { + balance := New(COLOR_IOTA, 1337) + assert.Equal(t, int64(1337), balance.Value()) + assert.Equal(t, COLOR_IOTA, balance.Color()) + + marshaledBalance := balance.Bytes() + assert.Equal(t, Length, len(marshaledBalance)) + + restoredBalance, err, consumedBytes := FromBytes(marshaledBalance) + if err != nil { + panic(err) + } + assert.Equal(t, Length, consumedBytes) + assert.Equal(t, balance.value, restoredBalance.Value()) + assert.Equal(t, balance.color, restoredBalance.Color()) +} diff --git a/packages/binary/valuetransfer/coloredbalance/color/color.go b/packages/binary/valuetransfer/balance/color.go similarity index 51% rename from packages/binary/valuetransfer/coloredbalance/color/color.go rename to packages/binary/valuetransfer/balance/color.go index 5afcc691..a3794188 100644 --- a/packages/binary/valuetransfer/coloredbalance/color/color.go +++ b/packages/binary/valuetransfer/balance/color.go @@ -1,4 +1,4 @@ -package color +package balance import ( "github.com/mr-tron/base58" @@ -6,32 +6,32 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/marshalutil" ) -type Color [Length]byte +type Color [ColorLength]byte -func FromBytes(bytes []byte) (result Color, err error, consumedBytes int) { - colorBytes, err := marshalutil.New(bytes).ReadBytes(Length) +func ColorFromBytes(bytes []byte) (result Color, err error, consumedBytes int) { + colorBytes, err := marshalutil.New(bytes).ReadBytes(ColorLength) if err != nil { return } copy(result[:], colorBytes) - consumedBytes = Length + consumedBytes = ColorLength return } -const Length = 32 +const ColorLength = 32 func (color Color) Bytes() []byte { return color[:] } func (color Color) String() string { - if color == IOTA { + if color == COLOR_IOTA { return "IOTA" } return base58.Encode(color[:]) } -var IOTA Color = [32]byte{} +var COLOR_IOTA Color = [32]byte{} diff --git a/packages/binary/valuetransfer/coloredbalance/coloredbalance.go b/packages/binary/valuetransfer/coloredbalance/coloredbalance.go deleted file mode 100644 index e17e8d68..00000000 --- a/packages/binary/valuetransfer/coloredbalance/coloredbalance.go +++ /dev/null @@ -1,70 +0,0 @@ -package coloredbalance - -import ( - "strconv" - - "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance/color" -) - -type ColoredBalance struct { - color color.Color - balance int64 -} - -func New(color color.Color, balance int64) (result *ColoredBalance) { - result = &ColoredBalance{ - color: color, - balance: balance, - } - - return -} - -func FromBytes(bytes []byte) (result *ColoredBalance, err error, consumedBytes int) { - result = &ColoredBalance{} - - marshalUtil := marshalutil.New(bytes) - - if coinColor, colorErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { - return color.FromBytes(data) - }); colorErr != nil { - return nil, colorErr, marshalUtil.ReadOffset() - } else { - result.color = coinColor.(color.Color) - } - - result.balance, err = marshalUtil.ReadInt64() - if err != nil { - return - } - - consumedBytes = marshalUtil.ReadOffset() - - return -} - -// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. -func Parse(marshalUtil *marshalutil.MarshalUtil) (*ColoredBalance, error) { - if address, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { - return nil, err - } else { - return address.(*ColoredBalance), nil - } -} - -func (balance *ColoredBalance) Bytes() []byte { - marshalUtil := marshalutil.New(color.Length + marshalutil.UINT32_SIZE) - - marshalUtil.WriteBytes(balance.color.Bytes()) - marshalUtil.WriteInt64(balance.balance) - - return marshalUtil.Bytes() -} - -func (balance *ColoredBalance) String() string { - return strconv.FormatInt(balance.balance, 10) + " " + balance.color.String() -} - -// Length encodes the length of a marshaled ColoredBalance (the length of the color + 8 bytes for the balance). -const Length = color.Length + 8 diff --git a/packages/binary/valuetransfer/payload/cached_object.go b/packages/binary/valuetransfer/payload/cached_object.go deleted file mode 100644 index 5c1639b1..00000000 --- a/packages/binary/valuetransfer/payload/cached_object.go +++ /dev/null @@ -1,39 +0,0 @@ -package payload - -import ( - "github.com/iotaledger/hive.go/objectstorage" -) - -// CachedObject is a wrapper for the object storage, that takes care of type casting the managed objects. -// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means -// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of -// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the -// specialized types of CachedObjects, without having to manually type cast over and over again. -type CachedObject struct { - objectstorage.CachedObject -} - -// Retain wraps the underlying method to return a new "wrapped object". -func (cachedPayload *CachedObject) Retain() *CachedObject { - return &CachedObject{cachedPayload.CachedObject.Retain()} -} - -// Consume wraps the underlying method to return the correctly typed objects in the callback. -func (cachedPayload *CachedObject) Consume(consumer func(payload *Payload)) bool { - return cachedPayload.CachedObject.Consume(func(object objectstorage.StorableObject) { - consumer(object.(*Payload)) - }) -} - -// Unwrap provides a way to "Get" a type casted version of the underlying object. -func (cachedPayload *CachedObject) Unwrap() *Payload { - if untypedTransaction := cachedPayload.Get(); untypedTransaction == nil { - return nil - } else { - if typeCastedTransaction := untypedTransaction.(*Payload); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } - } -} diff --git a/packages/binary/valuetransfer/payload/id/id.go b/packages/binary/valuetransfer/payload/id.go similarity index 63% rename from packages/binary/valuetransfer/payload/id/id.go rename to packages/binary/valuetransfer/payload/id.go index 8a8f24f0..d35da661 100644 --- a/packages/binary/valuetransfer/payload/id/id.go +++ b/packages/binary/valuetransfer/payload/id.go @@ -1,4 +1,4 @@ -package id +package payload import ( "fmt" @@ -9,16 +9,16 @@ import ( ) // Id represents the hash of a payload that is used to identify the given payload. -type Id [Length]byte +type Id [IdLength]byte -// New creates a payload id from a base58 encoded string. -func New(base58EncodedString string) (result Id, err error) { +// NewId creates a payload id from a base58 encoded string. +func NewId(base58EncodedString string) (result Id, err error) { bytes, err := base58.Decode(base58EncodedString) if err != nil { return } - if len(bytes) != Length { + if len(bytes) != IdLength { err = fmt.Errorf("length of base58 formatted payload id is wrong") return @@ -29,18 +29,18 @@ func New(base58EncodedString string) (result Id, err error) { return } -// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. -func Parse(marshalUtil *marshalutil.MarshalUtil) (Id, error) { - if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { +// ParseId is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func ParseId(marshalUtil *marshalutil.MarshalUtil) (Id, error) { + if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return IdFromBytes(data) }); err != nil { return Id{}, err } else { return id.(Id), nil } } -// FromBytes unmarshals a payload id from a sequence of bytes. +// IdFromBytes unmarshals a payload id from a sequence of bytes. // It either creates a new payload id or fills the optionally provided object with the parsed information. -func FromBytes(bytes []byte, optionalTargetObject ...*Id) (result Id, err error, consumedBytes int) { +func IdFromBytes(bytes []byte, optionalTargetObject ...*Id) (result Id, err error, consumedBytes int) { // determine the target object that will hold the unmarshaled information var targetObject *Id switch len(optionalTargetObject) { @@ -49,14 +49,14 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Id) (result Id, err error, case 1: targetObject = optionalTargetObject[0] default: - panic("too many arguments in call to FromBytes") + panic("too many arguments in call to IdFromBytes") } // initialize helper marshalUtil := marshalutil.New(bytes) // read id from bytes - idBytes, err := marshalUtil.ReadBytes(Length) + idBytes, err := marshalUtil.ReadBytes(IdLength) if err != nil { return } @@ -81,7 +81,7 @@ func (id Id) Bytes() []byte { } // Empty represents the id encoding the genesis. -var Genesis Id +var GenesisId Id -// Length defined the amount of bytes in a payload id (32 bytes hash value). -const Length = 32 +// IdLength defined the amount of bytes in a payload id (32 bytes hash value). +const IdLength = 32 diff --git a/packages/binary/valuetransfer/payload/id/id_test.go b/packages/binary/valuetransfer/payload/id_test.go similarity index 70% rename from packages/binary/valuetransfer/payload/id/id_test.go rename to packages/binary/valuetransfer/payload/id_test.go index 86fd25ab..22ff3b66 100644 --- a/packages/binary/valuetransfer/payload/id/id_test.go +++ b/packages/binary/valuetransfer/payload/id_test.go @@ -1,4 +1,4 @@ -package id +package payload import ( "testing" @@ -8,14 +8,14 @@ import ( func Test(t *testing.T) { // create variable for id - sourceId, err := New("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") + sourceId, err := NewId("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") if err != nil { panic(err) } // read serialized id into both variables var restoredIdPointer Id - restoredIdValue, err, _ := FromBytes(sourceId.Bytes(), &restoredIdPointer) + restoredIdValue, err, _ := IdFromBytes(sourceId.Bytes(), &restoredIdPointer) if err != nil { panic(err) } diff --git a/packages/binary/valuetransfer/payload/payload.go b/packages/binary/valuetransfer/payload/payload.go index ee248f7d..c97b2f12 100644 --- a/packages/binary/valuetransfer/payload/payload.go +++ b/packages/binary/valuetransfer/payload/payload.go @@ -8,36 +8,34 @@ import ( "golang.org/x/crypto/blake2b" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer" - transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" ) type Payload struct { objectstorage.StorableObjectFlags - trunkPayloadId payloadid.Id - branchPayloadId payloadid.Id - transfer *transfer.Transfer + trunkPayloadId Id + branchPayloadId Id + transaction *transaction.Transaction - id *payloadid.Id + id *Id idMutex sync.RWMutex bytes []byte bytesMutex sync.RWMutex } -func New(trunkPayloadId, branchPayloadId payloadid.Id, valueTransfer *transfer.Transfer) *Payload { +func New(trunkPayloadId, branchPayloadId Id, valueTransfer *transaction.Transaction) *Payload { return &Payload{ trunkPayloadId: trunkPayloadId, branchPayloadId: branchPayloadId, - transfer: valueTransfer, + transaction: valueTransfer, } } func FromStorage(key []byte) objectstorage.StorableObject { - id, err, _ := payloadid.FromBytes(key) + id, err, _ := IdFromBytes(key) if err != nil { panic(err) } @@ -74,25 +72,25 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, } // parse trunk payload id - parsedTrunkPayloadId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return payloadid.FromBytes(data) }) + parsedTrunkPayloadId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return IdFromBytes(data) }) if err != nil { return } - result.trunkPayloadId = parsedTrunkPayloadId.(payloadid.Id) + result.trunkPayloadId = parsedTrunkPayloadId.(Id) // parse branch payload id - parsedBranchPayloadId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return payloadid.FromBytes(data) }) + parsedBranchPayloadId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return IdFromBytes(data) }) if err != nil { return } - result.branchPayloadId = parsedBranchPayloadId.(payloadid.Id) + result.branchPayloadId = parsedBranchPayloadId.(Id) // parse transfer - parsedTransfer, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return transfer.FromBytes(data) }) + parsedTransfer, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return transaction.FromBytes(data) }) if err != nil { return } - result.transfer = parsedTransfer.(*transfer.Transfer) + result.transaction = parsedTransfer.(*transaction.Transaction) // return the number of bytes we processed consumedBytes = marshalUtil.ReadOffset() @@ -103,7 +101,7 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, return } -func (payload *Payload) GetId() payloadid.Id { +func (payload *Payload) Id() Id { // acquire lock for reading id payload.idMutex.RLock() @@ -125,27 +123,27 @@ func (payload *Payload) GetId() payloadid.Id { } // otherwise calculate the id - marshalUtil := marshalutil.New(payloadid.Length + payloadid.Length + transferid.Length) + marshalUtil := marshalutil.New(IdLength + IdLength + transaction.IdLength) marshalUtil.WriteBytes(payload.trunkPayloadId.Bytes()) marshalUtil.WriteBytes(payload.branchPayloadId.Bytes()) - marshalUtil.WriteBytes(payload.GetTransfer().GetId().Bytes()) + marshalUtil.WriteBytes(payload.Transaction().Id().Bytes()) - var id payloadid.Id = blake2b.Sum256(marshalUtil.Bytes()) + var id Id = blake2b.Sum256(marshalUtil.Bytes()) payload.id = &id return id } -func (payload *Payload) GetTrunkId() payloadid.Id { +func (payload *Payload) TrunkId() Id { return payload.trunkPayloadId } -func (payload *Payload) GetBranchId() payloadid.Id { +func (payload *Payload) BranchId() Id { return payload.branchPayloadId } -func (payload *Payload) GetTransfer() *transfer.Transfer { - return payload.transfer +func (payload *Payload) Transaction() *transaction.Transaction { + return payload.transaction } func (payload *Payload) Bytes() (bytes []byte) { @@ -170,13 +168,13 @@ func (payload *Payload) Bytes() (bytes []byte) { } // retrieve bytes of transfer - transferBytes, err := payload.GetTransfer().MarshalBinary() + transferBytes, err := payload.Transaction().MarshalBinary() if err != nil { return } // marshal fields - payloadLength := payloadid.Length + payloadid.Length + len(transferBytes) + payloadLength := IdLength + IdLength + len(transferBytes) marshalUtil := marshalutil.New(marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + payloadLength) marshalUtil.WriteUint32(Type) marshalUtil.WriteUint32(uint32(payloadLength)) @@ -193,10 +191,10 @@ func (payload *Payload) Bytes() (bytes []byte) { func (payload *Payload) String() string { return stringify.Struct("Payload", - stringify.StructField("id", payload.GetId()), - stringify.StructField("trunk", payload.GetTrunkId()), - stringify.StructField("branch", payload.GetBranchId()), - stringify.StructField("transfer", payload.GetTransfer()), + stringify.StructField("id", payload.Id()), + stringify.StructField("trunk", payload.TrunkId()), + stringify.StructField("branch", payload.BranchId()), + stringify.StructField("transfer", payload.Transaction()), ) } @@ -239,7 +237,7 @@ var _ payload.Payload = &Payload{} // UnmarshalBinary(data []byte) (err error) already implemented by Payload func (payload *Payload) GetStorageKey() []byte { - id := payload.GetId() + id := payload.Id() return id[:] } @@ -252,3 +250,37 @@ func (payload *Payload) Update(other objectstorage.StorableObject) { var _ objectstorage.StorableObject = &Payload{} // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// CachedPayload is a wrapper for the object storage, that takes care of type casting the managed objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of CachedObjects, without having to manually type cast over and over again. +type CachedPayload struct { + objectstorage.CachedObject +} + +// Retain wraps the underlying method to return a new "wrapped object". +func (cachedPayload *CachedPayload) Retain() *CachedPayload { + return &CachedPayload{cachedPayload.CachedObject.Retain()} +} + +// Consume wraps the underlying method to return the correctly typed objects in the callback. +func (cachedPayload *CachedPayload) Consume(consumer func(payload *Payload)) bool { + return cachedPayload.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*Payload)) + }) +} + +// Unwrap provides a way to "Get" a type casted version of the underlying object. +func (cachedPayload *CachedPayload) Unwrap() *Payload { + if untypedTransaction := cachedPayload.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*Payload); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} diff --git a/packages/binary/valuetransfer/payload/payload_test.go b/packages/binary/valuetransfer/payload/payload_test.go new file mode 100644 index 00000000..0dc21937 --- /dev/null +++ b/packages/binary/valuetransfer/payload/payload_test.go @@ -0,0 +1,120 @@ +package payload + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" +) + +func ExamplePayload() { + // 1. create value transfer (user provides this) + valueTransfer := transaction.New( + // inputs + transaction.NewInputs( + transaction.NewOutputId(address.Random(), transaction.RandomId()), + transaction.NewOutputId(address.Random(), transaction.RandomId()), + ), + + // outputs + transaction.NewOutputs(map[address.Address][]*balance.Balance{ + address.Random(): { + balance.New(balance.COLOR_IOTA, 1337), + }, + }), + ) + + // 2. create value payload (the ontology creates this and wraps the user provided transfer accordingly) + valuePayload := New( + // trunk in "value transfer ontology" (filled by ontology tipSelector) + GenesisId, + + // branch in "value transfer ontology" (filled by ontology tipSelector) + GenesisId, + + // value transfer + valueTransfer, + ) + + // 3. build actual transaction (the base layer creates this and wraps the ontology provided payload) + tx := message.New( + // trunk in "network tangle" ontology (filled by tipSelector) + message.EmptyId, + + // branch in "network tangle" ontology (filled by tipSelector) + message.EmptyId, + + // issuer of the transaction (signs automatically) + ed25119.GenerateKeyPair(), + + // the time when the transaction was created + time.Now(), + + // the ever increasing sequence number of this transaction + 0, + + // payload + valuePayload, + ) + + fmt.Println(tx) +} + +func TestPayload(t *testing.T) { + addressKeyPair1 := ed25119.GenerateKeyPair() + addressKeyPair2 := ed25119.GenerateKeyPair() + + originalPayload := New( + GenesisId, + GenesisId, + transaction.New( + transaction.NewInputs( + transaction.NewOutputId(address.FromED25519PubKey(addressKeyPair1.PublicKey), transaction.RandomId()), + transaction.NewOutputId(address.FromED25519PubKey(addressKeyPair2.PublicKey), transaction.RandomId()), + ), + + transaction.NewOutputs(map[address.Address][]*balance.Balance{ + address.Random(): { + balance.New(balance.COLOR_IOTA, 1337), + }, + }), + ).Sign( + signaturescheme.ED25519(addressKeyPair1), + ), + ) + + assert.Equal(t, false, originalPayload.Transaction().SignaturesValid()) + + originalPayload.Transaction().Sign( + signaturescheme.ED25519(addressKeyPair2), + ) + + assert.Equal(t, true, originalPayload.Transaction().SignaturesValid()) + + clonedPayload1, err, _ := FromBytes(originalPayload.Bytes()) + if err != nil { + panic(err) + } + + assert.Equal(t, originalPayload.BranchId(), clonedPayload1.BranchId()) + assert.Equal(t, originalPayload.TrunkId(), clonedPayload1.TrunkId()) + assert.Equal(t, originalPayload.Transaction().Bytes(), clonedPayload1.Transaction().Bytes()) + assert.Equal(t, originalPayload.Id(), clonedPayload1.Id()) + assert.Equal(t, true, clonedPayload1.Transaction().SignaturesValid()) + + clonedPayload2, err, _ := FromBytes(clonedPayload1.Bytes()) + if err != nil { + panic(err) + } + + assert.Equal(t, originalPayload.Id(), clonedPayload2.Id()) + assert.Equal(t, true, clonedPayload2.Transaction().SignaturesValid()) +} diff --git a/packages/binary/valuetransfer/payload/transfer/id/id.go b/packages/binary/valuetransfer/payload/transfer/id/id.go deleted file mode 100644 index 22baa614..00000000 --- a/packages/binary/valuetransfer/payload/transfer/id/id.go +++ /dev/null @@ -1,48 +0,0 @@ -package id - -import ( - "github.com/mr-tron/base58" - - "github.com/iotaledger/goshimmer/packages/binary/marshalutil" -) - -type Id [Length]byte - -func New(idBytes []byte) (result Id) { - copy(result[:], idBytes) - - return -} - -// FromBytes unmarshals a transfer id from a sequence of bytes. -func FromBytes(bytes []byte) (result Id, err error, consumedBytes int) { - // parse the bytes - marshalUtil := marshalutil.New(bytes) - idBytes, err := marshalUtil.ReadBytes(Length) - if err != nil { - return - } - copy(result[:], idBytes) - consumedBytes = marshalUtil.ReadOffset() - - return -} - -// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. -func Parse(marshalUtil *marshalutil.MarshalUtil) (Id, error) { - if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { - return Id{}, err - } else { - return id.(Id), nil - } -} - -func (id Id) Bytes() []byte { - return id[:] -} - -func (id Id) String() string { - return base58.Encode(id[:]) -} - -const Length = 32 diff --git a/packages/binary/valuetransfer/payload/transfer/signatures/interfaces.go b/packages/binary/valuetransfer/payload/transfer/signatures/interfaces.go deleted file mode 100644 index 81fe7247..00000000 --- a/packages/binary/valuetransfer/payload/transfer/signatures/interfaces.go +++ /dev/null @@ -1,27 +0,0 @@ -package signatures - -import "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - -// SignatureScheme defines an interface for different signature generation methods (i.e. ED25519, WOTS, and so on ...). -type SignatureScheme interface { - // Version returns the version byte that is associated to this signature scheme. - Version() byte - - // Address returns the address that this signature scheme instance is securing. - Address() address.Address - - // Sign creates a valid signature for the given data according to the signature scheme implementation. - Sign(data []byte) Signature -} - -// Signature defines an interface for an address signature generated by the corresponding signature scheme. -type Signature interface { - // IsValid returns true if the signature is valid for the given data. - IsValid(signedData []byte) bool - - // Bytes returns a marshaled version of the signature. - Bytes() []byte - - // Address returns the address, that this signature signs. - Address() address.Address -} diff --git a/packages/binary/valuetransfer/payload/transfer/transfer.go b/packages/binary/valuetransfer/payload/transfer/transfer.go deleted file mode 100644 index 0703fcba..00000000 --- a/packages/binary/valuetransfer/payload/transfer/transfer.go +++ /dev/null @@ -1,296 +0,0 @@ -package transfer - -import ( - "fmt" - "sync" - - "github.com/iotaledger/hive.go/objectstorage" - "github.com/iotaledger/hive.go/stringify" - "github.com/mr-tron/base58" - "golang.org/x/crypto/blake2b" - - "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/inputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/outputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/signatures" -) - -// region IMPLEMENT Transfer /////////////////////////////////////////////////////////////////////////////////////////// - -type Transfer struct { - objectstorage.StorableObjectFlags - - inputs *inputs.Inputs - outputs *outputs.Outputs - signatures *signatures.Signatures - - id *id.Id - idMutex sync.RWMutex - - essenceBytes []byte - essenceBytesMutex sync.RWMutex - - signatureBytes []byte - signatureBytesMutex sync.RWMutex - - bytes []byte - bytesMutex sync.RWMutex -} - -func New(inputs *inputs.Inputs, outputs *outputs.Outputs) *Transfer { - return &Transfer{ - inputs: inputs, - outputs: outputs, - signatures: signatures.New(), - } -} - -func FromBytes(bytes []byte, optionalTargetObject ...*Transfer) (result *Transfer, err error, consumedBytes int) { - // determine the target object that will hold the unmarshaled information - switch len(optionalTargetObject) { - case 0: - result = &Transfer{} - case 1: - result = optionalTargetObject[0] - default: - panic("too many arguments in call to OutputFromBytes") - } - - // initialize helper - marshalUtil := marshalutil.New(bytes) - - // unmarshal inputs - parsedInputs, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return inputs.FromBytes(data) }) - if err != nil { - return - } - result.inputs = parsedInputs.(*inputs.Inputs) - - // unmarshal outputs - parsedOutputs, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return outputs.FromBytes(data) }) - if err != nil { - return - } - result.outputs = parsedOutputs.(*outputs.Outputs) - - // store essence bytes - essenceBytesCount := marshalUtil.ReadOffset() - result.essenceBytes = make([]byte, essenceBytesCount) - copy(result.essenceBytes, bytes[:essenceBytesCount]) - - // unmarshal outputs - parsedSignatures, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return signatures.FromBytes(data) }) - if err != nil { - return - } - result.signatures = parsedSignatures.(*signatures.Signatures) - - // store signature bytes - signatureBytesCount := marshalUtil.ReadOffset() - essenceBytesCount - result.signatureBytes = make([]byte, signatureBytesCount) - copy(result.signatureBytes, bytes[essenceBytesCount:essenceBytesCount+signatureBytesCount]) - - // return the number of bytes we processed - consumedBytes = essenceBytesCount + signatureBytesCount - - // store bytes, so we don't have to marshal manually - result.bytes = bytes[:consumedBytes] - - return -} - -func FromStorage(key []byte) *Transfer { - transferId := id.New(key) - - return &Transfer{ - id: &transferId, - } -} - -func (transfer *Transfer) GetId() id.Id { - // acquire lock for reading id - transfer.idMutex.RLock() - - // return if id has been calculated already - if transfer.id != nil { - defer transfer.idMutex.RUnlock() - - return *transfer.id - } - - // switch to write lock - transfer.idMutex.RUnlock() - transfer.idMutex.Lock() - defer transfer.idMutex.Unlock() - - // return if id has been calculated in the mean time - if transfer.id != nil { - return *transfer.id - } - - // otherwise calculate the id - idBytes := blake2b.Sum256(transfer.Bytes()) - transferId := id.New(idBytes[:]) - - // cache result for later calls - transfer.id = &transferId - - return transferId -} - -func (transfer *Transfer) SignaturesValid() bool { - signaturesValid := true - transfer.inputs.ForEachAddress(func(address address.Address) bool { - if signature, exists := transfer.signatures.Get(address); !exists || !signature.IsValid(transfer.EssenceBytes()) { - signaturesValid = false - - return false - } - - return true - }) - - return signaturesValid -} - -func (transfer *Transfer) EssenceBytes() []byte { - // acquire read lock on essenceBytes - transfer.essenceBytesMutex.RLock() - - // return essenceBytes if the object has been marshaled already - if transfer.essenceBytes != nil { - defer transfer.essenceBytesMutex.RUnlock() - - return transfer.essenceBytes - } - - // switch to write lock - transfer.essenceBytesMutex.RUnlock() - transfer.essenceBytesMutex.Lock() - defer transfer.essenceBytesMutex.Unlock() - - // return essenceBytes if the object has been marshaled in the mean time - if essenceBytes := transfer.essenceBytes; essenceBytes != nil { - return essenceBytes - } - - // create marshal helper - marshalUtil := marshalutil.New() - - // marshal inputs - marshalUtil.WriteBytes(transfer.inputs.Bytes()) - - // marshal outputs - marshalUtil.WriteBytes(transfer.outputs.Bytes()) - - // store marshaled result - transfer.essenceBytes = marshalUtil.Bytes() - - return transfer.essenceBytes -} - -func (transfer *Transfer) SignatureBytes() []byte { - transfer.signatureBytesMutex.RLock() - if transfer.signatureBytes != nil { - defer transfer.signatureBytesMutex.RUnlock() - - return transfer.signatureBytes - } - - transfer.signatureBytesMutex.RUnlock() - transfer.signatureBytesMutex.Lock() - defer transfer.signatureBytesMutex.Unlock() - - if transfer.signatureBytes != nil { - return transfer.signatureBytes - } - - // generate signatures - transfer.signatureBytes = transfer.signatures.Bytes() - - return transfer.signatureBytes -} - -func (transfer *Transfer) Bytes() []byte { - // acquire read lock on bytes - transfer.bytesMutex.RLock() - - // return bytes if the object has been marshaled already - if transfer.bytes != nil { - defer transfer.bytesMutex.RUnlock() - - return transfer.bytes - } - - // switch to write lock - transfer.bytesMutex.RUnlock() - transfer.bytesMutex.Lock() - defer transfer.bytesMutex.Unlock() - - // return bytes if the object has been marshaled in the mean time - if bytes := transfer.bytes; bytes != nil { - return bytes - } - - // create marshal helper - marshalUtil := marshalutil.New() - - // marshal essence bytes - marshalUtil.WriteBytes(transfer.EssenceBytes()) - - // marshal signature bytes - marshalUtil.WriteBytes(transfer.SignatureBytes()) - - // store marshaled result - transfer.bytes = marshalUtil.Bytes() - - return transfer.bytes -} - -func (transfer *Transfer) Sign(signature signatures.SignatureScheme) *Transfer { - transfer.signatures.Add(signature.Address(), signature.Sign(transfer.EssenceBytes())) - - return transfer -} - -func (transfer *Transfer) String() string { - id := transfer.GetId() - - return stringify.Struct("Transfer"+fmt.Sprintf("(%p)", transfer), - stringify.StructField("id", base58.Encode(id[:])), - stringify.StructField("inputs", transfer.inputs), - stringify.StructField("outputs", transfer.outputs), - ) -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region IMPLEMENT StorableObject interface /////////////////////////////////////////////////////////////////////////// - -// define contract (ensure that the struct fulfills the given interface) -var _ objectstorage.StorableObject = &Transfer{} - -func (transfer *Transfer) GetStorageKey() []byte { - id := transfer.GetId() - - return id[:] -} - -func (transfer *Transfer) Update(other objectstorage.StorableObject) { - panic("update forbidden") -} - -// MarshalBinary returns a bytes representation of the transfer by implementing the encoding.BinaryMarshaler interface. -func (transfer *Transfer) MarshalBinary() ([]byte, error) { - return transfer.Bytes(), nil -} - -func (transfer *Transfer) UnmarshalBinary(bytes []byte) (err error) { - _, err, _ = FromBytes(bytes, transfer) - - return -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/binary/valuetransfer/tangle/attachment.go b/packages/binary/valuetransfer/tangle/attachment.go new file mode 100644 index 00000000..033e3f2b --- /dev/null +++ b/packages/binary/valuetransfer/tangle/attachment.go @@ -0,0 +1,23 @@ +package tangle + +import ( + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" +) + +// Attachment stores the information which transaction was attached by which transaction. We need this to perform +// reverse lookups for which Payloads contain which Transactions. +type Attachment struct { + transactionId transaction.Id + payloadId payload.Id +} + +// TransactionId returns the transaction id of this Attachment. +func (attachment *Attachment) TransactionId() transaction.Id { + return attachment.transactionId +} + +// PayloadId returns the payload id of this Attachment. +func (attachment *Attachment) PayloadId() payload.Id { + return attachment.payloadId +} diff --git a/packages/binary/valuetransfer/tangle/events.go b/packages/binary/valuetransfer/tangle/events.go index 653ae828..15e31ddd 100644 --- a/packages/binary/valuetransfer/tangle/events.go +++ b/packages/binary/valuetransfer/tangle/events.go @@ -4,8 +4,7 @@ import ( "github.com/iotaledger/hive.go/events" "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadmetadata" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" ) type Events struct { @@ -16,6 +15,7 @@ type Events struct { PayloadMissing *events.Event PayloadUnsolidifiable *events.Event TransactionRemoved *events.Event + OutputMissing *events.Event } func newEvents() *Events { @@ -26,16 +26,21 @@ func newEvents() *Events { PayloadMissing: events.NewEvent(payloadIdEvent), PayloadUnsolidifiable: events.NewEvent(payloadIdEvent), TransactionRemoved: events.NewEvent(payloadIdEvent), + OutputMissing: events.NewEvent(outputIdEvent), } } func payloadIdEvent(handler interface{}, params ...interface{}) { - handler.(func(payloadid.Id))(params[0].(payloadid.Id)) + handler.(func(payload.Id))(params[0].(payload.Id)) } func cachedPayloadEvent(handler interface{}, params ...interface{}) { - handler.(func(*payload.CachedObject, *payloadmetadata.CachedObject))( - params[0].(*payload.CachedObject).Retain(), - params[1].(*payloadmetadata.CachedObject).Retain(), + handler.(func(*payload.CachedPayload, *CachedPayloadMetadata))( + params[0].(*payload.CachedPayload).Retain(), + params[1].(*CachedPayloadMetadata).Retain(), ) } + +func outputIdEvent(handler interface{}, params ...interface{}) { + handler.(func(transaction.OutputId))(params[0].(transaction.OutputId)) +} diff --git a/packages/binary/valuetransfer/tangle/missingoutput.go b/packages/binary/valuetransfer/tangle/missingoutput.go new file mode 100644 index 00000000..039bc60c --- /dev/null +++ b/packages/binary/valuetransfer/tangle/missingoutput.go @@ -0,0 +1,109 @@ +package tangle + +import ( + "time" + + "github.com/iotaledger/hive.go/objectstorage" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" +) + +// MissingPayload represents an Output that was referenced by a Transaction, but that is missing in our object storage. +type MissingOutput struct { + objectstorage.StorableObjectFlags + + outputId transaction.OutputId + missingSince time.Time +} + +// NewMissingOutput creates a new MissingOutput object, that . +func NewMissingOutput(outputId transaction.OutputId) *MissingOutput { + return &MissingOutput{ + outputId: outputId, + missingSince: time.Now(), + } +} + +// MissingOutput unmarshals a MissingOutput from a sequence of bytes - it either creates a new object or fills the +// optionally provided one with the parsed information. +func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &MissingOutput{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to MissingOutputFromBytes") + } + + // parse the bytes + marshalUtil := marshalutil.New(bytes) + if result.outputId, err = transaction.ParseOutputId(marshalUtil); err != nil { + return + } + if result.missingSince, err = marshalUtil.ReadTime(); err != nil { + return + } + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// MissingOutputFromStorage gets called when we restore a MissingOutput from the storage. The content will be +// unmarshaled by an external caller using the binary.MarshalBinary interface. +func MissingOutputFromStorage(keyBytes []byte) objectstorage.StorableObject { + outputId, err, _ := transaction.OutputIdFromBytes(keyBytes) + if err != nil { + panic(err) + } + + return &MissingOutput{ + outputId: outputId, + } +} + +// Id returns the id of the Output that is missing. +func (missingOutput *MissingOutput) Id() transaction.OutputId { + return missingOutput.outputId +} + +// MissingSince returns the Time since the transaction was first reported as being missing. +func (missingOutput *MissingOutput) MissingSince() time.Time { + return missingOutput.missingSince +} + +// Bytes marshals the MissingOutput into a sequence of bytes. +func (missingOutput *MissingOutput) Bytes() []byte { + marshalUtil := marshalutil.New() + + marshalUtil.WriteBytes(missingOutput.outputId.Bytes()) + marshalUtil.WriteTime(missingOutput.missingSince) + + return marshalUtil.Bytes() +} + +// GetStorageKey returns the key that is used to store the object in the object storage. +func (missingOutput *MissingOutput) GetStorageKey() []byte { + return missingOutput.outputId.Bytes() +} + +// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. +func (missingOutput *MissingOutput) Update(other objectstorage.StorableObject) { + panic("implement me") +} + +// MarshalBinary returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler +// interface. +func (missingOutput *MissingOutput) MarshalBinary() (data []byte, err error) { + return missingOutput.Bytes(), nil +} + +// UnmarshalBinary restores the values of a MissingOutput from a sequence of bytes using the encoding.BinaryUnmarshaler +// interface. +func (missingOutput *MissingOutput) UnmarshalBinary(data []byte) (err error) { + _, err, _ = MissingOutputFromBytes(data, missingOutput) + + return +} diff --git a/packages/binary/valuetransfer/tangle/missingpayload/missingpayload.go b/packages/binary/valuetransfer/tangle/missingpayload.go similarity index 72% rename from packages/binary/valuetransfer/tangle/missingpayload/missingpayload.go rename to packages/binary/valuetransfer/tangle/missingpayload.go index 38afa809..c4eb6532 100644 --- a/packages/binary/valuetransfer/tangle/missingpayload/missingpayload.go +++ b/packages/binary/valuetransfer/tangle/missingpayload.go @@ -1,4 +1,4 @@ -package missingpayload +package tangle import ( "time" @@ -6,7 +6,7 @@ import ( "github.com/iotaledger/hive.go/objectstorage" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" ) // MissingPayload represents a payload that was referenced through branch or trunk but that is missing in our object @@ -14,21 +14,21 @@ import ( type MissingPayload struct { objectstorage.StorableObjectFlags - payloadId payloadid.Id + payloadId payload.Id missingSince time.Time } -// New creates an entry for a missing value transfer payload. -func New(payloadId payloadid.Id) *MissingPayload { +// NewMissingPayload creates an entry for a missing value transfer payload. +func NewMissingPayload(payloadId payload.Id) *MissingPayload { return &MissingPayload{ payloadId: payloadId, missingSince: time.Now(), } } -// FromBytes unmarshals an entry for a missing value transfer payload from a sequence of bytes. +// MissingPayloadFromBytes unmarshals an entry for a missing value transfer payload from a sequence of bytes. // It either creates a new entry or fills the optionally provided one with the parsed information. -func FromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) { +func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -36,12 +36,12 @@ func FromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *M case 1: result = optionalTargetObject[0] default: - panic("too many arguments in call to FromBytes") + panic("too many arguments in call to MissingPayloadFromBytes") } // parse the bytes marshalUtil := marshalutil.New(bytes) - if result.payloadId, err = payloadid.Parse(marshalUtil); err != nil { + if result.payloadId, err = payload.ParseId(marshalUtil); err != nil { return } if result.missingSince, err = marshalUtil.ReadTime(); err != nil { @@ -52,14 +52,14 @@ func FromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *M return } -// FromStorage gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and +// MissingPayloadFromStorage gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and // the content will be unmarshaled by an external caller using the binary.MarshalBinary interface. -func FromStorage([]byte) objectstorage.StorableObject { +func MissingPayloadFromStorage([]byte) objectstorage.StorableObject { return &MissingPayload{} } // GetId returns the payload id, that is missing. -func (missingPayload *MissingPayload) GetId() payloadid.Id { +func (missingPayload *MissingPayload) GetId() payload.Id { return missingPayload.payloadId } @@ -97,7 +97,7 @@ func (missingPayload *MissingPayload) MarshalBinary() (data []byte, err error) { // UnmarshalBinary is required to match the encoding.BinaryUnmarshaler interface. func (missingPayload *MissingPayload) UnmarshalBinary(data []byte) (err error) { - _, err, _ = FromBytes(data, missingPayload) + _, err, _ = MissingPayloadFromBytes(data, missingPayload) return } diff --git a/packages/binary/valuetransfer/tangle/payloadapprover.go b/packages/binary/valuetransfer/tangle/payloadapprover.go new file mode 100644 index 00000000..e8637925 --- /dev/null +++ b/packages/binary/valuetransfer/tangle/payloadapprover.go @@ -0,0 +1,129 @@ +package tangle + +import ( + "github.com/iotaledger/hive.go/objectstorage" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" +) + +// PayloadApprover is a database entity, that allows us to keep track of the "tangle structure" by encoding which +// payload approves which other payload. It allows us to traverse the tangle in the opposite direction of the referenced +// trunk and branch payloads. +type PayloadApprover struct { + objectstorage.StorableObjectFlags + + storageKey []byte + referencedPayloadId payload.Id + approvingPayloadId payload.Id +} + +// NewPayloadApprover creates an approver object that encodes a single relation between an approved and an approving payload. +func NewPayloadApprover(referencedPayload payload.Id, approvingPayload payload.Id) *PayloadApprover { + marshalUtil := marshalutil.New(payload.IdLength + payload.IdLength) + marshalUtil.WriteBytes(referencedPayload.Bytes()) + marshalUtil.WriteBytes(approvingPayload.Bytes()) + + return &PayloadApprover{ + referencedPayloadId: referencedPayload, + approvingPayloadId: approvingPayload, + storageKey: marshalUtil.Bytes(), + } +} + +// PayloadApproverFromStorage get's called when we restore transaction metadata from the storage. +// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalBinary +// method. +func PayloadApproverFromStorage(idBytes []byte) objectstorage.StorableObject { + marshalUtil := marshalutil.New(idBytes) + + referencedPayloadId, err := payload.ParseId(marshalUtil) + if err != nil { + panic(err) + } + approvingPayloadId, err := payload.ParseId(marshalUtil) + if err != nil { + panic(err) + } + + result := &PayloadApprover{ + referencedPayloadId: referencedPayloadId, + approvingPayloadId: approvingPayloadId, + storageKey: marshalUtil.Bytes(true), + } + + return result +} + +// GetApprovingPayloadId returns the id of the approving payload. +func (payloadApprover *PayloadApprover) GetApprovingPayloadId() payload.Id { + return payloadApprover.approvingPayloadId +} + +// GetStorageKey returns the key that is used to store the object in the database. +// It is required to match StorableObject interface. +func (payloadApprover *PayloadApprover) GetStorageKey() []byte { + return payloadApprover.storageKey +} + +// MarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything, +// since all of the information about an approver are stored in the "key". +func (payloadApprover *PayloadApprover) MarshalBinary() (data []byte, err error) { + return +} + +// UnmarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything, +// since all of the information about an approver are stored in the "key". +func (payloadApprover *PayloadApprover) UnmarshalBinary(data []byte) error { + return nil +} + +// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. +// It is required to match StorableObject interface. +func (payloadApprover *PayloadApprover) Update(other objectstorage.StorableObject) { + panic("implement me") +} + +// CachedPayloadApprover is a wrapper for the object storage, that takes care of type casting the managed objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of CachedApprovers, without having to manually type cast over and over again. +type CachedPayloadApprover struct { + objectstorage.CachedObject +} + +// Retain wraps the underlying method to return a new "wrapped object". +func (cachedPayloadApprover *CachedPayloadApprover) Retain() *CachedPayloadApprover { + return &CachedPayloadApprover{cachedPayloadApprover.CachedObject.Retain()} +} + +// Consume wraps the underlying method to return the correctly typed objects in the callback. +func (cachedPayloadApprover *CachedPayloadApprover) Consume(consumer func(payload *PayloadApprover)) bool { + return cachedPayloadApprover.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*PayloadApprover)) + }) +} + +// Unwrap provides a way to "Get" a type casted version of the underlying object. +func (cachedPayloadApprover *CachedPayloadApprover) Unwrap() *PayloadApprover { + if untypedTransaction := cachedPayloadApprover.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*PayloadApprover); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} + +type CachedApprovers []*CachedPayloadApprover + +func (cachedApprovers CachedApprovers) Consume(consumer func(approver *PayloadApprover)) (consumed bool) { + for _, cachedApprover := range cachedApprovers { + consumed = cachedApprover.Consume(consumer) || consumed + } + + return +} diff --git a/packages/binary/valuetransfer/tangle/payloadapprover/cached_object.go b/packages/binary/valuetransfer/tangle/payloadapprover/cached_object.go deleted file mode 100644 index b90c7042..00000000 --- a/packages/binary/valuetransfer/tangle/payloadapprover/cached_object.go +++ /dev/null @@ -1,49 +0,0 @@ -package payloadapprover - -import ( - "github.com/iotaledger/hive.go/objectstorage" -) - -// CachedObject is a wrapper for the object storage, that takes care of type casting the managed objects. -// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means -// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of -// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the -// specialized types of CachedObjects, without having to manually type cast over and over again. -type CachedObject struct { - objectstorage.CachedObject -} - -// Retain wraps the underlying method to return a new "wrapped object". -func (cachedApprover *CachedObject) Retain() *CachedObject { - return &CachedObject{cachedApprover.CachedObject.Retain()} -} - -// Consume wraps the underlying method to return the correctly typed objects in the callback. -func (cachedApprover *CachedObject) Consume(consumer func(payload *PayloadApprover)) bool { - return cachedApprover.CachedObject.Consume(func(object objectstorage.StorableObject) { - consumer(object.(*PayloadApprover)) - }) -} - -// Unwrap provides a way to "Get" a type casted version of the underlying object. -func (cachedApprover *CachedObject) Unwrap() *PayloadApprover { - if untypedTransaction := cachedApprover.Get(); untypedTransaction == nil { - return nil - } else { - if typeCastedTransaction := untypedTransaction.(*PayloadApprover); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } - } -} - -type CachedObjects []*CachedObject - -func (cachedApprovers CachedObjects) Consume(consumer func(approver *PayloadApprover)) (consumed bool) { - for _, cachedApprover := range cachedApprovers { - consumed = cachedApprover.Consume(consumer) || consumed - } - - return -} diff --git a/packages/binary/valuetransfer/tangle/payloadapprover/payloadapprover.go b/packages/binary/valuetransfer/tangle/payloadapprover/payloadapprover.go deleted file mode 100644 index 7c92ae68..00000000 --- a/packages/binary/valuetransfer/tangle/payloadapprover/payloadapprover.go +++ /dev/null @@ -1,85 +0,0 @@ -package payloadapprover - -import ( - "github.com/iotaledger/hive.go/objectstorage" - - "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" -) - -// PayloadApprover is a database entity, that allows us to keep track of the "tangle structure" by encoding which -// payload approves which other payload. It allows us to traverse the tangle in the opposite direction of the referenced -// trunk and branch payloads. -type PayloadApprover struct { - objectstorage.StorableObjectFlags - - storageKey []byte - referencedPayloadId payloadid.Id - approvingPayloadId payloadid.Id -} - -// New creates an approver object that encodes a single relation between an approved and an approving payload. -func New(referencedPayload payloadid.Id, approvingPayload payloadid.Id) *PayloadApprover { - marshalUtil := marshalutil.New(payloadid.Length + payloadid.Length) - marshalUtil.WriteBytes(referencedPayload.Bytes()) - marshalUtil.WriteBytes(approvingPayload.Bytes()) - - return &PayloadApprover{ - referencedPayloadId: referencedPayload, - approvingPayloadId: approvingPayload, - storageKey: marshalUtil.Bytes(), - } -} - -// FromStorage get's called when we restore transaction metadata from the storage. -// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalBinary -// method. -func FromStorage(idBytes []byte) objectstorage.StorableObject { - marshalUtil := marshalutil.New(idBytes) - - referencedPayloadId, err := payloadid.Parse(marshalUtil) - if err != nil { - panic(err) - } - approvingPayloadId, err := payloadid.Parse(marshalUtil) - if err != nil { - panic(err) - } - - result := &PayloadApprover{ - referencedPayloadId: referencedPayloadId, - approvingPayloadId: approvingPayloadId, - storageKey: marshalUtil.Bytes(true), - } - - return result -} - -// GetApprovingPayloadId returns the id of the approving payload. -func (approver *PayloadApprover) GetApprovingPayloadId() payloadid.Id { - return approver.approvingPayloadId -} - -// GetStorageKey returns the key that is used to store the object in the database. -// It is required to match StorableObject interface. -func (approver *PayloadApprover) GetStorageKey() []byte { - return approver.storageKey -} - -// MarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything, -// since all of the information about an approver are stored in the "key". -func (approver *PayloadApprover) MarshalBinary() (data []byte, err error) { - return -} - -// UnmarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything, -// since all of the information about an approver are stored in the "key". -func (approver *PayloadApprover) UnmarshalBinary(data []byte) error { - return nil -} - -// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. -// It is required to match StorableObject interface. -func (approver *PayloadApprover) Update(other objectstorage.StorableObject) { - panic("implement me") -} diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata.go b/packages/binary/valuetransfer/tangle/payloadmetadata.go similarity index 59% rename from packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata.go rename to packages/binary/valuetransfer/tangle/payloadmetadata.go index b6eb53fb..d693c86e 100644 --- a/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata.go +++ b/packages/binary/valuetransfer/tangle/payloadmetadata.go @@ -1,4 +1,4 @@ -package payloadmetadata +package tangle import ( "sync" @@ -8,7 +8,7 @@ import ( "github.com/iotaledger/hive.go/stringify" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" ) // PayloadMetadata is a container for the metadata of a value transfer payload. @@ -16,7 +16,7 @@ import ( type PayloadMetadata struct { objectstorage.StorableObjectFlags - payloadId payloadid.Id + payloadId payload.Id solid bool solidificationTime time.Time @@ -24,16 +24,16 @@ type PayloadMetadata struct { solidificationTimeMutex sync.RWMutex } -// New creates an empty container for the metadata of a value transfer payload. -func New(payloadId payloadid.Id) *PayloadMetadata { +// NewPayloadMetadata creates an empty container for the metadata of a value transfer payload. +func NewPayloadMetadata(payloadId payload.Id) *PayloadMetadata { return &PayloadMetadata{ payloadId: payloadId, } } -// FromBytes unmarshals a container with the metadata of a value transfer payload from a sequence of bytes. +// PayloadMetadataFromBytes unmarshals a container with the metadata of a value transfer payload from a sequence of bytes. // It either creates a new container or fills the optionally provided container with the parsed information. -func FromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) { +func PayloadMetadataFromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -41,12 +41,12 @@ func FromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result * case 1: result = optionalTargetObject[0] default: - panic("too many arguments in call to FromBytes") + panic("too many arguments in call to PayloadMetadataFromBytes") } // parse the bytes marshalUtil := marshalutil.New(bytes) - if result.payloadId, err = payloadid.Parse(marshalUtil); err != nil { + if result.payloadId, err = payload.ParseId(marshalUtil); err != nil { return } if result.solidificationTime, err = marshalUtil.ReadTime(); err != nil { @@ -60,22 +60,22 @@ func FromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result * return } -// FromStorage gets called when we restore transaction metadata from the storage. The bytes and the content will be +// PayloadMetadataFromStorage gets called when we restore transaction metadata from the storage. The bytes and the content will be // unmarshaled by an external caller using the binary.MarshalBinary interface. -func FromStorage(id []byte) objectstorage.StorableObject { +func PayloadMetadataFromStorage(id []byte) objectstorage.StorableObject { result := &PayloadMetadata{} var err error - if result.payloadId, err = payloadid.Parse(marshalutil.New(id)); err != nil { + if result.payloadId, err = payload.ParseId(marshalutil.New(id)); err != nil { panic(err) } return result } -// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. -func Parse(marshalUtil *marshalutil.MarshalUtil) (*PayloadMetadata, error) { - if payloadMetadata, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { +// ParsePayloadMetadata is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func ParsePayloadMetadata(marshalUtil *marshalutil.MarshalUtil) (*PayloadMetadata, error) { + if payloadMetadata, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return PayloadMetadataFromBytes(data) }); err != nil { return nil, err } else { return payloadMetadata.(*PayloadMetadata), nil @@ -83,11 +83,11 @@ func Parse(marshalUtil *marshalutil.MarshalUtil) (*PayloadMetadata, error) { } // GetPayloadId return the id of the payload that this metadata is associated to. -func (payloadMetadata *PayloadMetadata) GetPayloadId() payloadid.Id { +func (payloadMetadata *PayloadMetadata) GetPayloadId() payload.Id { return payloadMetadata.payloadId } -// IsSolid returns true of the payload has been marked as solid. +// IsSolid returns true if the payload has been marked as solid. func (payloadMetadata *PayloadMetadata) IsSolid() (result bool) { payloadMetadata.solidMutex.RLock() result = payloadMetadata.solid @@ -172,7 +172,41 @@ func (payloadMetadata *PayloadMetadata) MarshalBinary() ([]byte, error) { // UnmarshalBinary is required to match the encoding.BinaryUnmarshaler interface. func (payloadMetadata *PayloadMetadata) UnmarshalBinary(data []byte) (err error) { - _, err, _ = FromBytes(data, payloadMetadata) + _, err, _ = PayloadMetadataFromBytes(data, payloadMetadata) return } + +// CachedPayloadMetadata is a wrapper for the object storage, that takes care of type casting the managed objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of CachedObjects, without having to manually type cast over and over again. +type CachedPayloadMetadata struct { + objectstorage.CachedObject +} + +// Retain wraps the underlying method to return a new "wrapped object". +func (cachedPayloadMetadata *CachedPayloadMetadata) Retain() *CachedPayloadMetadata { + return &CachedPayloadMetadata{cachedPayloadMetadata.CachedObject.Retain()} +} + +// Consume wraps the underlying method to return the correctly typed objects in the callback. +func (cachedPayloadMetadata *CachedPayloadMetadata) Consume(consumer func(payload *PayloadMetadata)) bool { + return cachedPayloadMetadata.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*PayloadMetadata)) + }) +} + +// Unwrap provides a way to "Get" a type casted version of the underlying object. +func (cachedPayloadMetadata *CachedPayloadMetadata) Unwrap() *PayloadMetadata { + if untypedTransaction := cachedPayloadMetadata.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*PayloadMetadata); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata/cached_object.go b/packages/binary/valuetransfer/tangle/payloadmetadata/cached_object.go deleted file mode 100644 index bde06d7c..00000000 --- a/packages/binary/valuetransfer/tangle/payloadmetadata/cached_object.go +++ /dev/null @@ -1,39 +0,0 @@ -package payloadmetadata - -import ( - "github.com/iotaledger/hive.go/objectstorage" -) - -// CachedObject is a wrapper for the object storage, that takes care of type casting the managed objects. -// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means -// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of -// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the -// specialized types of CachedObjects, without having to manually type cast over and over again. -type CachedObject struct { - objectstorage.CachedObject -} - -// Retain wraps the underlying method to return a new "wrapped object". -func (cachedPayload *CachedObject) Retain() *CachedObject { - return &CachedObject{cachedPayload.CachedObject.Retain()} -} - -// Consume wraps the underlying method to return the correctly typed objects in the callback. -func (cachedPayload *CachedObject) Consume(consumer func(payload *PayloadMetadata)) bool { - return cachedPayload.CachedObject.Consume(func(object objectstorage.StorableObject) { - consumer(object.(*PayloadMetadata)) - }) -} - -// Unwrap provides a way to "Get" a type casted version of the underlying object. -func (cachedPayload *CachedObject) Unwrap() *PayloadMetadata { - if untypedTransaction := cachedPayload.Get(); untypedTransaction == nil { - return nil - } else { - if typeCastedTransaction := untypedTransaction.(*PayloadMetadata); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } - } -} diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata_test.go b/packages/binary/valuetransfer/tangle/payloadmetadata_test.go similarity index 80% rename from packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata_test.go rename to packages/binary/valuetransfer/tangle/payloadmetadata_test.go index fd85c6f5..cd50258b 100644 --- a/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata_test.go +++ b/packages/binary/valuetransfer/tangle/payloadmetadata_test.go @@ -1,4 +1,4 @@ -package payloadmetadata +package tangle import ( "testing" @@ -6,13 +6,13 @@ import ( "github.com/stretchr/testify/assert" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" ) func TestMarshalUnmarshal(t *testing.T) { - originalMetadata := New(id.Genesis) + originalMetadata := NewPayloadMetadata(payload.GenesisId) - clonedMetadata, err, _ := FromBytes(originalMetadata.Bytes()) + clonedMetadata, err, _ := PayloadMetadataFromBytes(originalMetadata.Bytes()) if err != nil { panic(err) } @@ -23,7 +23,7 @@ func TestMarshalUnmarshal(t *testing.T) { originalMetadata.SetSolid(true) - clonedMetadata, err, _ = FromBytes(originalMetadata.Bytes()) + clonedMetadata, err, _ = PayloadMetadataFromBytes(originalMetadata.Bytes()) if err != nil { panic(err) } @@ -34,7 +34,7 @@ func TestMarshalUnmarshal(t *testing.T) { } func TestPayloadMetadata_SetSolid(t *testing.T) { - originalMetadata := New(id.Genesis) + originalMetadata := NewPayloadMetadata(payload.GenesisId) assert.Equal(t, false, originalMetadata.IsSolid()) assert.Equal(t, time.Time{}, originalMetadata.GetSoldificationTime()) diff --git a/packages/binary/valuetransfer/tangle/tangle.go b/packages/binary/valuetransfer/tangle/tangle.go index 39c97d71..5c61b2b7 100644 --- a/packages/binary/valuetransfer/tangle/tangle.go +++ b/packages/binary/valuetransfer/tangle/tangle.go @@ -2,6 +2,7 @@ package tangle import ( "container/list" + "fmt" "time" "github.com/dgraph-io/badger/v2" @@ -9,11 +10,8 @@ import ( "github.com/iotaledger/hive.go/objectstorage" "github.com/iotaledger/goshimmer/packages/binary/storageprefix" - valuepayload "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/missingpayload" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadapprover" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadmetadata" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" ) // Tangle represents the value tangle that consists out of value payloads. @@ -26,6 +24,9 @@ type Tangle struct { approverStorage *objectstorage.ObjectStorage missingPayloadStorage *objectstorage.ObjectStorage + transactionOutputMetadataStorage *objectstorage.ObjectStorage + missingOutputStorage *objectstorage.ObjectStorage + Events Events storePayloadWorkerPool async.WorkerPool @@ -37,10 +38,13 @@ func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) { result = &Tangle{ storageId: storageId, - payloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayload...), valuepayload.FromStorage, objectstorage.CacheTime(time.Second)), - payloadMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayloadMetadata...), payloadmetadata.FromStorage, objectstorage.CacheTime(time.Second)), - approverStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferApprover...), payloadapprover.FromStorage, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payloadid.Length, payloadid.Length), objectstorage.KeysOnly(true)), - missingPayloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), missingpayload.FromStorage, objectstorage.CacheTime(time.Second)), + payloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayload...), payload.FromStorage, objectstorage.CacheTime(time.Second)), + payloadMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayloadMetadata...), PayloadMetadataFromStorage, objectstorage.CacheTime(time.Second)), + approverStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferApprover...), PayloadApproverFromStorage, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)), + missingPayloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingPayloadFromStorage, objectstorage.CacheTime(time.Second)), + + transactionOutputMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), transaction.OutputFromStorage, objectstorage.CacheTime(time.Second)), + missingOutputStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingOutputFromStorage, objectstorage.CacheTime(time.Second)), Events: *newEvents(), } @@ -49,25 +53,25 @@ func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) { } // AttachPayload adds a new payload to the value tangle. -func (tangle *Tangle) AttachPayload(payload *valuepayload.Payload) { +func (tangle *Tangle) AttachPayload(payload *payload.Payload) { tangle.storePayloadWorkerPool.Submit(func() { tangle.storePayloadWorker(payload) }) } // GetPayload retrieves a payload from the object storage. -func (tangle *Tangle) GetPayload(payloadId payloadid.Id) *valuepayload.CachedObject { - return &valuepayload.CachedObject{CachedObject: tangle.payloadStorage.Load(payloadId.Bytes())} +func (tangle *Tangle) GetPayload(payloadId payload.Id) *payload.CachedPayload { + return &payload.CachedPayload{CachedObject: tangle.payloadStorage.Load(payloadId.Bytes())} } // GetPayloadMetadata retrieves the metadata of a value payload from the object storage. -func (tangle *Tangle) GetPayloadMetadata(payloadId payloadid.Id) *payloadmetadata.CachedObject { - return &payloadmetadata.CachedObject{CachedObject: tangle.payloadMetadataStorage.Load(payloadId.Bytes())} +func (tangle *Tangle) GetPayloadMetadata(payloadId payload.Id) *CachedPayloadMetadata { + return &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Load(payloadId.Bytes())} } // GetApprovers retrieves the approvers of a payload from the object storage. -func (tangle *Tangle) GetApprovers(transactionId payloadid.Id) payloadapprover.CachedObjects { - approvers := make(payloadapprover.CachedObjects, 0) +func (tangle *Tangle) GetApprovers(transactionId payload.Id) CachedApprovers { + approvers := make(CachedApprovers, 0) tangle.approverStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { - approvers = append(approvers, &payloadapprover.CachedObject{CachedObject: cachedObject}) + approvers = append(approvers, &CachedPayloadApprover{CachedObject: cachedObject}) return true }, transactionId[:]) @@ -106,26 +110,26 @@ func (tangle *Tangle) Prune() error { } // storePayloadWorker is the worker function that stores the payload and calls the corresponding storage events. -func (tangle *Tangle) storePayloadWorker(payload *valuepayload.Payload) { +func (tangle *Tangle) storePayloadWorker(payloadToStore *payload.Payload) { // store payload - var cachedPayload *valuepayload.CachedObject - if _tmp, transactionIsNew := tangle.payloadStorage.StoreIfAbsent(payload); !transactionIsNew { + var cachedPayload *payload.CachedPayload + if _tmp, transactionIsNew := tangle.payloadStorage.StoreIfAbsent(payloadToStore); !transactionIsNew { return } else { - cachedPayload = &valuepayload.CachedObject{CachedObject: _tmp} + cachedPayload = &payload.CachedPayload{CachedObject: _tmp} } // store payload metadata - payloadId := payload.GetId() - cachedMetadata := &payloadmetadata.CachedObject{CachedObject: tangle.payloadMetadataStorage.Store(payloadmetadata.New(payloadId))} + payloadId := payloadToStore.Id() + cachedMetadata := &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Store(NewPayloadMetadata(payloadId))} // store trunk approver - trunkId := payload.GetTrunkId() - tangle.approverStorage.Store(payloadapprover.New(trunkId, payloadId)).Release() + trunkId := payloadToStore.TrunkId() + tangle.approverStorage.Store(NewPayloadApprover(trunkId, payloadId)).Release() // store branch approver - if branchId := payload.GetBranchId(); branchId != trunkId { - tangle.approverStorage.Store(payloadapprover.New(branchId, trunkId)).Release() + if branchId := payloadToStore.BranchId(); branchId != trunkId { + tangle.approverStorage.Store(NewPayloadApprover(branchId, trunkId)).Release() } // trigger events @@ -134,21 +138,39 @@ func (tangle *Tangle) storePayloadWorker(payload *valuepayload.Payload) { } tangle.Events.PayloadAttached.Trigger(cachedPayload, cachedMetadata) + // retrieve or store TransactionMetadata + newTransaction := false + transactionId := cachedPayload.Unwrap().Transaction().Id() + cachedTransactionMetadata := &CachedTransactionMetadata{CachedObject: tangle.payloadMetadataStorage.ComputeIfAbsent(transactionId.Bytes(), func(key []byte) objectstorage.StorableObject { + newTransaction = true + + result := NewTransactionMetadata(transactionId) + result.Persist() + result.SetModified() + + return result + })} + + // if the transaction is new, store the Consumers. + if newTransaction { + fmt.Println("git aWADD") + } + // check solidity tangle.solidifierWorkerPool.Submit(func() { - tangle.solidifyTransactionWorker(cachedPayload, cachedMetadata) + tangle.solidifyTransactionWorker(cachedPayload, cachedMetadata, cachedTransactionMetadata) }) } // solidifyTransactionWorker is the worker function that solidifies the payloads (recursively from past to present). -func (tangle *Tangle) solidifyTransactionWorker(cachedPayload *valuepayload.CachedObject, cachedMetadata *payloadmetadata.CachedObject) { - popElementsFromStack := func(stack *list.List) (*valuepayload.CachedObject, *payloadmetadata.CachedObject) { +func (tangle *Tangle) solidifyTransactionWorker(cachedPayload *payload.CachedPayload, cachedMetadata *CachedPayloadMetadata, cachedTransactionMetadata *CachedTransactionMetadata) { + popElementsFromStack := func(stack *list.List) (*payload.CachedPayload, *CachedPayloadMetadata) { currentSolidificationEntry := stack.Front() currentCachedPayload := currentSolidificationEntry.Value.([2]interface{})[0] currentCachedMetadata := currentSolidificationEntry.Value.([2]interface{})[1] stack.Remove(currentSolidificationEntry) - return currentCachedPayload.(*valuepayload.CachedObject), currentCachedMetadata.(*payloadmetadata.CachedObject) + return currentCachedPayload.(*payload.CachedPayload), currentCachedMetadata.(*CachedPayloadMetadata) } // initialize the stack @@ -164,33 +186,74 @@ func (tangle *Tangle) solidifyTransactionWorker(cachedPayload *valuepayload.Cach if currentPayload == nil || currentMetadata == nil { currentCachedPayload.Release() currentCachedMetadata.Release() + cachedTransactionMetadata.Release() continue } // if current transaction is solid and was not marked as solid before: mark as solid and propagate - if tangle.isPayloadSolid(currentPayload, currentMetadata) && currentMetadata.SetSolid(true) { - tangle.Events.PayloadSolid.Trigger(currentCachedPayload, currentCachedMetadata) + if tangle.isPayloadSolid(currentPayload, currentMetadata) && tangle.isTransactionSolid(currentPayload.Transaction(), cachedTransactionMetadata.Unwrap()) { + if currentMetadata.SetSolid(true) { + tangle.Events.PayloadSolid.Trigger(currentCachedPayload, currentCachedMetadata) - tangle.GetApprovers(currentPayload.GetId()).Consume(func(approver *payloadapprover.PayloadApprover) { - approverTransactionId := approver.GetApprovingPayloadId() + tangle.GetApprovers(currentPayload.Id()).Consume(func(approver *PayloadApprover) { + approverTransactionId := approver.GetApprovingPayloadId() - solidificationStack.PushBack([2]interface{}{ - tangle.GetPayload(approverTransactionId), - tangle.GetPayloadMetadata(approverTransactionId), + solidificationStack.PushBack([2]interface{}{ + tangle.GetPayload(approverTransactionId), + tangle.GetPayloadMetadata(approverTransactionId), + }) }) - }) + } } // release cached results currentCachedPayload.Release() currentCachedMetadata.Release() + cachedTransactionMetadata.Release() + } +} + +func (tangle *Tangle) isTransactionSolid(transaction *transaction.Transaction, metadata *TransactionMetadata) bool { + if transaction == nil || transaction.IsDeleted() { + return false + } + + if metadata == nil || metadata.IsDeleted() { + return false } + + if metadata.Solid() { + return true + } + + // iterate through all transfers and check if they are solid + return transaction.Inputs().ForEach(tangle.isOutputMarkedAsSolid) +} + +func (tangle *Tangle) GetTransferOutputMetadata(transactionOutputId transaction.OutputId) *CachedTransactionOutputMetadata { + return &CachedTransactionOutputMetadata{CachedObject: tangle.transactionOutputMetadataStorage.Load(transactionOutputId.Bytes())} +} + +func (tangle *Tangle) isOutputMarkedAsSolid(transferOutputId transaction.OutputId) (result bool) { + objectConsumed := tangle.GetTransferOutputMetadata(transferOutputId).Consume(func(transferOutputMetadata *TransactionOutputMetadata) { + result = transferOutputMetadata.Solid() + }) + + if !objectConsumed { + if cachedMissingOutput, missingOutputStored := tangle.missingOutputStorage.StoreIfAbsent(NewMissingOutput(transferOutputId)); missingOutputStored { + cachedMissingOutput.Consume(func(object objectstorage.StorableObject) { + tangle.Events.OutputMissing.Trigger(object.(*MissingOutput).Id()) + }) + } + } + + return } // isPayloadSolid returns true if the given payload is solid. A payload is considered to be solid solid, if it is either // already marked as solid or if its referenced payloads are marked as solid. -func (tangle *Tangle) isPayloadSolid(payload *valuepayload.Payload, metadata *payloadmetadata.PayloadMetadata) bool { +func (tangle *Tangle) isPayloadSolid(payload *payload.Payload, metadata *PayloadMetadata) bool { if payload == nil || payload.IsDeleted() { return false } @@ -203,13 +266,13 @@ func (tangle *Tangle) isPayloadSolid(payload *valuepayload.Payload, metadata *pa return true } - return tangle.isPayloadMarkedAsSolid(payload.GetTrunkId()) && tangle.isPayloadMarkedAsSolid(payload.GetBranchId()) + return tangle.isPayloadMarkedAsSolid(payload.TrunkId()) && tangle.isPayloadMarkedAsSolid(payload.BranchId()) } // isPayloadMarkedAsSolid returns true if the payload was marked as solid already (by setting the corresponding flags // in its metadata. -func (tangle *Tangle) isPayloadMarkedAsSolid(payloadId payloadid.Id) bool { - if payloadId == payloadid.Genesis { +func (tangle *Tangle) isPayloadMarkedAsSolid(payloadId payload.Id) bool { + if payloadId == payload.GenesisId { return true } @@ -218,9 +281,9 @@ func (tangle *Tangle) isPayloadMarkedAsSolid(payloadId payloadid.Id) bool { transactionMetadataCached.Release() // if transaction is missing and was not reported as missing, yet - if cachedMissingPayload, missingPayloadStored := tangle.missingPayloadStorage.StoreIfAbsent(missingpayload.New(payloadId)); missingPayloadStored { + if cachedMissingPayload, missingPayloadStored := tangle.missingPayloadStorage.StoreIfAbsent(NewMissingPayload(payloadId)); missingPayloadStored { cachedMissingPayload.Consume(func(object objectstorage.StorableObject) { - tangle.Events.PayloadMissing.Trigger(object.(*missingpayload.MissingPayload).GetId()) + tangle.Events.PayloadMissing.Trigger(object.(*MissingPayload).GetId()) }) } diff --git a/packages/binary/valuetransfer/tangle/tangle_test.go b/packages/binary/valuetransfer/tangle/tangle_test.go index ccbbea0a..cd83c779 100644 --- a/packages/binary/valuetransfer/tangle/tangle_test.go +++ b/packages/binary/valuetransfer/tangle/tangle_test.go @@ -11,16 +11,9 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance/color" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance" "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer" - transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/inputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/outputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadmetadata" - transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transferoutput/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" "github.com/iotaledger/goshimmer/packages/database" "github.com/iotaledger/goshimmer/plugins/config" ) @@ -39,7 +32,7 @@ func TestTangle_AttachPayload(t *testing.T) { return } - tangle.Events.PayloadSolid.Attach(events.NewClosure(func(payload *payload.CachedObject, metadata *payloadmetadata.CachedObject) { + tangle.Events.PayloadSolid.Attach(events.NewClosure(func(payload *payload.CachedPayload, metadata *CachedPayloadMetadata) { fmt.Println(payload.Unwrap()) payload.Release() @@ -49,15 +42,18 @@ func TestTangle_AttachPayload(t *testing.T) { addressKeyPair1 := ed25119.GenerateKeyPair() addressKeyPair2 := ed25119.GenerateKeyPair() - tangle.AttachPayload(payload.New(id.Genesis, id.Genesis, transfer.New( - inputs.New( - transferoutputid.New(address.FromED25519PubKey(addressKeyPair1.PublicKey), transferid.New([]byte("transfer1"))), - transferoutputid.New(address.FromED25519PubKey(addressKeyPair2.PublicKey), transferid.New([]byte("transfer2"))), + transferId1, _ := transaction.IdFromBase58("8opHzTAnfzRpPEx21XtnrVTX28YQuCpAjcn1PczScKh") + transferId2, _ := transaction.IdFromBase58("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") + + tangle.AttachPayload(payload.New(payload.GenesisId, payload.GenesisId, transaction.New( + transaction.NewInputs( + transaction.NewOutputId(address.FromED25519PubKey(addressKeyPair1.PublicKey), transferId1), + transaction.NewOutputId(address.FromED25519PubKey(addressKeyPair2.PublicKey), transferId2), ), - outputs.New(map[address.Address][]*coloredbalance.ColoredBalance{ + transaction.NewOutputs(map[address.Address][]*balance.Balance{ address.Random(): { - coloredbalance.New(color.IOTA, 1337), + balance.New(balance.COLOR_IOTA, 1337), }, }), ))) diff --git a/packages/binary/valuetransfer/tangle/transactionmetadata.go b/packages/binary/valuetransfer/tangle/transactionmetadata.go new file mode 100644 index 00000000..898c57a7 --- /dev/null +++ b/packages/binary/valuetransfer/tangle/transactionmetadata.go @@ -0,0 +1,213 @@ +package tangle + +import ( + "sync" + "time" + + "github.com/iotaledger/hive.go/objectstorage" + "github.com/iotaledger/hive.go/stringify" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" +) + +// TransactionMetadata contains the information of a Transaction, that are based on our local perception of things (i.e. if it is +// solid, or when we it became solid). +type TransactionMetadata struct { + objectstorage.StorableObjectFlags + + id transaction.Id + solid bool + solidificationTime time.Time + + solidMutex sync.RWMutex + solidificationTimeMutex sync.RWMutex +} + +// NewTransactionMetadata is the constructor for the TransactionMetadata type. +func NewTransactionMetadata(id transaction.Id) *TransactionMetadata { + return &TransactionMetadata{ + id: id, + } +} + +// TransactionMetadataFromBytes unmarshals a TransactionMetadata object from a sequence of bytes. +// It either creates a new object or fills the optionally provided object with the parsed information. +func TransactionMetadataFromBytes(bytes []byte, optionalTargetObject ...*TransactionMetadata) (result *TransactionMetadata, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &TransactionMetadata{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to TransactionMetadataFromBytes") + } + + // parse the bytes + marshalUtil := marshalutil.New(bytes) + if result.id, err = transaction.ParseId(marshalUtil); err != nil { + return + } + if result.solidificationTime, err = marshalUtil.ReadTime(); err != nil { + return + } + if result.solid, err = marshalUtil.ReadBool(); err != nil { + return + } + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// TransactionMetadataFromStorage is the factory method for TransactionMetadata objects stored in the objectstorage. The bytes and the content +// will be filled by the objectstorage, by subsequently calling MarshalBinary. +func TransactionMetadataFromStorage(storageKey []byte) objectstorage.StorableObject { + result := &TransactionMetadata{} + + var err error + if result.id, err = transaction.ParseId(marshalutil.New(storageKey)); err != nil { + panic(err) + } + + return result +} + +// Parse is a wrapper for simplified unmarshaling of TransactionMetadata objects from a byte stream using the marshalUtil package. +func ParseTransactionMetadata(marshalUtil *marshalutil.MarshalUtil) (*TransactionMetadata, error) { + if metadata, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return TransactionMetadataFromBytes(data) }); err != nil { + return nil, err + } else { + return metadata.(*TransactionMetadata), nil + } +} + +// Id return the id of the Transaction that this TransactionMetadata is associated to. +func (transactionMetadata *TransactionMetadata) Id() transaction.Id { + return transactionMetadata.id +} + +// Solid returns true if the Transaction has been marked as solid. +func (transactionMetadata *TransactionMetadata) Solid() (result bool) { + transactionMetadata.solidMutex.RLock() + result = transactionMetadata.solid + transactionMetadata.solidMutex.RUnlock() + + return +} + +// SetSolid marks a Transaction as either solid or not solid. +// It returns true if the solid flag was changes and automatically updates the solidificationTime as well. +func (transactionMetadata *TransactionMetadata) SetSolid(solid bool) (modified bool) { + transactionMetadata.solidMutex.RLock() + if transactionMetadata.solid != solid { + transactionMetadata.solidMutex.RUnlock() + + transactionMetadata.solidMutex.Lock() + if transactionMetadata.solid != solid { + transactionMetadata.solid = solid + if solid { + transactionMetadata.solidificationTimeMutex.Lock() + transactionMetadata.solidificationTime = time.Now() + transactionMetadata.solidificationTimeMutex.Unlock() + } + + transactionMetadata.SetModified() + + modified = true + } + transactionMetadata.solidMutex.Unlock() + + } else { + transactionMetadata.solidMutex.RUnlock() + } + + return +} + +// SoldificationTime returns the time when the Transaction was marked to be solid. +func (transactionMetadata *TransactionMetadata) SoldificationTime() time.Time { + transactionMetadata.solidificationTimeMutex.RLock() + defer transactionMetadata.solidificationTimeMutex.RUnlock() + + return transactionMetadata.solidificationTime +} + +// Bytes marshals the TransactionMetadata object into a sequence of bytes. +func (transactionMetadata *TransactionMetadata) Bytes() []byte { + marshalUtil := marshalutil.New() + + marshalUtil.WriteBytes(transactionMetadata.id.Bytes()) + marshalUtil.WriteTime(transactionMetadata.solidificationTime) + marshalUtil.WriteBool(transactionMetadata.solid) + + return marshalUtil.Bytes() +} + +// String creates a human readable version of the metadata (for debug purposes). +func (transactionMetadata *TransactionMetadata) String() string { + return stringify.Struct("transaction.TransactionMetadata", + stringify.StructField("payloadId", transactionMetadata.Id()), + stringify.StructField("solid", transactionMetadata.Solid()), + stringify.StructField("solidificationTime", transactionMetadata.SoldificationTime()), + ) +} + +// GetStorageKey returns the key that is used to identify the TransactionMetadata in the objectstorage. +func (transactionMetadata *TransactionMetadata) GetStorageKey() []byte { + return transactionMetadata.id.Bytes() +} + +// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. +func (transactionMetadata *TransactionMetadata) Update(other objectstorage.StorableObject) { + panic("update forbidden") +} + +// MarshalBinary marshals the TransactionMetadata object into a sequence of bytes and matches the encoding.BinaryMarshaler +// interface. +func (transactionMetadata *TransactionMetadata) MarshalBinary() ([]byte, error) { + return transactionMetadata.Bytes(), nil +} + +// UnmarshalBinary restores the values of a TransactionMetadata object from a sequence of bytes and matches the +// encoding.BinaryUnmarshaler interface. +func (transactionMetadata *TransactionMetadata) UnmarshalBinary(data []byte) (err error) { + _, err, _ = TransactionMetadataFromBytes(data, transactionMetadata) + + return +} + +// CachedTransactionMetadata is a wrapper for the object storage, that takes care of type casting the TransactionMetadata objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of TransactionMetadata, without having to manually type cast over and over again. +type CachedTransactionMetadata struct { + objectstorage.CachedObject +} + +// Retain overrides the underlying method to return a new CachedTransactionMetadata instead of a generic CachedObject. +func (cachedTransactionMetadata *CachedTransactionMetadata) Retain() *CachedTransactionMetadata { + return &CachedTransactionMetadata{cachedTransactionMetadata.CachedObject.Retain()} +} + +// Consume overrides the underlying method to use a CachedTransactionMetadata object instead of a generic CachedObject in the +// consumer). +func (cachedTransactionMetadata *CachedTransactionMetadata) Consume(consumer func(metadata *TransactionMetadata)) bool { + return cachedTransactionMetadata.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*TransactionMetadata)) + }) +} + +// Unwrap provides a way to retrieve a type casted version of the underlying object. +func (cachedTransactionMetadata *CachedTransactionMetadata) Unwrap() *TransactionMetadata { + if untypedTransaction := cachedTransactionMetadata.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*TransactionMetadata); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} diff --git a/packages/binary/valuetransfer/tangle/transactionoutputmetadata.go b/packages/binary/valuetransfer/tangle/transactionoutputmetadata.go new file mode 100644 index 00000000..9e0c15fe --- /dev/null +++ b/packages/binary/valuetransfer/tangle/transactionoutputmetadata.go @@ -0,0 +1,213 @@ +package tangle + +import ( + "sync" + "time" + + "github.com/iotaledger/hive.go/objectstorage" + "github.com/iotaledger/hive.go/stringify" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction" +) + +// TransactionOutputMetadata contains the information of a transaction output, that are based on our local perception of things (i.e. if it +// is solid, or when we it became solid). +type TransactionOutputMetadata struct { + objectstorage.StorableObjectFlags + + id transaction.OutputId + solid bool + solidificationTime time.Time + + solidMutex sync.RWMutex + solidificationTimeMutex sync.RWMutex +} + +// NewOutputMetadata is the constructor for the TransactionOutputMetadata type. +func NewTransactionOutputMetadata(outputId transaction.OutputId) *TransactionOutputMetadata { + return &TransactionOutputMetadata{ + id: outputId, + } +} + +// TransactionOutputMetadataFromBytes unmarshals a TransactionOutputMetadata object from a sequence of bytes. +// It either creates a new object or fills the optionally provided object with the parsed information. +func TransactionOutputMetadataFromBytes(bytes []byte, optionalTargetObject ...*TransactionOutputMetadata) (result *TransactionOutputMetadata, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &TransactionOutputMetadata{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to TransactionOutputMetadataFromBytes") + } + + // parse the bytes + marshalUtil := marshalutil.New(bytes) + if result.id, err = transaction.ParseOutputId(marshalUtil); err != nil { + return + } + if result.solidificationTime, err = marshalUtil.ReadTime(); err != nil { + return + } + if result.solid, err = marshalUtil.ReadBool(); err != nil { + return + } + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// TransactionOutputMetadataFromStorage is the factory method for TransactionOutputMetadata objects stored in the objectstorage. The bytes and the content +// will be filled by the objectstorage, by subsequently calling MarshalBinary. +func TransactionOutputMetadataFromStorage(storageKey []byte) objectstorage.StorableObject { + result := &TransactionOutputMetadata{} + + var err error + if result.id, err = transaction.ParseOutputId(marshalutil.New(storageKey)); err != nil { + panic(err) + } + + return result +} + +// Parse is a wrapper for simplified unmarshaling of TransactionOutputMetadata objects from a byte stream using the marshalUtil package. +func ParseTransactionOutputMetadata(marshalUtil *marshalutil.MarshalUtil) (*TransactionOutputMetadata, error) { + if outputMetadata, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return TransactionOutputMetadataFromBytes(data) }); err != nil { + return nil, err + } else { + return outputMetadata.(*TransactionOutputMetadata), nil + } +} + +// OutputId returns the id of the Output that this TransactionOutputMetadata is associated to. +func (transactionOutputMetadata *TransactionOutputMetadata) Id() transaction.OutputId { + return transactionOutputMetadata.id +} + +// Solid returns true if the Output has been marked as solid. +func (transactionOutputMetadata *TransactionOutputMetadata) Solid() (result bool) { + transactionOutputMetadata.solidMutex.RLock() + result = transactionOutputMetadata.solid + transactionOutputMetadata.solidMutex.RUnlock() + + return +} + +// SetSolid marks a Output as either solid or not solid. +// It returns true if the solid flag was changes and automatically updates the solidificationTime as well. +func (transactionOutputMetadata *TransactionOutputMetadata) SetSolid(solid bool) (modified bool) { + transactionOutputMetadata.solidMutex.RLock() + if transactionOutputMetadata.solid != solid { + transactionOutputMetadata.solidMutex.RUnlock() + + transactionOutputMetadata.solidMutex.Lock() + if transactionOutputMetadata.solid != solid { + transactionOutputMetadata.solid = solid + if solid { + transactionOutputMetadata.solidificationTimeMutex.Lock() + transactionOutputMetadata.solidificationTime = time.Now() + transactionOutputMetadata.solidificationTimeMutex.Unlock() + } + + transactionOutputMetadata.SetModified() + + modified = true + } + transactionOutputMetadata.solidMutex.Unlock() + + } else { + transactionOutputMetadata.solidMutex.RUnlock() + } + + return +} + +// SoldificationTime returns the time when the Output was marked to be solid. +func (transactionOutputMetadata *TransactionOutputMetadata) SoldificationTime() time.Time { + transactionOutputMetadata.solidificationTimeMutex.RLock() + defer transactionOutputMetadata.solidificationTimeMutex.RUnlock() + + return transactionOutputMetadata.solidificationTime +} + +// Bytes marshals the TransactionOutputMetadata object into a sequence of bytes. +func (transactionOutputMetadata *TransactionOutputMetadata) Bytes() []byte { + marshalUtil := marshalutil.New() + + marshalUtil.WriteBytes(transactionOutputMetadata.id.Bytes()) + marshalUtil.WriteTime(transactionOutputMetadata.solidificationTime) + marshalUtil.WriteBool(transactionOutputMetadata.solid) + + return marshalUtil.Bytes() +} + +// String creates a human readable version of the metadata (for debug purposes). +func (transactionOutputMetadata *TransactionOutputMetadata) String() string { + return stringify.Struct("transaction.TransactionOutputMetadata", + stringify.StructField("payloadId", transactionOutputMetadata.Id()), + stringify.StructField("solid", transactionOutputMetadata.Solid()), + stringify.StructField("solidificationTime", transactionOutputMetadata.SoldificationTime()), + ) +} + +// GetStorageKey returns the key that is used to identify the TransactionOutputMetadata in the objectstorage. +func (transactionOutputMetadata *TransactionOutputMetadata) GetStorageKey() []byte { + return transactionOutputMetadata.id.Bytes() +} + +// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. +func (transactionOutputMetadata *TransactionOutputMetadata) Update(other objectstorage.StorableObject) { + panic("update forbidden") +} + +// MarshalBinary marshals the TransactionOutputMetadata object into a sequence of bytes and matches the encoding.BinaryMarshaler +// interface. +func (transactionOutputMetadata *TransactionOutputMetadata) MarshalBinary() ([]byte, error) { + return transactionOutputMetadata.Bytes(), nil +} + +// UnmarshalBinary restores the values of a TransactionOutputMetadata object from a sequence of bytes and matches the +// encoding.BinaryUnmarshaler interface. +func (transactionOutputMetadata *TransactionOutputMetadata) UnmarshalBinary(data []byte) (err error) { + _, err, _ = TransactionOutputMetadataFromBytes(data, transactionOutputMetadata) + + return +} + +// CachedTransactionOutputMetadata is a wrapper for the object storage, that takes care of type casting the TransactionOutputMetadata objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of TransactionOutputMetadata, without having to manually type cast over and over again. +type CachedTransactionOutputMetadata struct { + objectstorage.CachedObject +} + +// Retain overrides the underlying method to return a new CachedTransactionOutputMetadata instead of a generic CachedObject. +func (cachedOutputMetadata *CachedTransactionOutputMetadata) Retain() *CachedTransactionOutputMetadata { + return &CachedTransactionOutputMetadata{cachedOutputMetadata.CachedObject.Retain()} +} + +// Consume overrides the underlying method to use a CachedTransactionOutputMetadata object instead of a generic CachedObject in the +// consumer). +func (cachedOutputMetadata *CachedTransactionOutputMetadata) Consume(consumer func(outputMetadata *TransactionOutputMetadata)) bool { + return cachedOutputMetadata.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*TransactionOutputMetadata)) + }) +} + +// Unwrap provides a way to retrieve a type casted version of the underlying object. +func (cachedOutputMetadata *CachedTransactionOutputMetadata) Unwrap() *TransactionOutputMetadata { + if untypedTransaction := cachedOutputMetadata.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*TransactionOutputMetadata); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} diff --git a/packages/binary/valuetransfer/test/payload_test.go b/packages/binary/valuetransfer/test/payload_test.go deleted file mode 100644 index dcee4c24..00000000 --- a/packages/binary/valuetransfer/test/payload_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package test - -import ( - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance/color" - valuepayload "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer" - transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/inputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/outputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/signatures" - transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transferoutput/id" -) - -func ExamplePayload() { - // 1. create value transfer (user provides this) - valueTransfer := transfer.New( - // inputs - inputs.New( - transferoutputid.New(address.Random(), transferid.New([]byte("transfer1"))), - transferoutputid.New(address.Random(), transferid.New([]byte("transfer2"))), - ), - - // outputs - outputs.New(map[address.Address][]*coloredbalance.ColoredBalance{ - address.Random(): { - coloredbalance.New(color.IOTA, 1337), - }, - }), - ) - - // 2. create value payload (the ontology creates this and wraps the user provided transfer accordingly) - valuePayload := valuepayload.New( - // trunk in "value transfer ontology" (filled by ontology tipSelector) - payloadid.Genesis, - - // branch in "value transfer ontology" (filled by ontology tipSelector) - payloadid.Genesis, - - // value transfer - valueTransfer, - ) - - // 3. build actual transaction (the base layer creates this and wraps the ontology provided payload) - tx := transaction.New( - // trunk in "network tangle" ontology (filled by tipSelector) - transaction.EmptyId, - - // branch in "network tangle" ontology (filled by tipSelector) - transaction.EmptyId, - - // issuer of the transaction (signs automatically) - ed25119.GenerateKeyPair(), - - // the time when the transaction was created - time.Now(), - - // the ever increasing sequence number of this transaction - 0, - - // payload - valuePayload, - ) - - fmt.Println(tx) -} - -func TestPayload(t *testing.T) { - addressKeyPair1 := ed25119.GenerateKeyPair() - addressKeyPair2 := ed25119.GenerateKeyPair() - - originalPayload := valuepayload.New( - payloadid.Genesis, - payloadid.Genesis, - transfer.New( - inputs.New( - transferoutputid.New(address.FromED25519PubKey(addressKeyPair1.PublicKey), transferid.New([]byte("transfer1"))), - transferoutputid.New(address.FromED25519PubKey(addressKeyPair2.PublicKey), transferid.New([]byte("transfer2"))), - ), - - outputs.New(map[address.Address][]*coloredbalance.ColoredBalance{ - address.Random(): { - coloredbalance.New(color.IOTA, 1337), - }, - }), - ).Sign( - signatures.ED25519(addressKeyPair1), - ), - ) - - assert.Equal(t, false, originalPayload.GetTransfer().SignaturesValid()) - - originalPayload.GetTransfer().Sign( - signatures.ED25519(addressKeyPair2), - ) - - assert.Equal(t, true, originalPayload.GetTransfer().SignaturesValid()) - - clonedPayload1, err, _ := valuepayload.FromBytes(originalPayload.Bytes()) - if err != nil { - panic(err) - } - - assert.Equal(t, originalPayload.GetId(), clonedPayload1.GetId()) - assert.Equal(t, true, clonedPayload1.GetTransfer().SignaturesValid()) - - clonedPayload2, err, _ := valuepayload.FromBytes(clonedPayload1.Bytes()) - if err != nil { - panic(err) - } - - assert.Equal(t, originalPayload.GetId(), clonedPayload2.GetId()) - assert.Equal(t, true, clonedPayload2.GetTransfer().SignaturesValid()) -} diff --git a/packages/binary/valuetransfer/transaction/id.go b/packages/binary/valuetransfer/transaction/id.go new file mode 100644 index 00000000..396b5d28 --- /dev/null +++ b/packages/binary/valuetransfer/transaction/id.go @@ -0,0 +1,86 @@ +package transaction + +import ( + "crypto/rand" + "fmt" + + "github.com/mr-tron/base58" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" +) + +// Id is the data type that represents the identifier for a Transaction. +type Id [IdLength]byte + +// IdFromBase58 creates an id from a base58 encoded string. +func IdFromBase58(base58String string) (id Id, err error) { + // decode string + bytes, err := base58.Decode(base58String) + if err != nil { + return + } + + // sanitize input + if len(bytes) != IdLength { + err = fmt.Errorf("base58 encoded string does not match the length of a transaction id") + + return + } + + // copy bytes to result + copy(id[:], bytes) + + return +} + +// IdFromBytes unmarshals an Id from a sequence of bytes. +func IdFromBytes(bytes []byte) (result Id, err error, consumedBytes int) { + // parse the bytes + marshalUtil := marshalutil.New(bytes) + if idBytes, idErr := marshalUtil.ReadBytes(IdLength); idErr != nil { + err = idErr + + return + } else { + copy(result[:], idBytes) + } + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// Parse is a wrapper for simplified unmarshaling of Ids from a byte stream using the marshalUtil package. +func ParseId(marshalUtil *marshalutil.MarshalUtil) (Id, error) { + if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return IdFromBytes(data) }); err != nil { + return Id{}, err + } else { + return id.(Id), nil + } +} + +// Random creates a random address, which can for example be used in unit tests. +func RandomId() (id Id) { + // generate a random sequence of bytes + idBytes := make([]byte, IdLength) + if _, err := rand.Read(idBytes); err != nil { + panic(err) + } + + // copy the generated bytes into the result + copy(id[:], idBytes) + + return +} + +// Bytes marshals the Id into a sequence of bytes. +func (id Id) Bytes() []byte { + return id[:] +} + +// String creates a human readable version of the Id (for debug purposes). +func (id Id) String() string { + return base58.Encode(id[:]) +} + +// IdLength contains the amount of bytes that a marshaled version of the Id contains. +const IdLength = 32 diff --git a/packages/binary/valuetransfer/payload/transfer/inputs/inputs.go b/packages/binary/valuetransfer/transaction/inputs.go similarity index 50% rename from packages/binary/valuetransfer/payload/transfer/inputs/inputs.go rename to packages/binary/valuetransfer/transaction/inputs.go index 1d107dc7..49f07e96 100644 --- a/packages/binary/valuetransfer/payload/transfer/inputs/inputs.go +++ b/packages/binary/valuetransfer/transaction/inputs.go @@ -1,29 +1,26 @@ -package inputs +package transaction import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" - transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" - transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transferoutput/id" ) type Inputs struct { *orderedmap.OrderedMap } -func New(transferOutputIds ...transferoutputid.Id) (inputs *Inputs) { +func NewInputs(outputIds ...OutputId) (inputs *Inputs) { inputs = &Inputs{orderedmap.New()} - for _, transferOutputId := range transferOutputIds { - inputs.Add(transferOutputId) + for _, outputId := range outputIds { + inputs.Add(outputId) } return } -func FromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int) { - inputs = New() +func InputsFromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int) { + inputs = NewInputs() marshalUtil := marshalutil.New(bytes) inputCount, err := marshalUtil.ReadUint32() @@ -39,13 +36,18 @@ func FromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int) { return } - transferIdBytes, readErr := marshalUtil.ReadBytes(transferid.Length) + idBytes, readErr := marshalUtil.ReadBytes(IdLength) if readErr != nil { err = readErr return } - transferId := id.New(transferIdBytes) + id, idErr, _ := IdFromBytes(idBytes) + if idErr != nil { + err = idErr + + return + } addressMap, addressExists := inputs.Get(readAddress) if !addressExists { @@ -53,7 +55,7 @@ func FromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int) { inputs.Set(readAddress, addressMap) } - addressMap.(*orderedmap.OrderedMap).Set(transferId, transferoutputid.New(readAddress, transferId)) + addressMap.(*orderedmap.OrderedMap).Set(id, NewOutputId(readAddress, id)) } consumedBytes = marshalUtil.ReadOffset() @@ -61,9 +63,9 @@ func FromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int) { return } -func (inputs *Inputs) Add(input transferoutputid.Id) *Inputs { - inputAddress := input.GetAddress() - transferId := input.GetTransferId() +func (inputs *Inputs) Add(input OutputId) *Inputs { + inputAddress := input.Address() + transactionId := input.TransactionId() addressMap, addressExists := inputs.Get(inputAddress) if !addressExists { @@ -72,7 +74,7 @@ func (inputs *Inputs) Add(input transferoutputid.Id) *Inputs { inputs.Set(inputAddress, addressMap) } - addressMap.(*orderedmap.OrderedMap).Set(transferId, input) + addressMap.(*orderedmap.OrderedMap).Set(transactionId, input) return inputs } @@ -82,10 +84,12 @@ func (inputs *Inputs) Bytes() (bytes []byte) { marshalUtil.WriteSeek(4) var inputCounter uint32 - inputs.ForEach(func(transferOutputId transferoutputid.Id) { - marshalUtil.WriteBytes(transferOutputId.ToBytes()) + inputs.ForEach(func(outputId OutputId) bool { + marshalUtil.WriteBytes(outputId.Bytes()) inputCounter++ + + return true }) marshalUtil.WriteSeek(0) marshalUtil.WriteUint32(inputCounter) @@ -93,24 +97,34 @@ func (inputs *Inputs) Bytes() (bytes []byte) { return marshalUtil.Bytes() } -func (inputs *Inputs) ForEach(consumer func(transferOutputId transferoutputid.Id)) { - inputs.OrderedMap.ForEach(func(key, value interface{}) bool { - value.(*orderedmap.OrderedMap).ForEach(func(key, value interface{}) bool { - consumer(value.(transferoutputid.Id)) - - return true +func (inputs *Inputs) ForEach(consumer func(outputId OutputId) bool) bool { + return inputs.OrderedMap.ForEach(func(key, value interface{}) bool { + return value.(*orderedmap.OrderedMap).ForEach(func(key, value interface{}) bool { + return consumer(value.(OutputId)) }) - - return true }) } -func (inputs *Inputs) ForEachAddress(consumer func(currentAddress address.Address) bool) { - inputs.OrderedMap.ForEach(func(key, value interface{}) bool { +func (inputs *Inputs) ForEachAddress(consumer func(currentAddress address.Address) bool) bool { + return inputs.OrderedMap.ForEach(func(key, value interface{}) bool { return consumer(key.(address.Address)) }) } +func (inputs *Inputs) ForEachTransaction(consumer func(transactionId Id) bool) bool { + seenTransactions := make(map[Id]bool) + + return inputs.ForEach(func(outputId OutputId) bool { + if currentTransactionId := outputId.TransactionId(); !seenTransactions[currentTransactionId] { + seenTransactions[currentTransactionId] = true + + return consumer(currentTransactionId) + } + + return true + }) +} + func (inputs *Inputs) String() string { if inputs == nil { return "<nil>" @@ -119,10 +133,12 @@ func (inputs *Inputs) String() string { result := "[\n" empty := true - inputs.ForEach(func(transferOutputId transferoutputid.Id) { + inputs.ForEach(func(outputId OutputId) bool { empty = false - result += " " + transferOutputId.String() + ",\n" + result += " " + outputId.String() + ",\n" + + return true }) if empty { diff --git a/packages/binary/valuetransfer/transaction/output.go b/packages/binary/valuetransfer/transaction/output.go new file mode 100644 index 00000000..949434dc --- /dev/null +++ b/packages/binary/valuetransfer/transaction/output.go @@ -0,0 +1,126 @@ +package transaction + +import ( + "fmt" + + "github.com/iotaledger/hive.go/objectstorage" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance" +) + +// Output represents the output of a Transaction and contains the balances and the identifiers for this output. +type Output struct { + address address.Address + transactionId Id + balances []*balance.Balance + + objectstorage.StorableObjectFlags + storageKey []byte +} + +// NewOutput creates an Output that contains the balances and identifiers of a Transaction. +func NewOutput(address address.Address, transactionId Id, balances []*balance.Balance) *Output { + return &Output{ + address: address, + transactionId: transactionId, + balances: balances, + + storageKey: marshalutil.New().WriteBytes(address.Bytes()).WriteBytes(transactionId.Bytes()).Bytes(), + } +} + +// OutputFromStorage get's called when we restore a Output from the storage. +// In contrast to other database models, it unmarshals some information from the key so we simply store the key before +// it gets handed over to UnmarshalBinary (by the ObjectStorage). +func OutputFromStorage(keyBytes []byte) objectstorage.StorableObject { + return &Output{ + storageKey: marshalutil.New(keyBytes).Bytes(true), + } +} + +// Address returns the address that this output belongs to. +func (output *Output) Address() address.Address { + return output.address +} + +// TransactionId returns the id of the Transaction, that created this output. +func (output *Output) TransactionId() Id { + return output.transactionId +} + +// Balances returns the colored balances (color + balance) that this output contains. +func (output *Output) Balances() []*balance.Balance { + return output.balances +} + +// MarshalBinary marshals the balances into a sequence of bytes - the address and transaction id are stored inside the key +// and are ignored here. +func (output *Output) MarshalBinary() (data []byte, err error) { + // determine amount of balances in the output + balanceCount := len(output.balances) + + // initialize helper + marshalUtil := marshalutil.New(4 + balanceCount*balance.Length) + + // marshal the amount of balances + marshalUtil.WriteUint32(uint32(balanceCount)) + + // marshal balances + for _, balance := range output.balances { + marshalUtil.WriteBytes(balance.Bytes()) + } + + return +} + +// UnmarshalBinary restores a Output from a serialized version in the ObjectStorage with parts of the object +// being stored in its key rather than the content of the database to reduce storage requirements. +func (output *Output) UnmarshalBinary(data []byte) (err error) { + // check if the storageKey has been set + if output.storageKey == nil { + return fmt.Errorf("missing storageKey when trying to unmarshal Output (it contains part of the information)") + } + + // parse information from storageKey + storageKeyUnmarshaler := marshalutil.New(output.storageKey) + output.address, err = address.Parse(storageKeyUnmarshaler) + if err != nil { + return + } + output.transactionId, err = ParseId(storageKeyUnmarshaler) + if err != nil { + return + } + + // parse information from content bytes + contentUnmarshaler := marshalutil.New(data) + balanceCount, err := contentUnmarshaler.ReadUint32() + if err != nil { + return + } + output.balances = make([]*balance.Balance, balanceCount) + for i := uint32(0); i < balanceCount; i++ { + output.balances[i], err = balance.Parse(contentUnmarshaler) + if err != nil { + return + } + } + + return +} + +// Update is disabled and panics if it ever gets called - it is required to match StorableObject interface. +func (output *Output) Update(other objectstorage.StorableObject) { + panic("this object should never be updated") +} + +// GetStorageKey returns the key that is used to store the object in the database. +// It is required to match StorableObject interface. +func (output *Output) GetStorageKey() []byte { + return output.storageKey +} + +// define contract (ensure that the struct fulfills the given interface) +var _ objectstorage.StorableObject = &Output{} diff --git a/packages/binary/valuetransfer/transferoutput/transferoutput_test.go b/packages/binary/valuetransfer/transaction/output_test.go similarity index 70% rename from packages/binary/valuetransfer/transferoutput/transferoutput_test.go rename to packages/binary/valuetransfer/transaction/output_test.go index c7614b3b..305409e8 100644 --- a/packages/binary/valuetransfer/transferoutput/transferoutput_test.go +++ b/packages/binary/valuetransfer/transaction/output_test.go @@ -1,4 +1,4 @@ -package transferoutput +package transaction import ( "testing" diff --git a/packages/binary/valuetransfer/transaction/outputid.go b/packages/binary/valuetransfer/transaction/outputid.go new file mode 100644 index 00000000..891cd5c0 --- /dev/null +++ b/packages/binary/valuetransfer/transaction/outputid.go @@ -0,0 +1,71 @@ +package transaction + +import ( + "github.com/mr-tron/base58" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" +) + +// OutputId is the data type that represents the identifier for a Output. +type OutputId [OutputIdLength]byte + +// NewOutputId is the constructor for the OutputId type. +func NewOutputId(outputAddress address.Address, transactionId Id) (outputId OutputId) { + copy(outputId[:address.Length], outputAddress.Bytes()) + copy(outputId[address.Length:], transactionId[:]) + + return +} + +// OutputIdFromBytes unmarshals an OutputId from a sequence of bytes. +func OutputIdFromBytes(bytes []byte) (result OutputId, err error, consumedBytes int) { + // parse the bytes + marshalUtil := marshalutil.New(bytes) + if idBytes, idErr := marshalUtil.ReadBytes(OutputIdLength); idErr != nil { + err = idErr + + return + } else { + copy(result[:], idBytes) + } + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// Parse is a wrapper for simplified unmarshaling of Ids from a byte stream using the marshalUtil package. +func ParseOutputId(marshalUtil *marshalutil.MarshalUtil) (OutputId, error) { + if outputId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return OutputIdFromBytes(data) }); err != nil { + return OutputId{}, err + } else { + return outputId.(OutputId), nil + } +} + +// Address returns the address part of an OutputId. +func (outputId OutputId) Address() (address address.Address) { + copy(address[:], outputId[:]) + + return +} + +// TransactionId returns the transaction id part of an OutputId. +func (outputId OutputId) TransactionId() (transactionId Id) { + copy(transactionId[:], outputId[address.Length:]) + + return +} + +// Bytes marshals the OutputId into a sequence of bytes. +func (outputId OutputId) Bytes() []byte { + return outputId[:] +} + +// String creates a human readable version of the OutputId (for debug purposes). +func (outputId OutputId) String() string { + return base58.Encode(outputId[:]) +} + +// IdLength contains the amount of bytes that a marshaled version of the OutputId contains. +const OutputIdLength = address.Length + IdLength diff --git a/packages/binary/valuetransfer/payload/transfer/outputs/outputs.go b/packages/binary/valuetransfer/transaction/outputs.go similarity index 79% rename from packages/binary/valuetransfer/payload/transfer/outputs/outputs.go rename to packages/binary/valuetransfer/transaction/outputs.go index d32956f4..3166ac93 100644 --- a/packages/binary/valuetransfer/payload/transfer/outputs/outputs.go +++ b/packages/binary/valuetransfer/transaction/outputs.go @@ -1,17 +1,17 @@ -package outputs +package transaction import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance" ) type Outputs struct { *orderedmap.OrderedMap } -func New(outputs map[address.Address][]*coloredbalance.ColoredBalance) (result *Outputs) { +func NewOutputs(outputs map[address.Address][]*balance.Balance) (result *Outputs) { result = &Outputs{orderedmap.New()} for address, balances := range outputs { result.Add(address, balances) @@ -22,7 +22,7 @@ func New(outputs map[address.Address][]*coloredbalance.ColoredBalance) (result * // FromBytes reads the bytes and unmarshals the given information into an *Outputs object. It either creates a // new object, or uses the optional object provided in the arguments. -func FromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, err error, consumedBytes int) { +func OutputsFromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, err error, consumedBytes int) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -61,16 +61,16 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, } // iterate the corresponding times and collect balances - coloredBalances := make([]*coloredbalance.ColoredBalance, balanceCount) + coloredBalances := make([]*balance.Balance, balanceCount) for j := uint32(0); j < balanceCount; j++ { - coloredBalance, coloredBalanceErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return coloredbalance.FromBytes(data) }) + coloredBalance, coloredBalanceErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return balance.FromBytes(data) }) if coloredBalanceErr != nil { err = coloredBalanceErr return } - coloredBalances[j] = coloredBalance.(*coloredbalance.ColoredBalance) + coloredBalances[j] = coloredBalance.(*balance.Balance) } // add the gathered information as an output @@ -83,15 +83,15 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, return } -func (outputs *Outputs) Add(address address.Address, balances []*coloredbalance.ColoredBalance) *Outputs { +func (outputs *Outputs) Add(address address.Address, balances []*balance.Balance) *Outputs { outputs.Set(address, balances) return outputs } -func (outputs *Outputs) ForEach(consumer func(address address.Address, balances []*coloredbalance.ColoredBalance)) { +func (outputs *Outputs) ForEach(consumer func(address address.Address, balances []*balance.Balance)) { outputs.OrderedMap.ForEach(func(key, value interface{}) bool { - consumer(key.(address.Address), value.([]*coloredbalance.ColoredBalance)) + consumer(key.(address.Address), value.([]*balance.Balance)) return true }) @@ -107,7 +107,7 @@ func (outputs *Outputs) Bytes() []byte { } marshalUtil.WriteUint32(uint32(outputs.Size())) - outputs.ForEach(func(address address.Address, balances []*coloredbalance.ColoredBalance) { + outputs.ForEach(func(address address.Address, balances []*balance.Balance) { marshalUtil.WriteBytes(address.Bytes()) marshalUtil.WriteUint32(uint32(len(balances))) @@ -126,7 +126,7 @@ func (outputs *Outputs) String() string { result := "[\n" empty := true - outputs.ForEach(func(address address.Address, balances []*coloredbalance.ColoredBalance) { + outputs.ForEach(func(address address.Address, balances []*balance.Balance) { empty = false result += " " + address.String() + ": [\n" diff --git a/packages/binary/valuetransfer/payload/transfer/signatures/signatures.go b/packages/binary/valuetransfer/transaction/signatures.go similarity index 66% rename from packages/binary/valuetransfer/payload/transfer/signatures/signatures.go rename to packages/binary/valuetransfer/transaction/signatures.go index d07d1a43..26f3f45f 100644 --- a/packages/binary/valuetransfer/payload/transfer/signatures/signatures.go +++ b/packages/binary/valuetransfer/transaction/signatures.go @@ -1,9 +1,10 @@ -package signatures +package transaction import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme" ) // Signatures represents a container for the address signatures of a value transfer. @@ -14,7 +15,7 @@ type Signatures struct { } // New creates an empty container for the address signatures of a value transfer. -func New() *Signatures { +func NewSignatures() *Signatures { return &Signatures{ orderedMap: orderedmap.New(), } @@ -22,7 +23,7 @@ func New() *Signatures { // FromBytes unmarshals a container with signatures from a sequence of bytes. // It either creates a new container or fills the optionally provided container with the parsed information. -func FromBytes(bytes []byte, optionalTargetObject ...*Signatures) (result *Signatures, err error, consumedBytes int) { +func SignaturesFromBytes(bytes []byte, optionalTargetObject ...*Signatures) (result *Signatures, err error, consumedBytes int) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -46,15 +47,15 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Signatures) (result *Signa for versionByte != 0 { // perform signature scheme specific decoding switch versionByte { - case VERSION_ED25519: + case signaturescheme.VERSION_ED25519: marshalUtil.ReadSeek(-1) - signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return ed25519SignatureFromBytes(data) }) + signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return signaturescheme.Ed25519SignatureFromBytes(data) }) if signatureErr != nil { err = signatureErr return } - typeCastedSignature := signature.(Signature) + typeCastedSignature := signature.(signaturescheme.Signature) result.orderedMap.Set(typeCastedSignature.Address(), typeCastedSignature) } @@ -71,17 +72,17 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Signatures) (result *Signa return } -func (signatures *Signatures) Add(address address.Address, signature Signature) { +func (signatures *Signatures) Add(address address.Address, signature signaturescheme.Signature) { signatures.orderedMap.Set(address, signature) } -func (signatures *Signatures) Get(address address.Address) (Signature, bool) { +func (signatures *Signatures) Get(address address.Address) (signaturescheme.Signature, bool) { signature, exists := signatures.orderedMap.Get(address) if !exists { return nil, false } - return signature.(Signature), exists + return signature.(signaturescheme.Signature), exists } // Size returns the amount of signatures in this container. @@ -91,9 +92,9 @@ func (signatures *Signatures) Size() int { // ForEach iterates through all signatures, calling the consumer for every found entry. // The iteration can be aborted by the consumer returning false -func (signatures *Signatures) ForEach(consumer func(address address.Address, signature Signature) bool) { +func (signatures *Signatures) ForEach(consumer func(address address.Address, signature signaturescheme.Signature) bool) { signatures.orderedMap.ForEach(func(key, value interface{}) bool { - return consumer(key.(address.Address), value.(Signature)) + return consumer(key.(address.Address), value.(signaturescheme.Signature)) }) } @@ -103,7 +104,7 @@ func (signatures *Signatures) Bytes() []byte { marshalUtil := marshalutil.New() // iterate through signatures and dump them - signatures.ForEach(func(address address.Address, signature Signature) bool { + signatures.ForEach(func(address address.Address, signature signaturescheme.Signature) bool { marshalUtil.WriteBytes(signature.Bytes()) return true @@ -115,3 +116,40 @@ func (signatures *Signatures) Bytes() []byte { // return result return marshalUtil.Bytes() } + +func (signatures *Signatures) String() string { + if signatures == nil { + return "<nil>" + } + + result := "[\n" + empty := true + signatures.ForEach(func(address address.Address, signature signaturescheme.Signature) bool { + empty = false + + result += " " + address.String() + ": [\n" + + /* + balancesEmpty := true + for _, balance := range balances { + balancesEmpty = false + + result += " " + balance.String() + ",\n" + } + + if balancesEmpty { + result += " <empty>\n" + } + */ + + result += " ]\n" + + return true + }) + + if empty { + result += " <empty>\n" + } + + return result + "]" +} diff --git a/packages/binary/valuetransfer/payload/transfer/signatures/signatures_test.go b/packages/binary/valuetransfer/transaction/signatures_test.go similarity index 65% rename from packages/binary/valuetransfer/payload/transfer/signatures/signatures_test.go rename to packages/binary/valuetransfer/transaction/signatures_test.go index 214092e8..88589852 100644 --- a/packages/binary/valuetransfer/payload/transfer/signatures/signatures_test.go +++ b/packages/binary/valuetransfer/transaction/signatures_test.go @@ -1,4 +1,4 @@ -package signatures +package transaction import ( "testing" @@ -7,15 +7,16 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme" ) func TestSignatures(t *testing.T) { dataToSign := []byte("test") - address1SigScheme := ED25519(ed25119.GenerateKeyPair()) - address2SigScheme := ED25519(ed25119.GenerateKeyPair()) + address1SigScheme := signaturescheme.ED25519(ed25119.GenerateKeyPair()) + address2SigScheme := signaturescheme.ED25519(ed25119.GenerateKeyPair()) - signatures := New() + signatures := NewSignatures() signatures.Add(address1SigScheme.Address(), address1SigScheme.Sign(dataToSign)) signatures.Add(address2SigScheme.Address(), address2SigScheme.Sign(dataToSign)) @@ -25,13 +26,13 @@ func TestSignatures(t *testing.T) { assert.Equal(t, 2, signatures.Size()) - signatures.ForEach(func(address address.Address, signature Signature) bool { + signatures.ForEach(func(address address.Address, signature signaturescheme.Signature) bool { assert.Equal(t, true, signature.IsValid(dataToSign)) return true }) - clonedSignatures, err, _ := FromBytes(signatures.Bytes()) + clonedSignatures, err, _ := SignaturesFromBytes(signatures.Bytes()) if err != nil { t.Error(err) @@ -40,7 +41,7 @@ func TestSignatures(t *testing.T) { assert.Equal(t, 2, clonedSignatures.Size()) - clonedSignatures.ForEach(func(address address.Address, signature Signature) bool { + clonedSignatures.ForEach(func(address address.Address, signature signaturescheme.Signature) bool { assert.Equal(t, true, signature.IsValid(dataToSign)) return true diff --git a/packages/binary/valuetransfer/transaction/transaction.go b/packages/binary/valuetransfer/transaction/transaction.go new file mode 100644 index 00000000..705a62ab --- /dev/null +++ b/packages/binary/valuetransfer/transaction/transaction.go @@ -0,0 +1,339 @@ +package transaction + +import ( + "fmt" + "sync" + + "github.com/iotaledger/hive.go/objectstorage" + "github.com/iotaledger/hive.go/stringify" + "github.com/mr-tron/base58" + "golang.org/x/crypto/blake2b" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme" +) + +// region IMPLEMENT Transaction /////////////////////////////////////////////////////////////////////////////////////////// + +type Transaction struct { + objectstorage.StorableObjectFlags + + inputs *Inputs + outputs *Outputs + signatures *Signatures + + id *Id + idMutex sync.RWMutex + + essenceBytes []byte + essenceBytesMutex sync.RWMutex + + signatureBytes []byte + signatureBytesMutex sync.RWMutex + + bytes []byte + bytesMutex sync.RWMutex +} + +func New(inputs *Inputs, outputs *Outputs) *Transaction { + return &Transaction{ + inputs: inputs, + outputs: outputs, + signatures: NewSignatures(), + } +} + +func FromBytes(bytes []byte, optionalTargetObject ...*Transaction) (result *Transaction, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &Transaction{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to OutputFromBytes") + } + + // initialize helper + marshalUtil := marshalutil.New(bytes) + + // unmarshal inputs + parsedInputs, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return InputsFromBytes(data) }) + if err != nil { + return + } + result.inputs = parsedInputs.(*Inputs) + + // unmarshal outputs + parsedOutputs, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return OutputsFromBytes(data) }) + if err != nil { + return + } + result.outputs = parsedOutputs.(*Outputs) + + // store essence bytes + essenceBytesCount := marshalUtil.ReadOffset() + result.essenceBytes = make([]byte, essenceBytesCount) + copy(result.essenceBytes, bytes[:essenceBytesCount]) + + // unmarshal outputs + parsedSignatures, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return SignaturesFromBytes(data) }) + if err != nil { + return + } + result.signatures = parsedSignatures.(*Signatures) + + // store signature bytes + signatureBytesCount := marshalUtil.ReadOffset() - essenceBytesCount + result.signatureBytes = make([]byte, signatureBytesCount) + copy(result.signatureBytes, bytes[essenceBytesCount:essenceBytesCount+signatureBytesCount]) + + // return the number of bytes we processed + consumedBytes = essenceBytesCount + signatureBytesCount + + // store bytes, so we don't have to marshal manually + result.bytes = bytes[:consumedBytes] + + return +} + +func FromStorage(key []byte) *Transaction { + id, err, _ := IdFromBytes(key) + if err != nil { + panic(err) + } + + return &Transaction{ + id: &id, + } +} + +func (transaction *Transaction) Id() Id { + // acquire lock for reading id + transaction.idMutex.RLock() + + // return if id has been calculated already + if transaction.id != nil { + defer transaction.idMutex.RUnlock() + + return *transaction.id + } + + // switch to write lock + transaction.idMutex.RUnlock() + transaction.idMutex.Lock() + defer transaction.idMutex.Unlock() + + // return if id has been calculated in the mean time + if transaction.id != nil { + return *transaction.id + } + + // otherwise calculate the id + idBytes := blake2b.Sum256(transaction.Bytes()) + id, err, _ := IdFromBytes(idBytes[:]) + if err != nil { + panic(err) + } + + // cache result for later calls + transaction.id = &id + + return id +} + +func (transaction *Transaction) Inputs() *Inputs { + return transaction.inputs +} + +func (transaction *Transaction) SignaturesValid() bool { + signaturesValid := true + transaction.inputs.ForEachAddress(func(address address.Address) bool { + if signature, exists := transaction.signatures.Get(address); !exists || !signature.IsValid(transaction.EssenceBytes()) { + signaturesValid = false + + return false + } + + return true + }) + + return signaturesValid +} + +func (transaction *Transaction) EssenceBytes() []byte { + // acquire read lock on essenceBytes + transaction.essenceBytesMutex.RLock() + + // return essenceBytes if the object has been marshaled already + if transaction.essenceBytes != nil { + defer transaction.essenceBytesMutex.RUnlock() + + return transaction.essenceBytes + } + + // switch to write lock + transaction.essenceBytesMutex.RUnlock() + transaction.essenceBytesMutex.Lock() + defer transaction.essenceBytesMutex.Unlock() + + // return essenceBytes if the object has been marshaled in the mean time + if essenceBytes := transaction.essenceBytes; essenceBytes != nil { + return essenceBytes + } + + // create marshal helper + marshalUtil := marshalutil.New() + + // marshal inputs + marshalUtil.WriteBytes(transaction.inputs.Bytes()) + + // marshal outputs + marshalUtil.WriteBytes(transaction.outputs.Bytes()) + + // store marshaled result + transaction.essenceBytes = marshalUtil.Bytes() + + return transaction.essenceBytes +} + +func (transaction *Transaction) SignatureBytes() []byte { + transaction.signatureBytesMutex.RLock() + if transaction.signatureBytes != nil { + defer transaction.signatureBytesMutex.RUnlock() + + return transaction.signatureBytes + } + + transaction.signatureBytesMutex.RUnlock() + transaction.signatureBytesMutex.Lock() + defer transaction.signatureBytesMutex.Unlock() + + if transaction.signatureBytes != nil { + return transaction.signatureBytes + } + + // generate signatures + transaction.signatureBytes = transaction.signatures.Bytes() + + return transaction.signatureBytes +} + +func (transaction *Transaction) Bytes() []byte { + // acquire read lock on bytes + transaction.bytesMutex.RLock() + + // return bytes if the object has been marshaled already + if transaction.bytes != nil { + defer transaction.bytesMutex.RUnlock() + + return transaction.bytes + } + + // switch to write lock + transaction.bytesMutex.RUnlock() + transaction.bytesMutex.Lock() + defer transaction.bytesMutex.Unlock() + + // return bytes if the object has been marshaled in the mean time + if bytes := transaction.bytes; bytes != nil { + return bytes + } + + // create marshal helper + marshalUtil := marshalutil.New() + + // marshal essence bytes + marshalUtil.WriteBytes(transaction.EssenceBytes()) + + // marshal signature bytes + marshalUtil.WriteBytes(transaction.SignatureBytes()) + + // store marshaled result + transaction.bytes = marshalUtil.Bytes() + + return transaction.bytes +} + +func (transaction *Transaction) Sign(signature signaturescheme.SignatureScheme) *Transaction { + transaction.signatures.Add(signature.Address(), signature.Sign(transaction.EssenceBytes())) + + return transaction +} + +func (transaction *Transaction) String() string { + id := transaction.Id() + + return stringify.Struct("Transaction"+fmt.Sprintf("(%p)", transaction), + stringify.StructField("id", base58.Encode(id[:])), + stringify.StructField("inputs", transaction.inputs), + stringify.StructField("outputs", transaction.outputs), + stringify.StructField("signatures", transaction.signatures), + ) +} + +// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// region IMPLEMENT StorableObject interface /////////////////////////////////////////////////////////////////////////// + +// define contract (ensure that the struct fulfills the given interface) +var _ objectstorage.StorableObject = &Transaction{} + +func (transaction *Transaction) GetStorageKey() []byte { + id := transaction.Id() + + return id[:] +} + +func (transaction *Transaction) Update(other objectstorage.StorableObject) { + panic("update forbidden") +} + +// MarshalBinary returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler interface. +func (transaction *Transaction) MarshalBinary() ([]byte, error) { + return transaction.Bytes(), nil +} + +func (transaction *Transaction) UnmarshalBinary(bytes []byte) (err error) { + _, err, _ = FromBytes(bytes, transaction) + + return +} + +// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// CachedTransaction is a wrapper for the object storage, that takes care of type casting the Transaction objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of Transaction, without having to manually type cast over and over again. +type CachedTransaction struct { + objectstorage.CachedObject +} + +// Retain overrides the underlying method to return a new CachedTransaction instead of a generic CachedObject. +func (cachedTransaction *CachedTransaction) Retain() *CachedTransaction { + return &CachedTransaction{cachedTransaction.CachedObject.Retain()} +} + +// Consume overrides the underlying method to use a CachedTransaction object instead of a generic CachedObject in the +// consumer). +func (cachedTransaction *CachedTransaction) Consume(consumer func(metadata *Transaction)) bool { + return cachedTransaction.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*Transaction)) + }) +} + +// Unwrap provides a way to retrieve a type casted version of the underlying object. +func (cachedTransaction *CachedTransaction) Unwrap() *Transaction { + if untypedTransaction := cachedTransaction.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*Transaction); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} diff --git a/packages/binary/valuetransfer/transferoutput/id/id.go b/packages/binary/valuetransfer/transferoutput/id/id.go deleted file mode 100644 index b8d9252e..00000000 --- a/packages/binary/valuetransfer/transferoutput/id/id.go +++ /dev/null @@ -1,43 +0,0 @@ -package id - -import ( - "github.com/mr-tron/base58" - - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" -) - -type Id [Length]byte - -func New(outputAddress address.Address, transferId id.Id) (transferOutputId Id) { - copy(transferOutputId[:address.Length], outputAddress.Bytes()) - copy(transferOutputId[address.Length:], transferId[:]) - - return -} - -func FromBytes(bytes []byte) (transferOutputId Id) { - copy(transferOutputId[:], bytes) - - return -} - -func (transferOutputId Id) GetAddress() (address address.Address) { - copy(address[:], transferOutputId[:]) - - return -} - -func (transferOutputId Id) GetTransferId() id.Id { - return id.New(transferOutputId[address.Length:]) -} - -func (transferOutputId Id) ToBytes() []byte { - return transferOutputId[:] -} - -func (transferOutputId Id) String() string { - return "Id(" + base58.Encode(transferOutputId[:]) + ")" -} - -const Length = address.Length + id.Length diff --git a/packages/binary/valuetransfer/transferoutput/transferoutput.go b/packages/binary/valuetransfer/transferoutput/transferoutput.go deleted file mode 100644 index b2808491..00000000 --- a/packages/binary/valuetransfer/transferoutput/transferoutput.go +++ /dev/null @@ -1,127 +0,0 @@ -package transferoutput - -import ( - "fmt" - - "github.com/iotaledger/hive.go/objectstorage" - - "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance" - transferId "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" -) - -// TransferOutput represents the output of a transfer and it contains the balances and the identifiers for this output. -type TransferOutput struct { - address address.Address - transferId transferId.Id - balances []*coloredbalance.ColoredBalance - - objectstorage.StorableObjectFlags - storageKey []byte -} - -// New creates a transfer output that contains the balances and identifiers of a successful transfer. -func New(address address.Address, transferId transferId.Id, balances []*coloredbalance.ColoredBalance) *TransferOutput { - return &TransferOutput{ - address: address, - transferId: transferId, - balances: balances, - - storageKey: marshalutil.New().WriteBytes(address.Bytes()).WriteBytes(transferId.Bytes()).Bytes(), - } -} - -// FromStorage get's called when we restore a TransferOutput from the storage. -// In contrast to other database models, it unmarshals some information from the key so we simply store the key before -// it gets handed over to UnmarshalBinary (by the ObjectStorage). -func FromStorage(keyBytes []byte) objectstorage.StorableObject { - return &TransferOutput{ - storageKey: marshalutil.New(keyBytes).Bytes(true), - } -} - -// Address returns the address that this output belongs to. -func (transferOutput *TransferOutput) Address() address.Address { - return transferOutput.address -} - -// TransferId returns the transfer id, that created this output. -func (transferOutput *TransferOutput) TransferId() transferId.Id { - return transferOutput.transferId -} - -// Balances returns the colored balances (color + balance) that this output contains. -func (transferOutput *TransferOutput) Balances() []*coloredbalance.ColoredBalance { - return transferOutput.balances -} - -// MarshalBinary marshals the balances into a sequence of bytes - the address and transferId are stored inside the key -// and are ignored here. -func (transferOutput *TransferOutput) MarshalBinary() (data []byte, err error) { - // determine amount of balances in the output - balanceCount := len(transferOutput.balances) - - // initialize helper - marshalUtil := marshalutil.New(4 + balanceCount*coloredbalance.Length) - - // marshal the amount of balances - marshalUtil.WriteUint32(uint32(balanceCount)) - - // marshal balances - for _, balance := range transferOutput.balances { - marshalUtil.WriteBytes(balance.Bytes()) - } - - return -} - -// UnmarshalBinary restores a TransferOutput from a serialized version in the ObjectStorage with parts of the object -// being stored in its key rather than the content of the database to reduce storage requirements. -func (transferOutput *TransferOutput) UnmarshalBinary(data []byte) (err error) { - // check if the storageKey has been set - if transferOutput.storageKey == nil { - return fmt.Errorf("missing storageKey when trying to unmarshal TransferOutput (it contains part of the information)") - } - - // parse information from storageKey - storageKeyUnmarshaler := marshalutil.New(transferOutput.storageKey) - transferOutput.address, err = address.Parse(storageKeyUnmarshaler) - if err != nil { - return - } - transferOutput.transferId, err = transferId.Parse(storageKeyUnmarshaler) - if err != nil { - return - } - - // parse information from content bytes - contentUnmarshaler := marshalutil.New(data) - balanceCount, err := contentUnmarshaler.ReadUint32() - if err != nil { - return - } - transferOutput.balances = make([]*coloredbalance.ColoredBalance, balanceCount) - for i := uint32(0); i < balanceCount; i++ { - transferOutput.balances[i], err = coloredbalance.Parse(contentUnmarshaler) - if err != nil { - return - } - } - - return -} - -// Update is disabled and panics if it ever gets called - it is required to match StorableObject interface. -func (transferOutput *TransferOutput) Update(other objectstorage.StorableObject) { - panic("this object should never be updated") -} - -// GetStorageKey returns the key that is used to store the object in the database. -// It is required to match StorableObject interface. -func (transferOutput *TransferOutput) GetStorageKey() []byte { - return transferOutput.storageKey -} - -// define contract (ensure that the struct fulfills the given interface) -var _ objectstorage.StorableObject = &TransferOutput{} diff --git a/packages/gossip/manager.go b/packages/gossip/manager.go index 24b72a25..d3d6ccba 100644 --- a/packages/gossip/manager.go +++ b/packages/gossip/manager.go @@ -6,7 +6,7 @@ import ( "net" "sync" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/golang/protobuf/proto" pb "github.com/iotaledger/goshimmer/packages/gossip/proto" @@ -26,7 +26,7 @@ var ( ) // GetTransaction defines a function that returns the transaction data with the given hash. -type GetTransaction func(transactionId transaction.Id) ([]byte, error) +type GetTransaction func(transactionId message.Id) ([]byte, error) type Manager struct { local *peer.Local @@ -256,7 +256,7 @@ func (m *Manager) handlePacket(data []byte, p *peer.Peer) error { } m.log.Debugw("received message", "type", "TRANSACTION_REQUEST", "id", p.ID()) // do something - txId, err, _ := transaction.IdFromBytes(msg.GetHash()) + txId, err, _ := message.IdFromBytes(msg.GetHash()) if err != nil { m.log.Debugw("error getting transaction", "hash", msg.GetHash(), "err", err) } diff --git a/packages/gossip/manager_test.go b/packages/gossip/manager_test.go index afb6ee59..f91adc10 100644 --- a/packages/gossip/manager_test.go +++ b/packages/gossip/manager_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/golang/protobuf/proto" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" pb "github.com/iotaledger/goshimmer/packages/gossip/proto" "github.com/iotaledger/goshimmer/packages/gossip/server" "github.com/iotaledger/hive.go/autopeering/peer" @@ -27,7 +27,7 @@ var ( testTxData = []byte("testTx") ) -func getTestTransaction(transaction.Id) ([]byte, error) { return testTxData, nil } +func getTestTransaction(message.Id) ([]byte, error) { return testTxData, nil } func TestClose(t *testing.T) { _, detach := newEventMock(t) diff --git a/plugins/gossip/gossip.go b/plugins/gossip/gossip.go index 7eaf015f..c32d37d8 100644 --- a/plugins/gossip/gossip.go +++ b/plugins/gossip/gossip.go @@ -8,7 +8,7 @@ import ( "github.com/iotaledger/hive.go/autopeering/peer/service" "github.com/iotaledger/hive.go/logger" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" gp "github.com/iotaledger/goshimmer/packages/gossip" "github.com/iotaledger/goshimmer/packages/gossip/server" "github.com/iotaledger/goshimmer/plugins/autopeering/local" @@ -76,10 +76,10 @@ func start(shutdownSignal <-chan struct{}) { log.Info("Stopping " + name + " ...") } -func getTransaction(transactionId transaction.Id) (bytes []byte, err error) { +func getTransaction(transactionId message.Id) (bytes []byte, err error) { log.Debugw("get tx from db", "id", transactionId.String()) - if !tangle.Instance.GetTransaction(transactionId).Consume(func(transaction *transaction.Transaction) { + if !tangle.Instance.GetTransaction(transactionId).Consume(func(transaction *message.Transaction) { bytes = transaction.Bytes() }) { err = fmt.Errorf("transaction not found: hash=%s", transactionId) diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go index 3d917c98..ceca12f9 100644 --- a/plugins/gossip/plugin.go +++ b/plugins/gossip/plugin.go @@ -8,7 +8,7 @@ import ( "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/node" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" "github.com/iotaledger/goshimmer/packages/gossip" "github.com/iotaledger/goshimmer/packages/shutdown" @@ -77,16 +77,16 @@ func configureEvents() { })) // configure flow of outgoing transactions (gossip on solidification) - tangle.Instance.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, transactionMetadata *transactionmetadata.CachedTransactionMetadata) { + tangle.Instance.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *message.CachedTransaction, transactionMetadata *transactionmetadata.CachedTransactionMetadata) { transactionMetadata.Release() - cachedTransaction.Consume(func(transaction *transaction.Transaction) { + cachedTransaction.Consume(func(transaction *message.Transaction) { mgr.SendTransaction(transaction.Bytes()) }) })) // request missing transactions - tangle.TransactionRequester.Events.SendRequest.Attach(events.NewClosure(func(transactionId transaction.Id) { + tangle.TransactionRequester.Events.SendRequest.Attach(events.NewClosure(func(transactionId message.Id) { mgr.RequestTransaction(transactionId[:]) })) } diff --git a/plugins/metrics/plugin.go b/plugins/metrics/plugin.go index 28f3013c..501e05f9 100644 --- a/plugins/metrics/plugin.go +++ b/plugins/metrics/plugin.go @@ -8,7 +8,7 @@ import ( "github.com/iotaledger/hive.go/node" "github.com/iotaledger/hive.go/timeutil" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" "github.com/iotaledger/goshimmer/packages/shutdown" "github.com/iotaledger/goshimmer/plugins/tangle" @@ -18,7 +18,7 @@ var PLUGIN = node.NewPlugin("Metrics", node.Enabled, configure, run) func configure(plugin *node.Plugin) { // increase received TPS counter whenever we receive a new transaction - tangle.Instance.Events.TransactionAttached.Attach(events.NewClosure(func(transaction *transaction.CachedTransaction, metadata *transactionmetadata.CachedTransactionMetadata) { + tangle.Instance.Events.TransactionAttached.Attach(events.NewClosure(func(transaction *message.CachedTransaction, metadata *transactionmetadata.CachedTransactionMetadata) { transaction.Release() metadata.Release() diff --git a/plugins/spa/explorer_routes.go b/plugins/spa/explorer_routes.go index e98cccbb..7be33868 100644 --- a/plugins/spa/explorer_routes.go +++ b/plugins/spa/explorer_routes.go @@ -4,7 +4,7 @@ import ( "net/http" "sync" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/plugins/tangle" "github.com/labstack/echo" @@ -23,7 +23,7 @@ type ExplorerTx struct { MWM int `json:"mwm"` } -func createExplorerTx(tx *transaction.Transaction) (*ExplorerTx, error) { +func createExplorerTx(tx *message.Transaction) (*ExplorerTx, error) { transactionId := tx.GetId() txMetadata := tangle.Instance.GetTransactionMetadata(transactionId) @@ -57,7 +57,7 @@ type SearchResult struct { func setupExplorerRoutes(routeGroup *echo.Group) { routeGroup.GET("/tx/:hash", func(c echo.Context) (err error) { - transactionId, err := transaction.NewId(c.Param("hash")) + transactionId, err := message.NewId(c.Param("hash")) if err != nil { return } @@ -91,7 +91,7 @@ func setupExplorerRoutes(routeGroup *echo.Group) { go func() { defer wg.Done() - transactionId, err := transaction.NewId(search) + transactionId, err := message.NewId(search) if err != nil { return } @@ -115,8 +115,8 @@ func setupExplorerRoutes(routeGroup *echo.Group) { }) } -func findTransaction(transactionId transaction.Id) (explorerTx *ExplorerTx, err error) { - if !tangle.Instance.GetTransaction(transactionId).Consume(func(transaction *transaction.Transaction) { +func findTransaction(transactionId message.Id) (explorerTx *ExplorerTx, err error) { + if !tangle.Instance.GetTransaction(transactionId).Consume(func(transaction *message.Transaction) { explorerTx, err = createExplorerTx(transaction) }) { err = errors.Wrapf(ErrNotFound, "tx hash: %s", transactionId.String()) diff --git a/plugins/spa/livefeed.go b/plugins/spa/livefeed.go index 7a6674c9..adea985e 100644 --- a/plugins/spa/livefeed.go +++ b/plugins/spa/livefeed.go @@ -7,7 +7,7 @@ import ( "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/workerpool" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" "github.com/iotaledger/goshimmer/packages/shutdown" "github.com/iotaledger/goshimmer/plugins/tangle" @@ -19,7 +19,7 @@ var liveFeedWorkerPool *workerpool.WorkerPool func configureLiveFeed() { liveFeedWorkerPool = workerpool.New(func(task workerpool.Task) { - task.Param(0).(*transaction.CachedTransaction).Consume(func(transaction *transaction.Transaction) { + task.Param(0).(*message.CachedTransaction).Consume(func(transaction *message.Transaction) { sendToAllWSClient(&msg{MsgTypeTx, &tx{transaction.GetId().String(), 0}}) }) @@ -29,7 +29,7 @@ func configureLiveFeed() { func runLiveFeed() { newTxRateLimiter := time.NewTicker(time.Second / 10) - notifyNewTx := events.NewClosure(func(tx *transaction.CachedTransaction, metadata *transactionmetadata.CachedTransactionMetadata) { + notifyNewTx := events.NewClosure(func(tx *message.CachedTransaction, metadata *transactionmetadata.CachedTransactionMetadata) { metadata.Release() select { diff --git a/plugins/tangle/plugin.go b/plugins/tangle/plugin.go index acc998fe..0b3f156d 100644 --- a/plugins/tangle/plugin.go +++ b/plugins/tangle/plugin.go @@ -5,7 +5,7 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/storageprefix" "github.com/iotaledger/goshimmer/packages/binary/tangle" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" "github.com/iotaledger/goshimmer/packages/binary/tangle/tipselector" "github.com/iotaledger/goshimmer/packages/binary/tangle/transactionparser" @@ -41,7 +41,7 @@ func configure(*node.Plugin) { Instance = tangle.New(database.GetBadgerInstance(), storageprefix.MainNet) // setup TransactionParser - TransactionParser.Events.TransactionParsed.Attach(events.NewClosure(func(transaction *transaction.Transaction, peer *peer.Peer) { + TransactionParser.Events.TransactionParsed.Attach(events.NewClosure(func(transaction *message.Transaction, peer *peer.Peer) { // TODO: ADD PEER Instance.AttachTransaction(transaction) @@ -49,16 +49,16 @@ func configure(*node.Plugin) { // setup TransactionRequester Instance.Events.TransactionMissing.Attach(events.NewClosure(TransactionRequester.ScheduleRequest)) - Instance.Events.MissingTransactionReceived.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { + Instance.Events.MissingTransactionReceived.Attach(events.NewClosure(func(cachedTransaction *message.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { cachedTransactionMetadata.Release() - cachedTransaction.Consume(func(transaction *transaction.Transaction) { + cachedTransaction.Consume(func(transaction *message.Transaction) { TransactionRequester.StopRequest(transaction.GetId()) }) })) // setup TipSelector - Instance.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { + Instance.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *message.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { cachedTransactionMetadata.Release() cachedTransaction.Consume(TipSelector.AddTip) diff --git a/plugins/webapi/gtta/plugin.go b/plugins/webapi/gtta/plugin.go index 4e05e8e3..ebebea7b 100644 --- a/plugins/webapi/gtta/plugin.go +++ b/plugins/webapi/gtta/plugin.go @@ -3,7 +3,7 @@ package gtta import ( "net/http" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/message" "github.com/iotaledger/goshimmer/plugins/tangle" "github.com/iotaledger/goshimmer/plugins/webapi" "github.com/iotaledger/hive.go/node" @@ -24,6 +24,6 @@ func Handler(c echo.Context) error { } type Response struct { - BranchTransaction transaction.Id `json:"branchTransaction"` - TrunkTransaction transaction.Id `json:"trunkTransaction"` + BranchTransaction message.Id `json:"branchTransaction"` + TrunkTransaction message.Id `json:"trunkTransaction"` } -- GitLab