diff --git a/go.mod b/go.mod index 7afa104f1b4a6be435bfecf59d1042b3d6670695..c51b84bdf89a6836d872ff2d34f6a45d55206833 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,11 @@ module github.com/iotaledger/goshimmer go 1.13 require ( - cloud.google.com/go v0.36.0 // indirect github.com/dgraph-io/badger/v2 v2.0.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b // indirect github.com/gobuffalo/envy v1.8.1 // indirect - github.com/gobuffalo/logger v1.0.3 // indirect + github.com/gobuffalo/logger v1.0.3 github.com/gobuffalo/packr/v2 v2.7.1 github.com/golang/protobuf v1.3.2 github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2 @@ -37,12 +36,12 @@ require ( github.com/valyala/fasttemplate v1.1.0 // indirect go.uber.org/atomic v1.5.1 go.uber.org/zap v1.13.0 + golang.org/dl v0.0.0-20200212233958-09d79dcf4807 // indirect golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect golang.org/x/text v0.3.2 // indirect golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 // indirect - google.golang.org/appengine v1.4.0 // indirect gopkg.in/ini.v1 v1.51.1 // indirect gopkg.in/yaml.v2 v2.2.7 // indirect ) diff --git a/go.sum b/go.sum index d8296fac8999ae6b0c2997016bc2f61dc80b3b69..a72469bc23877dbdd3c26167d4e37561f2ae3247 100644 --- a/go.sum +++ b/go.sum @@ -314,6 +314,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/dl v0.0.0-20200212233958-09d79dcf4807 h1:P3ZXCWM1Xdo1ZUpMAM/KocwYgn5r/cKxffvaoYUlfYE= +golang.org/dl v0.0.0-20200212233958-09d79dcf4807/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/main.go b/main.go index 2f94717210c0aea39f96347dd3ba68315da7f130..32513b07b2b64b42d5a1fb4572e4953337884a87 100644 --- a/main.go +++ b/main.go @@ -4,27 +4,14 @@ import ( "net/http" _ "net/http/pprof" - "github.com/iotaledger/goshimmer/plugins/analysis" + "github.com/iotaledger/goshimmer/plugins/gracefulshutdown" + + "github.com/iotaledger/goshimmer/plugins/tangle" + "github.com/iotaledger/goshimmer/plugins/autopeering" - "github.com/iotaledger/goshimmer/plugins/bundleprocessor" "github.com/iotaledger/goshimmer/plugins/cli" "github.com/iotaledger/goshimmer/plugins/gossip" - "github.com/iotaledger/goshimmer/plugins/gracefulshutdown" - "github.com/iotaledger/goshimmer/plugins/graph" - "github.com/iotaledger/goshimmer/plugins/metrics" "github.com/iotaledger/goshimmer/plugins/remotelog" - "github.com/iotaledger/goshimmer/plugins/spa" - "github.com/iotaledger/goshimmer/plugins/tangle" - "github.com/iotaledger/goshimmer/plugins/tipselection" - "github.com/iotaledger/goshimmer/plugins/webapi" - webapi_broadcastData "github.com/iotaledger/goshimmer/plugins/webapi/broadcastData" - webapi_findTransactionHashes "github.com/iotaledger/goshimmer/plugins/webapi/findTransactionHashes" - webapi_getNeighbors "github.com/iotaledger/goshimmer/plugins/webapi/getNeighbors" - webapi_getTransactionObjectsByHash "github.com/iotaledger/goshimmer/plugins/webapi/getTransactionObjectsByHash" - webapi_getTransactionTrytesByHash "github.com/iotaledger/goshimmer/plugins/webapi/getTransactionTrytesByHash" - webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi/gtta" - webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi/spammer" - webapi_auth "github.com/iotaledger/goshimmer/plugins/webauth" "github.com/iotaledger/hive.go/node" ) @@ -39,27 +26,28 @@ func main() { remotelog.PLUGIN, autopeering.PLUGIN, - gossip.PLUGIN, tangle.PLUGIN, - bundleprocessor.PLUGIN, - analysis.PLUGIN, + gossip.PLUGIN, gracefulshutdown.PLUGIN, - tipselection.PLUGIN, - metrics.PLUGIN, - - webapi.PLUGIN, - webapi_auth.PLUGIN, - webapi_gtta.PLUGIN, - webapi_spammer.PLUGIN, - webapi_broadcastData.PLUGIN, - webapi_getTransactionTrytesByHash.PLUGIN, - webapi_getTransactionObjectsByHash.PLUGIN, - webapi_findTransactionHashes.PLUGIN, - webapi_getNeighbors.PLUGIN, - webapi_spammer.PLUGIN, - spa.PLUGIN, - graph.PLUGIN, + /* + analysis.PLUGIN, + metrics.PLUGIN, + + webapi.PLUGIN, + webapi_auth.PLUGIN, + webapi_gtta.PLUGIN, + webapi_spammer.PLUGIN, + webapi_broadcastData.PLUGIN, + webapi_getTransactionTrytesByHash.PLUGIN, + webapi_getTransactionObjectsByHash.PLUGIN, + webapi_findTransactionHashes.PLUGIN, + webapi_getNeighbors.PLUGIN, + webapi_spammer.PLUGIN, + + //spa.PLUGIN, + //graph.PLUGIN, + */ ), ) } diff --git a/packages/binary/datastructure/random_map.go b/packages/binary/datastructure/random_map.go new file mode 100644 index 0000000000000000000000000000000000000000..ff1692c441440377d9dc325d1745401e738d7f3d --- /dev/null +++ b/packages/binary/datastructure/random_map.go @@ -0,0 +1,129 @@ +package datastructure + +import ( + "math/rand" + "sync" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +type randomMapEntry struct { + key interface{} + value interface{} + keyIndex int +} + +type RandomMap struct { + rawMap map[interface{}]*randomMapEntry + keys []interface{} + size int + mutex sync.RWMutex +} + +func NewRandomMap() *RandomMap { + return &RandomMap{ + rawMap: make(map[interface{}]*randomMapEntry), + keys: make([]interface{}, 0), + } +} + +func (rmap *RandomMap) Set(key interface{}, value interface{}) (updated bool) { + rmap.mutex.Lock() + + if entry, exists := rmap.rawMap[key]; exists { + if entry.value != value { + entry.value = value + + updated = true + } + } else { + rmap.rawMap[key] = &randomMapEntry{ + key: key, + value: value, + keyIndex: rmap.size, + } + + updated = true + + rmap.keys = append(rmap.keys, key) + + rmap.size++ + } + + rmap.mutex.Unlock() + + return +} + +func (rmap *RandomMap) Get(key interface{}) (result interface{}, exists bool) { + rmap.mutex.RLock() + + if entry, entryExists := rmap.rawMap[key]; entryExists { + result = entry.value + exists = entryExists + } + + rmap.mutex.RUnlock() + + return +} + +func (rmap *RandomMap) Delete(key interface{}) (result interface{}, exists bool) { + rmap.mutex.RLock() + + if _, entryExists := rmap.rawMap[key]; entryExists { + rmap.mutex.RUnlock() + rmap.mutex.Lock() + + if entry, entryExists := rmap.rawMap[key]; entryExists { + delete(rmap.rawMap, key) + + rmap.size-- + + if entry.keyIndex != rmap.size { + oldKey := entry.keyIndex + movedKey := rmap.keys[rmap.size] + + rmap.rawMap[movedKey].keyIndex = oldKey + + rmap.keys[oldKey] = movedKey + } + + rmap.keys = rmap.keys[:rmap.size] + + result = entry.value + exists = true + } + + rmap.mutex.Unlock() + } else { + rmap.mutex.RUnlock() + } + + return +} + +func (rmap *RandomMap) Size() (result int) { + rmap.mutex.RLock() + + result = rmap.size + + rmap.mutex.RUnlock() + + return +} + +func (rmap *RandomMap) RandomEntry() (result interface{}) { + rmap.mutex.RLock() + + if rmap.size >= 1 { + result = rmap.rawMap[rmap.keys[rand.Intn(rmap.size)]].value + } + + rmap.mutex.RUnlock() + + return +} diff --git a/packages/binary/storageprefix/storageprefix.go b/packages/binary/storageprefix/storageprefix.go index 1e55f2db25ff3bd2703056c8ea61c0aa048fda84..6493adf68473e6cdd98ecd4befaa510967437220 100644 --- a/packages/binary/storageprefix/storageprefix.go +++ b/packages/binary/storageprefix/storageprefix.go @@ -1,17 +1,19 @@ package storageprefix var ( - TangleTransaction = []byte{0} - TangleTransactionMetadata = []byte{1} - TangleApprovers = []byte{2} - TangleMissingTransaction = []byte{3} + Mainnet = []byte{0} - ValueTangleTransferMetadata = []byte{4} - ValueTangleConsumers = []byte{5} - ValueTangleMissingTransfers = []byte{6} + TangleTransaction = []byte{1} + TangleTransactionMetadata = []byte{2} + TangleApprovers = []byte{3} + TangleMissingTransaction = []byte{4} - LedgerStateTransferOutput = []byte{7} - LedgerStateTransferOutputBooking = []byte{8} - LedgerStateReality = []byte{9} - LedgerStateConflictSet = []byte{10} + ValueTangleTransferMetadata = []byte{5} + ValueTangleConsumers = []byte{6} + ValueTangleMissingTransfers = []byte{7} + + LedgerStateTransferOutput = []byte{8} + LedgerStateTransferOutputBooking = []byte{9} + LedgerStateReality = []byte{10} + LedgerStateConflictSet = []byte{11} ) diff --git a/packages/binary/tangle/model/transaction/cached_transaction.go b/packages/binary/tangle/model/transaction/cached_transaction.go index 5f177ea76c1ce12c474bfe7a1be0ab2b3d0315af..d95494ed6e8706a0b2708a963b17cce3925461f5 100644 --- a/packages/binary/tangle/model/transaction/cached_transaction.go +++ b/packages/binary/tangle/model/transaction/cached_transaction.go @@ -12,7 +12,7 @@ func (cachedTransaction *CachedTransaction) Retain() *CachedTransaction { return &CachedTransaction{cachedTransaction.CachedObject.Retain()} } -func (cachedTransaction *CachedTransaction) Consume(consumer func(object *Transaction)) bool { +func (cachedTransaction *CachedTransaction) Consume(consumer func(transaction *Transaction)) bool { return cachedTransaction.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*Transaction)) }) diff --git a/packages/binary/tangle/tipselector/events.go b/packages/binary/tangle/tipselector/events.go new file mode 100644 index 0000000000000000000000000000000000000000..563e4a7066545d609c13b8b74c9f4a292f3a5607 --- /dev/null +++ b/packages/binary/tangle/tipselector/events.go @@ -0,0 +1,15 @@ +package tipselector + +import ( + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/hive.go/events" +) + +type Events struct { + TipAdded *events.Event + TipRemoved *events.Event +} + +func transactionIdEvent(handler interface{}, params ...interface{}) { + handler.(func(transaction.Id))(params[0].(transaction.Id)) +} diff --git a/packages/binary/tangle/tipselector/tipselector.go b/packages/binary/tangle/tipselector/tipselector.go new file mode 100644 index 0000000000000000000000000000000000000000..1b03500cb316ea720589c0bbf2a99fe09b111805 --- /dev/null +++ b/packages/binary/tangle/tipselector/tipselector.go @@ -0,0 +1,68 @@ +package tipselector + +import ( + "github.com/iotaledger/goshimmer/packages/binary/datastructure" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/hive.go/events" +) + +type TipSelector struct { + tips *datastructure.RandomMap + Events Events +} + +func New() *TipSelector { + return &TipSelector{ + tips: datastructure.NewRandomMap(), + Events: Events{ + TipAdded: events.NewEvent(transactionIdEvent), + TipRemoved: events.NewEvent(transactionIdEvent), + }, + } +} + +func (tipSelector *TipSelector) AddTip(transaction *transaction.Transaction) { + transactionId := transaction.GetId() + if tipSelector.tips.Set(transactionId, transactionId) { + tipSelector.Events.TipAdded.Trigger(transactionId) + } + + trunkTransactionId := transaction.GetTrunkTransactionId() + if _, deleted := tipSelector.tips.Delete(trunkTransactionId); deleted { + tipSelector.Events.TipRemoved.Trigger(trunkTransactionId) + } + + branchTransactionId := transaction.GetBranchTransactionId() + if _, deleted := tipSelector.tips.Delete(branchTransactionId); deleted { + tipSelector.Events.TipRemoved.Trigger(branchTransactionId) + } +} + +func (tipSelector *TipSelector) GetTips() (trunkTransaction, branchTransaction transaction.Id) { + tip := tipSelector.tips.RandomEntry() + if tip == nil { + trunkTransaction = transaction.EmptyId + branchTransaction = transaction.EmptyId + + return + } + + branchTransaction = tip.(transaction.Id) + + if tipSelector.tips.Size() == 1 { + trunkTransaction = branchTransaction + + return + } + + trunkTransaction = tipSelector.tips.RandomEntry().(transaction.Id) + for trunkTransaction == branchTransaction && tipSelector.tips.Size() > 1 { + trunkTransaction = tipSelector.tips.RandomEntry().(transaction.Id) + } + + return +} + +func (tipSelector *TipSelector) GetTipCount() int { + return tipSelector.tips.Size() +} diff --git a/packages/binary/tangle/tipselector/tipselector_test.go b/packages/binary/tangle/tipselector/tipselector_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0bd3d385482c852445a5d92969e4dcc990b08c05 --- /dev/null +++ b/packages/binary/tangle/tipselector/tipselector_test.go @@ -0,0 +1,51 @@ +package tipselector + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/iotaledger/goshimmer/packages/binary/identity" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" +) + +func Test(t *testing.T) { + // create tip selector + tipSelector := New() + + // check if first tips point to genesis + trunk1, branch1 := tipSelector.GetTips() + assert.Equal(t, transaction.EmptyId, trunk1) + assert.Equal(t, transaction.EmptyId, branch1) + + // create a transaction and attach it + transaction1 := transaction.New(trunk1, branch1, identity.Generate(), data.New([]byte("testtransaction"))) + tipSelector.AddTip(transaction1) + + // check if the tip shows up in the tip count + assert.Equal(t, 1, tipSelector.GetTipCount()) + + // check if next tips point to our first transaction + trunk2, branch2 := tipSelector.GetTips() + assert.Equal(t, transaction1.GetId(), trunk2) + assert.Equal(t, transaction1.GetId(), branch2) + + // create a 2nd transaction and attach it + transaction2 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("testtransaction"))) + tipSelector.AddTip(transaction2) + + // check if the tip shows up in the tip count + assert.Equal(t, 2, tipSelector.GetTipCount()) + + // attach a transaction to our two tips + trunk3, branch3 := tipSelector.GetTips() + transaction3 := transaction.New(trunk3, branch3, identity.Generate(), data.New([]byte("testtransaction"))) + tipSelector.AddTip(transaction3) + + // check if the tip shows replaces the current tips + trunk4, branch4 := tipSelector.GetTips() + assert.Equal(t, 1, tipSelector.GetTipCount()) + assert.Equal(t, transaction3.GetId(), trunk4) + assert.Equal(t, transaction3.GetId(), branch4) +} diff --git a/packages/gossip/manager.go b/packages/gossip/manager.go index 49a9d0d9921b930a89fa2be9963a405039b6bc81..e28c81afda3211d546a8f865ec6783a70348523c 100644 --- a/packages/gossip/manager.go +++ b/packages/gossip/manager.go @@ -6,6 +6,8 @@ import ( "net" "sync" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/golang/protobuf/proto" pb "github.com/iotaledger/goshimmer/packages/gossip/proto" "github.com/iotaledger/goshimmer/packages/gossip/server" @@ -24,7 +26,7 @@ var ( ) // GetTransaction defines a function that returns the transaction data with the given hash. -type GetTransaction func(txHash []byte) ([]byte, error) +type GetTransaction func(transactionId transaction.Id) ([]byte, error) type Manager struct { local *peer.Local @@ -254,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 - tx, err := m.getTransaction(msg.GetHash()) + tx, err := m.getTransaction(transaction.NewId(msg.GetHash())) if err != nil { m.log.Debugw("error getting transaction", "hash", msg.GetHash(), "err", err) } else { diff --git a/plugins/bundleprocessor/bundleprocessor.go b/plugins/bundleprocessor/bundleprocessor.go deleted file mode 100644 index 6085e2a97dfe54457ee630c7064f51a6d03c9f7f..0000000000000000000000000000000000000000 --- a/plugins/bundleprocessor/bundleprocessor.go +++ /dev/null @@ -1,101 +0,0 @@ -package bundleprocessor - -import ( - "fmt" - "runtime" - - "github.com/iotaledger/goshimmer/packages/model/bundle" - "github.com/iotaledger/goshimmer/packages/model/transactionmetadata" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/plugins/tangle" - "github.com/iotaledger/hive.go/workerpool" - "github.com/iotaledger/iota.go/trinary" -) - -var workerPool = workerpool.New(func(task workerpool.Task) { - if err := ProcessSolidBundleHead(task.Param(0).(*value_transaction.ValueTransaction)); err != nil { - Events.Error.Trigger(err) - } - - task.Return(nil) -}, workerpool.WorkerCount(WORKER_COUNT), workerpool.QueueSize(2*WORKER_COUNT)) - -var WORKER_COUNT = runtime.NumCPU() - -func ProcessSolidBundleHead(headTransaction *value_transaction.ValueTransaction) error { - // only process the bundle if we didn't process it, yet - _, err := tangle.GetBundle(headTransaction.GetHash(), func(headTransactionHash trinary.Trytes) (*bundle.Bundle, error) { - // abort if bundle syntax is wrong - if !headTransaction.IsHead() { - return nil, fmt.Errorf("%w: transaction needs to be the head of the bundle", ErrProcessBundleFailed) - } - - // initialize event variables - newBundle := bundle.New(headTransactionHash) - bundleTransactions := make([]*value_transaction.ValueTransaction, 0) - - // iterate through trunk transactions until we reach the tail - currentTransaction := headTransaction - for { - // abort if we reached a previous head - if currentTransaction.IsHead() && currentTransaction != headTransaction { - newBundle.SetTransactionHashes(mapTransactionsToTransactionHashes(bundleTransactions)) - - Events.InvalidBundle.Trigger(newBundle, bundleTransactions) - return nil, fmt.Errorf("%w: missing bundle tail", ErrProcessBundleFailed) - } - - // update bundle transactions - bundleTransactions = append(bundleTransactions, currentTransaction) - - // retrieve & update metadata - currentTransactionMetadata, err := tangle.GetTransactionMetadata(currentTransaction.GetHash(), transactionmetadata.New) - if err != nil { - return nil, fmt.Errorf("%w: failed to retrieve transaction metadata: %s", ErrProcessBundleFailed, err) - } - currentTransactionMetadata.SetBundleHeadHash(headTransactionHash) - - // update value bundle flag - if !newBundle.IsValueBundle() && currentTransaction.GetValue() < 0 { - newBundle.SetValueBundle(true) - } - - // if we are done -> trigger events - if currentTransaction.IsTail() { - newBundle.SetTransactionHashes(mapTransactionsToTransactionHashes(bundleTransactions)) - - if newBundle.IsValueBundle() { - valueBundleProcessorWorkerPool.Submit(newBundle, bundleTransactions) - - return newBundle, nil - } - - Events.BundleSolid.Trigger(newBundle, bundleTransactions) - - return newBundle, nil - } - - // try to iterate to next turn - if nextTransaction, err := tangle.GetTransaction(currentTransaction.GetTrunkTransactionHash()); err != nil { - return nil, fmt.Errorf("%w: failed to retrieve trunk while processing bundle: %s", ErrProcessBundleFailed, err) - } else if nextTransaction == nil { - err := fmt.Errorf("%w: failed to retrieve trunk while processing bundle: missing trunk transaction %s\n", ErrProcessBundleFailed, currentTransaction.GetTrunkTransactionHash()) - fmt.Println(err) - return nil, err - } else { - currentTransaction = nextTransaction - } - } - }) - - return err -} - -func mapTransactionsToTransactionHashes(transactions []*value_transaction.ValueTransaction) (result []trinary.Trytes) { - result = make([]trinary.Trytes, len(transactions)) - for k, v := range transactions { - result[k] = v.GetHash() - } - - return -} diff --git a/plugins/bundleprocessor/bundleprocessor_test.go b/plugins/bundleprocessor/bundleprocessor_test.go deleted file mode 100644 index e7b90366bd676bf6a0ba3d284ba6e241a368b3f9..0000000000000000000000000000000000000000 --- a/plugins/bundleprocessor/bundleprocessor_test.go +++ /dev/null @@ -1,143 +0,0 @@ -package bundleprocessor - -import ( - "io/ioutil" - "os" - "sync" - "testing" - - "github.com/iotaledger/goshimmer/packages/client" - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/goshimmer/packages/model/bundle" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/packages/parameter" - "github.com/iotaledger/goshimmer/plugins/tangle" - "github.com/iotaledger/goshimmer/plugins/tipselection" - "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/hive.go/logger" - "github.com/iotaledger/hive.go/node" - "github.com/iotaledger/iota.go/consts" - "github.com/magiconair/properties/assert" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" -) - -var seed = client.NewSeed("YFHQWAUPCXC9S9DSHP9NDF9RLNPMZVCMSJKUKQP9SWUSUCPRQXCMDVDVZ9SHHESHIQNCXWBJF9UJSWE9Z", consts.SecurityLevelMedium) - -func init() { - err := parameter.LoadDefaultConfig(false) - if err != nil { - log.Fatalf("Failed to initialize config: %s", err) - } - logger.InitGlobalLogger(&viper.Viper{}) -} - -func BenchmarkValidateSignatures(b *testing.B) { - bundleFactory := client.NewBundleFactory() - bundleFactory.AddInput(seed.GetAddress(0), -400) - bundleFactory.AddOutput(seed.GetAddress(1), 400, "Testmessage") - bundleFactory.AddOutput(client.NewAddress("SJKUKQP9SWUSUCPRQXCMDVDVZ9SHHESHIQNCXWBJF9UJSWE9ZYFHQWAUPCXC9S9DSHP9NDF9RLNPMZVCM"), 400, "Testmessage") - - generatedBundle := bundleFactory.GenerateBundle(tipselection.GetRandomTip(), tipselection.GetRandomTip()) - - b.ResetTimer() - - var wg sync.WaitGroup - - for i := 0; i < b.N; i++ { - wg.Add(1) - - go func() { - ValidateSignatures(generatedBundle.GetEssenceHash(), generatedBundle.GetTransactions()) - - wg.Done() - }() - } - - wg.Wait() -} - -func TestValidateSignatures(t *testing.T) { - bundleFactory := client.NewBundleFactory() - bundleFactory.AddInput(seed.GetAddress(0), -400) - bundleFactory.AddOutput(seed.GetAddress(1), 400, "Testmessage") - bundleFactory.AddOutput(client.NewAddress("SJKUKQP9SWUSUCPRQXCMDVDVZ9SHHESHIQNCXWBJF9UJSWE9ZYFHQWAUPCXC9S9DSHP9NDF9RLNPMZVCM"), 400, "Testmessage") - - generatedBundle := bundleFactory.GenerateBundle(tipselection.GetRandomTip(), tipselection.GetRandomTip()) - - successful, err := ValidateSignatures(generatedBundle.GetEssenceHash(), generatedBundle.GetTransactions()) - if err != nil { - t.Error(err) - } - assert.Equal(t, successful, true, "validation failed") -} - -func TestProcessSolidBundleHead(t *testing.T) { - dir, err := ioutil.TempDir("", t.Name()) - require.NoError(t, err) - defer os.Remove(dir) - // use the tempdir for the database - parameter.NodeConfig.Set(database.CFG_DIRECTORY, dir) - - // start a test node - node.Start(node.Plugins(tangle.PLUGIN, PLUGIN)) - defer node.Shutdown() - - t.Run("data", func(t *testing.T) { - bundleFactory := client.NewBundleFactory() - bundleFactory.AddOutput(seed.GetAddress(1), 400, "Testmessage") - bundleFactory.AddOutput(client.NewAddress("SJKUKQP9SWUSUCPRQXCMDVDVZ9SHHESHIQNCXWBJF9UJSWE9ZYFHQWAUPCXC9S9DSHP9NDF9RLNPMZVCM"), 400, "Testmessage") - - generatedBundle := bundleFactory.GenerateBundle(tipselection.GetRandomTip(), tipselection.GetRandomTip()) - for _, transaction := range generatedBundle.GetTransactions() { - tangle.StoreTransaction(transaction) - } - - var wg sync.WaitGroup - testResults := events.NewClosure(func(bundle *bundle.Bundle, transactions []*value_transaction.ValueTransaction) { - assert.Equal(t, bundle.GetHash(), generatedBundle.GetTransactions()[0].GetHash(), "invalid bundle hash") - assert.Equal(t, bundle.IsValueBundle(), false, "invalid value bundle status") - - wg.Done() - }) - Events.BundleSolid.Attach(testResults) - defer Events.BundleSolid.Detach(testResults) - - wg.Add(1) - if err := ProcessSolidBundleHead(generatedBundle.GetTransactions()[0]); err != nil { - t.Error(err) - } - - wg.Wait() - }) - - t.Run("value", func(t *testing.T) { - bundleFactory := client.NewBundleFactory() - bundleFactory.AddInput(seed.GetAddress(0), -400) - bundleFactory.AddOutput(seed.GetAddress(1), 400, "Testmessage") - bundleFactory.AddOutput(client.NewAddress("SJKUKQP9SWUSUCPRQXCMDVDVZ9SHHESHIQNCXWBJF9UJSWE9ZYFHQWAUPCXC9S9DSHP9NDF9RLNPMZVCM"), 400, "Testmessage") - - generatedBundle := bundleFactory.GenerateBundle(tipselection.GetRandomTip(), tipselection.GetRandomTip()) - for _, transaction := range generatedBundle.GetTransactions() { - tangle.StoreTransaction(transaction) - } - - var wg sync.WaitGroup - testResults := events.NewClosure(func(bundle *bundle.Bundle, transactions []*value_transaction.ValueTransaction) { - assert.Equal(t, bundle.GetHash(), generatedBundle.GetTransactions()[0].GetHash(), "invalid bundle hash") - assert.Equal(t, bundle.IsValueBundle(), true, "invalid value bundle status") - - wg.Done() - }) - - wg.Add(1) - Events.BundleSolid.Attach(testResults) - defer Events.BundleSolid.Detach(testResults) - - if err := ProcessSolidBundleHead(generatedBundle.GetTransactions()[0]); err != nil { - t.Error(err) - } - - wg.Wait() - }) -} diff --git a/plugins/bundleprocessor/errors.go b/plugins/bundleprocessor/errors.go deleted file mode 100644 index 7b488de18a26dca073df29488a5a00d0d54d9d21..0000000000000000000000000000000000000000 --- a/plugins/bundleprocessor/errors.go +++ /dev/null @@ -1,7 +0,0 @@ -package bundleprocessor - -import "errors" - -var ( - ErrProcessBundleFailed = errors.New("failed to process bundle") -) diff --git a/plugins/bundleprocessor/events.go b/plugins/bundleprocessor/events.go deleted file mode 100644 index 46eeaa5ca6ee676b4e28b692fad037d5cdf7be9d..0000000000000000000000000000000000000000 --- a/plugins/bundleprocessor/events.go +++ /dev/null @@ -1,27 +0,0 @@ -package bundleprocessor - -import ( - "github.com/iotaledger/goshimmer/packages/model/bundle" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/hive.go/events" -) - -var Events = pluginEvents{ - Error: events.NewEvent(errorCaller), - BundleSolid: events.NewEvent(bundleEventCaller), - InvalidBundle: events.NewEvent(bundleEventCaller), -} - -type pluginEvents struct { - Error *events.Event - BundleSolid *events.Event - InvalidBundle *events.Event -} - -func errorCaller(handler interface{}, params ...interface{}) { - handler.(func(error))(params[0].(error)) -} - -func bundleEventCaller(handler interface{}, params ...interface{}) { - handler.(func(*bundle.Bundle, []*value_transaction.ValueTransaction))(params[0].(*bundle.Bundle), params[1].([]*value_transaction.ValueTransaction)) -} diff --git a/plugins/bundleprocessor/plugin.go b/plugins/bundleprocessor/plugin.go deleted file mode 100644 index d8a6303dfe71ab83d96c0dcd6a151dfb113828ee..0000000000000000000000000000000000000000 --- a/plugins/bundleprocessor/plugin.go +++ /dev/null @@ -1,52 +0,0 @@ -package bundleprocessor - -import ( - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/packages/shutdown" - "github.com/iotaledger/goshimmer/plugins/tangle" - "github.com/iotaledger/hive.go/daemon" - "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/hive.go/logger" - "github.com/iotaledger/hive.go/node" -) - -var PLUGIN = node.NewPlugin("Bundle Processor", node.Enabled, configure, run) -var log *logger.Logger - -func configure(*node.Plugin) { - log = logger.NewLogger("Bundle Processor") - - tangle.Events.TransactionSolid.Attach(events.NewClosure(func(tx *value_transaction.ValueTransaction) { - if tx.IsHead() { - workerPool.Submit(tx) - } - })) - - Events.Error.Attach(events.NewClosure(func(err error) { - log.Error(err) - })) -} - -func run(*node.Plugin) { - log.Info("Starting Bundle Processor ...") - - daemon.BackgroundWorker("Bundle Processor", func(shutdownSignal <-chan struct{}) { - log.Info("Starting Bundle Processor ... done") - workerPool.Start() - <-shutdownSignal - log.Info("Stopping Bundle Processor ...") - workerPool.StopAndWait() - log.Info("Stopping Bundle Processor ... done") - }, shutdown.ShutdownPriorityBundleProcessor) - - log.Info("Starting Value Bundle Processor ...") - - daemon.BackgroundWorker("Value Bundle Processor", func(shutdownSignal <-chan struct{}) { - log.Info("Starting Value Bundle Processor ... done") - valueBundleProcessorWorkerPool.Start() - <-shutdownSignal - log.Info("Stopping Value Bundle Processor ...") - valueBundleProcessorWorkerPool.StopAndWait() - log.Info("Stopping Value Bundle Processor ... done") - }, shutdown.ShutdownPriorityBundleProcessor) -} diff --git a/plugins/bundleprocessor/valuebundleprocessor.go b/plugins/bundleprocessor/valuebundleprocessor.go deleted file mode 100644 index 984c2b244b354abfc26562859b69d82eae5810e2..0000000000000000000000000000000000000000 --- a/plugins/bundleprocessor/valuebundleprocessor.go +++ /dev/null @@ -1,80 +0,0 @@ -package bundleprocessor - -import ( - "github.com/iotaledger/goshimmer/packages/model/bundle" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/hive.go/workerpool" - "github.com/iotaledger/iota.go/curl" - "github.com/iotaledger/iota.go/signing" - "github.com/iotaledger/iota.go/trinary" -) - -var valueBundleProcessorWorkerPool = workerpool.New(func(task workerpool.Task) { - if err := ProcessSolidValueBundle(task.Param(0).(*bundle.Bundle), task.Param(1).([]*value_transaction.ValueTransaction)); err != nil { - Events.Error.Trigger(err) - } - - task.Return(nil) -}, workerpool.WorkerCount(WORKER_COUNT), workerpool.QueueSize(2*WORKER_COUNT)) - -func ProcessSolidValueBundle(bundle *bundle.Bundle, bundleTransactions []*value_transaction.ValueTransaction) error { - bundle.SetBundleEssenceHash(CalculateBundleHash(bundleTransactions)) - - Events.BundleSolid.Trigger(bundle, bundleTransactions) - - return nil -} - -func CalculateBundleHash(transactions []*value_transaction.ValueTransaction) trinary.Trytes { - var lastInputAddress trinary.Trytes - - var concatenatedBundleEssences = make(trinary.Trits, len(transactions)*value_transaction.BUNDLE_ESSENCE_SIZE) - for i, bundleTransaction := range transactions { - if bundleTransaction.GetValue() <= 0 { - lastInputAddress = bundleTransaction.GetAddress() - } - - copy(concatenatedBundleEssences[value_transaction.BUNDLE_ESSENCE_SIZE*i:value_transaction.BUNDLE_ESSENCE_SIZE*(i+1)], bundleTransaction.GetBundleEssence(lastInputAddress != bundleTransaction.GetAddress())) - } - - bundleHash, err := curl.HashTrits(concatenatedBundleEssences) - if err != nil { - panic(err) - } - return trinary.MustTritsToTrytes(bundleHash) -} - -func ValidateSignatures(bundleHash trinary.Hash, txs []*value_transaction.ValueTransaction) (bool, error) { - for i, tx := range txs { - // ignore all non-input transactions - if tx.GetValue() >= 0 { - continue - } - - address := tx.GetAddress() - - // it is unknown how many fragments there will be - fragments := []trinary.Trytes{tx.GetSignatureMessageFragment()} - - // each consecutive meta transaction with the same address contains another signature fragment - for j := i; j < len(txs)-1; j++ { - otherTx := txs[j+1] - if otherTx.GetValue() != 0 || otherTx.GetAddress() != address { - break - } - - fragments = append(fragments, otherTx.GetSignatureMessageFragment()) - } - - // validate all the fragments against the address using Kerl - valid, err := signing.ValidateSignatures(address, fragments, bundleHash) - if err != nil { - return false, err - } - if !valid { - return false, nil - } - } - - return true, nil -} diff --git a/plugins/gossip/gossip.go b/plugins/gossip/gossip.go index 0293370e71bd87a77386fa39ef0f005013b846c5..57f348d1ae6643ece99c63b4c6a219892ceddecb 100644 --- a/plugins/gossip/gossip.go +++ b/plugins/gossip/gossip.go @@ -6,17 +6,17 @@ import ( "strconv" "sync" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/plugins/tangle" + gp "github.com/iotaledger/goshimmer/packages/gossip" "github.com/iotaledger/goshimmer/packages/gossip/server" "github.com/iotaledger/goshimmer/packages/parameter" "github.com/iotaledger/goshimmer/plugins/autopeering/local" "github.com/iotaledger/goshimmer/plugins/cli" - "github.com/iotaledger/goshimmer/plugins/tangle" "github.com/iotaledger/hive.go/autopeering/peer" "github.com/iotaledger/hive.go/autopeering/peer/service" "github.com/iotaledger/hive.go/logger" - "github.com/iotaledger/hive.go/typeutils" - "github.com/iotaledger/iota.go/trinary" ) var ( @@ -105,24 +105,16 @@ func checkConnection(srv *server.TCP, self *peer.Peer) { wg.Wait() } -func getTransaction(hash []byte) ([]byte, error) { - tx, err := tangle.GetTransaction(typeutils.BytesToString(hash)) - log.Debugw("get tx from db", - "hash", hash, - "tx", tx, - "err", err, - ) - if err != nil { - return nil, fmt.Errorf("could not get transaction: %w", err) - } - if tx == nil { - return nil, fmt.Errorf("transaction not found: hash=%s", hash) +func getTransaction(transactionId transaction.Id) (bytes []byte, err error) { + log.Debugw("get tx from db", "id", transactionId.String()) + + if !tangle.Instance.GetTransaction(transactionId).Consume(func(transaction *transaction.Transaction) { + bytes = transaction.GetBytes() + }) { + err = fmt.Errorf("transaction not found: hash=%s", transactionId) } - return tx.GetBytes(), nil -} -func requestTransaction(hash trinary.Hash) { - mgr.RequestTransaction(typeutils.StringToBytes(hash)) + return } func GetAllNeighbors() []*gp.Neighbor { diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go index ff4b335fc80c9976533fef1dd6fc751805d435f8..66a27e2214ade99614d19a9200c7aa438ba62b03 100644 --- a/plugins/gossip/plugin.go +++ b/plugins/gossip/plugin.go @@ -1,8 +1,9 @@ package gossip import ( + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" "github.com/iotaledger/goshimmer/packages/gossip" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" "github.com/iotaledger/goshimmer/packages/shutdown" "github.com/iotaledger/goshimmer/plugins/tangle" "github.com/iotaledger/hive.go/autopeering/peer" @@ -69,9 +70,22 @@ func configureEvents() { log.Infof("Neighbor removed: %s / %s", gossip.GetAddress(p), p.ID()) })) - // gossip transactions on solidification - tangle.Events.TransactionSolid.Attach(events.NewClosure(func(tx *value_transaction.ValueTransaction) { - mgr.SendTransaction(tx.GetBytes()) + // configure flow of incoming transactions + gossip.Events.TransactionReceived.Attach(events.NewClosure(func(event *gossip.TransactionReceivedEvent) { + tangle.TransactionParser.Parse(event.Data) + })) + + // configure flow of outgoing transactions (gossip on solidification) + tangle.Instance.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, transactionMetadata *transactionmetadata.CachedTransactionMetadata) { + transactionMetadata.Release() + + cachedTransaction.Consume(func(transaction *transaction.Transaction) { + mgr.SendTransaction(transaction.GetBytes()) + }) + })) + + // request missing transactions + tangle.TransactionRequester.Events.SendRequest.Attach(events.NewClosure(func(transactionId transaction.Id) { + mgr.RequestTransaction(transactionId[:]) })) - tangle.SetRequester(tangle.RequesterFunc(requestTransaction)) } diff --git a/plugins/graph/plugin.go b/plugins/graph/plugin.go index af5861654331de80acf31a44c52676fc21f8d41d..566ba82af9795f0105946848844898bf53dfe8f0 100644 --- a/plugins/graph/plugin.go +++ b/plugins/graph/plugin.go @@ -8,7 +8,7 @@ import ( "github.com/iotaledger/goshimmer/packages/model/value_transaction" "github.com/iotaledger/goshimmer/packages/parameter" "github.com/iotaledger/goshimmer/packages/shutdown" - "github.com/iotaledger/goshimmer/plugins/tangle" + "github.com/iotaledger/goshimmer/plugins/tangle_old" "golang.org/x/net/context" engineio "github.com/googollee/go-engine.io" @@ -100,10 +100,10 @@ func run(*node.Plugin) { daemon.BackgroundWorker("Graph[NewTxWorker]", func(shutdownSignal <-chan struct{}) { log.Info("Starting Graph[NewTxWorker] ... done") - tangle.Events.TransactionStored.Attach(notifyNewTx) + tangle_old.Events.TransactionStored.Attach(notifyNewTx) newTxWorkerPool.Start() <-shutdownSignal - tangle.Events.TransactionStored.Detach(notifyNewTx) + tangle_old.Events.TransactionStored.Detach(notifyNewTx) newTxWorkerPool.Stop() log.Info("Stopping Graph[NewTxWorker] ... done") }, shutdown.ShutdownPriorityGraph) diff --git a/plugins/spa/explorer_routes.go b/plugins/spa/explorer_routes.go index 7d324e149a7f274b5669c7496fa1dc97f6920178..13d4510508677b0b431f968fc44ad8f3980cfc72 100644 --- a/plugins/spa/explorer_routes.go +++ b/plugins/spa/explorer_routes.go @@ -4,9 +4,11 @@ import ( "net/http" "sync" - "github.com/iotaledger/goshimmer/packages/model/transactionmetadata" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/plugins/tangle" + + "github.com/iotaledger/goshimmer/packages/model/transactionmetadata" + "github.com/iotaledger/goshimmer/plugins/tangle_old" "github.com/labstack/echo" "github.com/pkg/errors" @@ -16,26 +18,23 @@ import ( ) type ExplorerTx struct { - Hash Hash `json:"hash"` - SignatureMessageFragment Trytes `json:"signature_message_fragment"` - Address Hash `json:"address"` - Value int64 `json:"value"` - Timestamp uint `json:"timestamp"` - Trunk Hash `json:"trunk"` - Branch Hash `json:"branch"` - Solid bool `json:"solid"` - MWM int `json:"mwm"` + Hash transaction.Id `json:"hash"` + SignatureMessageFragment Trytes `json:"signature_message_fragment"` + Timestamp uint `json:"timestamp"` + Trunk transaction.Id `json:"trunk"` + Branch transaction.Id `json:"branch"` + Solid bool `json:"solid"` + MWM int `json:"mwm"` } -func createExplorerTx(hash Hash, tx *value_transaction.ValueTransaction) (*ExplorerTx, error) { - - txMetadata, err := tangle.GetTransactionMetadata(hash, transactionmetadata.New) +func createExplorerTx(tx *transaction.Transaction) (*ExplorerTx, error) { + txMetadata, err := tangle_old.GetTransactionMetadata(hash, transactionmetadata.New) if err != nil { return nil, err } t := &ExplorerTx{ - Hash: tx.GetHash(), + Hash: tx.GetId(), SignatureMessageFragment: tx.GetSignatureMessageFragment(), Address: tx.GetAddress(), Timestamp: tx.GetTimestamp(), @@ -121,20 +120,13 @@ func setupExplorerRoutes(routeGroup *echo.Group) { }) } -func findTransaction(hash Hash) (*ExplorerTx, error) { - if !guards.IsTrytesOfExactLength(hash, consts.HashTrytesSize) { - return nil, errors.Wrapf(ErrInvalidParameter, "hash invalid: %s", hash) - } - - tx, err := tangle.GetTransaction(hash) - if err != nil { - return nil, err - } - if tx == nil { - return nil, errors.Wrapf(ErrNotFound, "tx hash: %s", hash) +func findTransaction(transactionId transaction.Id) (*ExplorerTx, error) { + if !tangle.Instance.GetTransaction(transactionId).Consume(func(transaction *transaction.Transaction) { + t, err := createExplorerTx(transaction) + }) { + return nil, errors.Wrapf(ErrNotFound, "tx hash: %s", transactionId.String()) } - t, err := createExplorerTx(hash, tx) return t, err } @@ -146,7 +138,7 @@ func findAddress(hash Hash) (*ExplorerAdress, error) { return nil, errors.Wrapf(ErrInvalidParameter, "hash invalid: %s", hash) } - txHashes, err := tangle.ReadTransactionHashesForAddressFromDatabase(hash) + txHashes, err := tangle_old.ReadTransactionHashesForAddressFromDatabase(hash) if err != nil { return nil, ErrInternalError } @@ -159,7 +151,7 @@ func findAddress(hash Hash) (*ExplorerAdress, error) { for i := 0; i < len(txHashes); i++ { txHash := txHashes[i] - tx, err := tangle.GetTransaction(hash) + tx, err := tangle_old.GetTransaction(hash) if err != nil { continue } diff --git a/plugins/tangle/approvers.go b/plugins/tangle/approvers.go deleted file mode 100644 index 3e50c29caec97397832490d911ca3989ebe3be6b..0000000000000000000000000000000000000000 --- a/plugins/tangle/approvers.go +++ /dev/null @@ -1,128 +0,0 @@ -package tangle - -import ( - "fmt" - - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/goshimmer/packages/model/approvers" - "github.com/iotaledger/hive.go/lru_cache" - "github.com/iotaledger/hive.go/typeutils" - "github.com/iotaledger/iota.go/trinary" -) - -// region global public api //////////////////////////////////////////////////////////////////////////////////////////// - -// GetApprovers retrieves approvers from the database. -func GetApprovers(transactionHash trinary.Trytes, computeIfAbsent ...func(trinary.Trytes) *approvers.Approvers) (result *approvers.Approvers, err error) { - if cacheResult := approversCache.ComputeIfAbsent(transactionHash, func() interface{} { - if dbApprovers, dbErr := getApproversFromDatabase(transactionHash); dbErr != nil { - err = dbErr - - return nil - } else if dbApprovers != nil { - return dbApprovers - } else { - if len(computeIfAbsent) >= 1 { - return computeIfAbsent[0](transactionHash) - } - - return nil - } - }); cacheResult != nil && cacheResult.(*approvers.Approvers) != nil { - result = cacheResult.(*approvers.Approvers) - } - - return -} - -func ContainsApprovers(transactionHash trinary.Trytes) (result bool, err error) { - if approversCache.Contains(transactionHash) { - result = true - } else { - result, err = databaseContainsApprovers(transactionHash) - } - - return -} - -func StoreApprovers(approvers *approvers.Approvers) { - approversCache.Set(approvers.GetHash(), approvers) -} - -// region lru cache //////////////////////////////////////////////////////////////////////////////////////////////////// - -var approversCache = lru_cache.NewLRUCache(APPROVERS_CACHE_SIZE, &lru_cache.LRUCacheOptions{ - EvictionCallback: onEvictApprovers, - EvictionBatchSize: 100, -}) - -func onEvictApprovers(_ interface{}, values interface{}) { - // TODO: replace with apply - for _, obj := range values.([]interface{}) { - if approvers := obj.(*approvers.Approvers); approvers.GetModified() { - if err := storeApproversInDatabase(approvers); err != nil { - panic(err) - } - } - } -} - -func FlushApproversCache() { - approversCache.DeleteAll() -} - -const ( - APPROVERS_CACHE_SIZE = 50000 -) - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region database ///////////////////////////////////////////////////////////////////////////////////////////////////// - -var approversDatabase database.Database - -func configureApproversDatabase() { - if db, err := database.Get(database.DBPrefixApprovers, database.GetBadgerInstance()); err != nil { - panic(err) - } else { - approversDatabase = db - } -} - -func storeApproversInDatabase(approvers *approvers.Approvers) error { - if approvers.GetModified() { - if err := approversDatabase.Set(database.Entry{Key: typeutils.StringToBytes(approvers.GetHash()), Value: approvers.Marshal()}); err != nil { - return fmt.Errorf("%w: failed to store approvers: %s", ErrDatabaseError, err) - } - approvers.SetModified(false) - } - - return nil -} - -func getApproversFromDatabase(transactionHash trinary.Trytes) (*approvers.Approvers, error) { - approversData, err := approversDatabase.Get(typeutils.StringToBytes(transactionHash)) - if err != nil { - if err == database.ErrKeyNotFound { - return nil, nil - } - return nil, fmt.Errorf("%w: failed to retrieve approvers: %s", ErrDatabaseError, err) - } - - var result approvers.Approvers - if err = result.Unmarshal(approversData.Value); err != nil { - panic(err) - } - - return &result, nil -} - -func databaseContainsApprovers(transactionHash trinary.Trytes) (bool, error) { - if contains, err := approversDatabase.Contains(typeutils.StringToBytes(transactionHash)); err != nil { - return false, fmt.Errorf("%w: failed to check if the approvers exist: %s", ErrDatabaseError, err) - } else { - return contains, nil - } -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/tangle/bundle.go b/plugins/tangle/bundle.go deleted file mode 100644 index 2cb1fb896ae5cd5a8d6152a0e2398ef4651f4a87..0000000000000000000000000000000000000000 --- a/plugins/tangle/bundle.go +++ /dev/null @@ -1,133 +0,0 @@ -package tangle - -import ( - "fmt" - - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/goshimmer/packages/model/bundle" - "github.com/iotaledger/hive.go/lru_cache" - "github.com/iotaledger/hive.go/typeutils" - "github.com/iotaledger/iota.go/trinary" -) - -// region global public api //////////////////////////////////////////////////////////////////////////////////////////// - -// GetBundle retrieves bundle from the database. -func GetBundle(headerTransactionHash trinary.Trytes, computeIfAbsent ...func(trinary.Trytes) (*bundle.Bundle, error)) (result *bundle.Bundle, err error) { - if cacheResult := bundleCache.ComputeIfAbsent(headerTransactionHash, func() interface{} { - if dbBundle, dbErr := getBundleFromDatabase(headerTransactionHash); dbErr != nil { - err = dbErr - - return nil - } else if dbBundle != nil { - return dbBundle - } else { - if len(computeIfAbsent) >= 1 { - if computedBundle, computedErr := computeIfAbsent[0](headerTransactionHash); computedErr != nil { - err = computedErr - } else { - return computedBundle - } - } - - return nil - } - }); cacheResult != nil && cacheResult.(*bundle.Bundle) != nil { - result = cacheResult.(*bundle.Bundle) - } - - return -} - -func ContainsBundle(headerTransactionHash trinary.Trytes) (result bool, err error) { - if bundleCache.Contains(headerTransactionHash) { - result = true - } else { - result, err = databaseContainsBundle(headerTransactionHash) - } - - return -} - -func StoreBundle(bundle *bundle.Bundle) { - bundleCache.Set(bundle.GetHash(), bundle) -} - -// region lru cache //////////////////////////////////////////////////////////////////////////////////////////////////// - -var bundleCache = lru_cache.NewLRUCache(BUNDLE_CACHE_SIZE, &lru_cache.LRUCacheOptions{ - EvictionCallback: onEvictBundles, - EvictionBatchSize: 100, -}) - -func onEvictBundles(_ interface{}, values interface{}) { - // TODO: replace with apply - for _, obj := range values.([]interface{}) { - if bndl := obj.(*bundle.Bundle); bndl.GetModified() { - if err := storeBundleInDatabase(bndl); err != nil { - panic(err) - } - } - } -} - -func FlushBundleCache() { - bundleCache.DeleteAll() -} - -const ( - BUNDLE_CACHE_SIZE = 500 -) - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region database ///////////////////////////////////////////////////////////////////////////////////////////////////// - -var bundleDatabase database.Database - -func configureBundleDatabase() { - if db, err := database.Get(database.DBPrefixBundle, database.GetBadgerInstance()); err != nil { - panic(err) - } else { - bundleDatabase = db - } -} - -func storeBundleInDatabase(bundle *bundle.Bundle) error { - if bundle.GetModified() { - if err := bundleDatabase.Set(database.Entry{Key: typeutils.StringToBytes(bundle.GetHash()), Value: bundle.Marshal()}); err != nil { - return fmt.Errorf("%w: failed to store bundle: %s", ErrDatabaseError, err) - } - bundle.SetModified(false) - } - - return nil -} - -func getBundleFromDatabase(transactionHash trinary.Trytes) (*bundle.Bundle, error) { - bundleData, err := bundleDatabase.Get(typeutils.StringToBytes(transactionHash)) - if err != nil { - if err == database.ErrKeyNotFound { - return nil, nil - } - - return nil, fmt.Errorf("%w: failed to retrieve bundle: %s", ErrDatabaseError, err) - } - - var result bundle.Bundle - if err = result.Unmarshal(bundleData.Value); err != nil { - panic(err) - } - - return &result, nil -} - -func databaseContainsBundle(transactionHash trinary.Trytes) (bool, error) { - if contains, err := bundleDatabase.Contains(typeutils.StringToBytes(transactionHash)); err != nil { - return false, fmt.Errorf("%w: failed to check if the bundle exists: %s", ErrDatabaseError, err) - } else { - return contains, nil - } -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/tangle/errors.go b/plugins/tangle/errors.go deleted file mode 100644 index 5ca8797f9ff4f5d0c08e7a744988108b6605b1d7..0000000000000000000000000000000000000000 --- a/plugins/tangle/errors.go +++ /dev/null @@ -1,7 +0,0 @@ -package tangle - -import "errors" - -var ( - ErrDatabaseError = errors.New("database error") -) diff --git a/plugins/tangle/events.go b/plugins/tangle/events.go deleted file mode 100644 index 2a89c7248afbdb38762b0a2beb44fa27afb72f88..0000000000000000000000000000000000000000 --- a/plugins/tangle/events.go +++ /dev/null @@ -1,18 +0,0 @@ -package tangle - -import ( - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/hive.go/events" -) - -var Events = struct { - TransactionStored *events.Event - TransactionSolid *events.Event -}{ - TransactionStored: events.NewEvent(transactionCaller), - TransactionSolid: events.NewEvent(transactionCaller), -} - -func transactionCaller(handler interface{}, params ...interface{}) { - handler.(func(*value_transaction.ValueTransaction))(params[0].(*value_transaction.ValueTransaction)) -} diff --git a/plugins/tangle/misc.go b/plugins/tangle/misc.go deleted file mode 100644 index 490f52d74aa145b2498f2afa7b65da5ba2fc6f03..0000000000000000000000000000000000000000 --- a/plugins/tangle/misc.go +++ /dev/null @@ -1,16 +0,0 @@ -package tangle - -import ( - "github.com/iotaledger/hive.go/typeutils" - "github.com/iotaledger/iota.go/trinary" -) - -func databaseKeyForHashPrefixedHash(address trinary.Hash, transactionHash trinary.Hash) []byte { - //return append(databaseKeyForHashPrefix(address), trinary.MustTrytesToBytes(transactionHash)...) - return append(databaseKeyForHashPrefix(address), typeutils.StringToBytes(transactionHash)...) -} - -func databaseKeyForHashPrefix(hash trinary.Hash) []byte { - //return trinary.MustTrytesToBytes(hash) - return typeutils.StringToBytes(hash) -} diff --git a/plugins/tangle/plugin.go b/plugins/tangle/plugin.go deleted file mode 100644 index 6c6bc09015f462d137784c7c9c5fad2a26c59929..0000000000000000000000000000000000000000 --- a/plugins/tangle/plugin.go +++ /dev/null @@ -1,67 +0,0 @@ -package tangle - -import ( - "time" - - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/goshimmer/packages/shutdown" - "github.com/iotaledger/hive.go/daemon" - "github.com/iotaledger/hive.go/logger" - "github.com/iotaledger/hive.go/node" - "github.com/iotaledger/hive.go/timeutil" - "github.com/iotaledger/iota.go/trinary" -) - -// region plugin module setup ////////////////////////////////////////////////////////////////////////////////////////// - -var PLUGIN = node.NewPlugin("Tangle", node.Enabled, configure, run) -var log *logger.Logger - -func configure(*node.Plugin) { - log = logger.NewLogger("Tangle") - - configureTransactionDatabase() - configureTransactionMetaDataDatabase() - configureApproversDatabase() - configureBundleDatabase() - configureTransactionHashesForAddressDatabase() - configureSolidifier() - - daemon.BackgroundWorker("Cache Flush", func(shutdownSignal <-chan struct{}) { - <-shutdownSignal - - log.Info("Flushing caches to database...") - FlushTransactionCache() - FlushTransactionMetadata() - FlushApproversCache() - FlushBundleCache() - log.Info("Flushing caches to database... done") - - log.Info("Syncing database to disk...") - database.GetBadgerInstance().Close() - log.Info("Syncing database to disk... done") - }, shutdown.ShutdownPriorityTangle) - -} - -func run(*node.Plugin) { - - daemon.BackgroundWorker("Badger garbage collection", func(shutdownSignal <-chan struct{}) { - timeutil.Ticker(func() { - database.CleanupBadgerInstance(log) - }, 5*time.Minute, shutdownSignal) - }, shutdown.ShutdownPriorityBadgerGarbageCollection) - - runSolidifier() -} - -// Requester provides the functionality to request a transaction from the network. -type Requester interface { - RequestTransaction(hash trinary.Hash) -} - -type RequesterFunc func(hash trinary.Hash) - -func (f RequesterFunc) RequestTransaction(hash trinary.Hash) { f(hash) } - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/tangle/solidifier.go b/plugins/tangle/solidifier.go deleted file mode 100644 index 02d84440969ce18efcef093e23ea8e3c6e897d92..0000000000000000000000000000000000000000 --- a/plugins/tangle/solidifier.go +++ /dev/null @@ -1,265 +0,0 @@ -package tangle - -import ( - "runtime" - "time" - - "github.com/iotaledger/goshimmer/packages/gossip" - "github.com/iotaledger/goshimmer/packages/model/approvers" - "github.com/iotaledger/goshimmer/packages/model/meta_transaction" - "github.com/iotaledger/goshimmer/packages/model/transactionmetadata" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/packages/shutdown" - "github.com/iotaledger/hive.go/daemon" - "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/hive.go/workerpool" - "github.com/iotaledger/iota.go/trinary" -) - -// region plugin module setup ////////////////////////////////////////////////////////////////////////////////////////// - -const UnsolidInterval = time.Minute - -var ( - workerCount = runtime.NumCPU() - workerPool *workerpool.WorkerPool - requestedTxs *UnsolidTxs - - requester Requester -) - -func SetRequester(req Requester) { - requester = req -} - -func configureSolidifier() { - workerPool = workerpool.New(func(task workerpool.Task) { - processMetaTransaction(task.Param(0).(*meta_transaction.MetaTransaction)) - - task.Return(nil) - }, workerpool.WorkerCount(workerCount), workerpool.QueueSize(10000)) - - requestedTxs = NewUnsolidTxs() - - gossip.Events.TransactionReceived.Attach(events.NewClosure(func(ev *gossip.TransactionReceivedEvent) { - metaTx := meta_transaction.FromBytes(ev.Data) - if err := metaTx.Validate(); err != nil { - log.Warnf("invalid transaction: %s", err) - return - } - workerPool.Submit(metaTx) - })) -} - -func runSolidifier() { - daemon.BackgroundWorker("Tangle Solidifier", func(shutdownSignal <-chan struct{}) { - log.Info("Starting Solidifier ...") - workerPool.Start() - log.Info("Starting Solidifier ... done") - - <-shutdownSignal - - log.Info("Stopping Solidifier ...") - workerPool.StopAndWait() - log.Info("Stopping Solidifier ... done") - }, shutdown.ShutdownPrioritySolidifier) - -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -func processMetaTransaction(metaTransaction *meta_transaction.MetaTransaction) { - metaTransactionHash := metaTransaction.GetHash() - - var newTransaction bool - tx, err := GetTransaction(metaTransactionHash, func(transactionHash trinary.Trytes) *value_transaction.ValueTransaction { - newTransaction = true - - tx := value_transaction.FromMetaTransaction(metaTransaction) - tx.SetModified(true) - return tx - }) - if err != nil { - log.Errorf("Unable to process transaction %s: %s", metaTransactionHash, err.Error()) - return - } - if newTransaction { - log.Debugw("process new transaction", "hash", tx.GetHash()) - processNewTransaction(tx) - requestedTxs.Remove(tx.GetHash()) - updateRequestedTxs() - } -} - -func processNewTransaction(transaction *value_transaction.ValueTransaction) { - Events.TransactionStored.Trigger(transaction) - - // store transaction hash for address in DB - if err := StoreTransactionHashForAddressInDatabase( - &TxHashForAddress{ - Address: transaction.GetAddress(), - TxHash: transaction.GetHash(), - }, - ); err != nil { - log.Errorw(err.Error()) - } - - transactionHash := transaction.GetHash() - - // register tx as approver for trunk - if trunkApprovers, err := GetApprovers(transaction.GetTrunkTransactionHash(), approvers.New); err != nil { - log.Errorf("Unable to get approvers of transaction %s: %s", transaction.GetTrunkTransactionHash(), err.Error()) - return - } else { - trunkApprovers.Add(transactionHash) - } - - // register tx as approver for branch - if branchApprovers, err := GetApprovers(transaction.GetBranchTransactionHash(), approvers.New); err != nil { - log.Errorf("Unable to get approvers of transaction %s: %s", transaction.GetBranchTransactionHash(), err.Error()) - return - } else { - branchApprovers.Add(transactionHash) - } - - isSolid, err := isSolid(transactionHash) - if err != nil { - log.Errorf("Unable to check solidity: %s", err.Error()) - } - // if the transaction was solidified propagate this information - if isSolid { - if err := propagateSolidity(transaction.GetHash()); err != nil { - log.Errorf("Unable to propagate solidity: %s", err.Error()) - } - } -} - -// isSolid checks whether the transaction with the given hash is solid. A transaction is solid, if it is -// either marked as solid or all its referenced transactions are in the database. -func isSolid(hash trinary.Hash) (bool, error) { - // the genesis is always solid - if hash == meta_transaction.BRANCH_NULL_HASH { - return true, nil - } - // if the transaction is not in the DB, request it - transaction, err := GetTransaction(hash) - if err != nil { - return false, err - } - if transaction == nil { - if requestedTxs.Add(hash) { - requestTransaction(hash) - } - return false, nil - } - - // check whether the transaction is marked solid - metadata, err := GetTransactionMetadata(hash, transactionmetadata.New) - if err != nil { - return false, err - } - if metadata.GetSolid() { - return true, nil - } - - branch := contains(transaction.GetBranchTransactionHash()) - trunk := contains(transaction.GetTrunkTransactionHash()) - - if !branch || !trunk { - return false, nil - } - // everything is good, mark the transaction as solid - return true, markSolid(transaction) -} - -func contains(hash trinary.Hash) bool { - if hash == meta_transaction.BRANCH_NULL_HASH { - return true - } - if contains, _ := ContainsTransaction(hash); !contains { - if requestedTxs.Add(hash) { - requestTransaction(hash) - } - return false - } - return true -} - -func isMarkedSolid(hash trinary.Hash) (bool, error) { - if hash == meta_transaction.BRANCH_NULL_HASH { - return true, nil - } - metadata, err := GetTransactionMetadata(hash, transactionmetadata.New) - if err != nil { - return false, err - } - return metadata.GetSolid(), nil -} - -func markSolid(transaction *value_transaction.ValueTransaction) error { - txMetadata, err := GetTransactionMetadata(transaction.GetHash(), transactionmetadata.New) - if err != nil { - return err - } - if txMetadata.SetSolid(true) { - log.Debugw("transaction solidified", "hash", transaction.GetHash()) - Events.TransactionSolid.Trigger(transaction) - return propagateSolidity(transaction.GetHash()) - } - return nil -} - -func propagateSolidity(transactionHash trinary.Trytes) error { - approvingTransactions, err := GetApprovers(transactionHash, approvers.New) - if err != nil { - return err - } - for _, hash := range approvingTransactions.GetHashes() { - approver, err := GetTransaction(hash) - if err != nil { - return err - } - if approver != nil { - branchSolid, err := isMarkedSolid(approver.GetBranchTransactionHash()) - if err != nil { - return err - } - if !branchSolid { - continue - } - trunkSolid, err := isMarkedSolid(approver.GetTrunkTransactionHash()) - if err != nil { - return err - } - if !trunkSolid { - continue - } - - if err := markSolid(approver); err != nil { - return err - } - } - } - return nil -} - -func updateRequestedTxs() { - targetTime := time.Now().Add(-UnsolidInterval) - txs := requestedTxs.Update(targetTime) - for _, txHash := range txs { - if contains, _ := ContainsTransaction(txHash); contains { - requestedTxs.Remove(txHash) - continue - } - requestTransaction(txHash) - } -} - -func requestTransaction(hash trinary.Trytes) { - if requester == nil { - return - } - - log.Debugw("Requesting tx", "hash", hash) - requester.RequestTransaction(hash) -} diff --git a/plugins/tangle/solidifier_test.go b/plugins/tangle/solidifier_test.go deleted file mode 100644 index 28a63bc25a1fdcd79f16fb2f82d2b66380088ae5..0000000000000000000000000000000000000000 --- a/plugins/tangle/solidifier_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package tangle - -import ( - "io/ioutil" - stdlog "log" - "os" - "sync/atomic" - "testing" - "time" - - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/goshimmer/packages/gossip" - "github.com/iotaledger/goshimmer/packages/model/meta_transaction" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/packages/parameter" - "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/hive.go/logger" - "github.com/iotaledger/hive.go/node" - "github.com/iotaledger/iota.go/trinary" - "github.com/stretchr/testify/require" -) - -// use much lower min weight magnitude for the tests -const testMWM = 8 - -func init() { - if err := parameter.LoadDefaultConfig(false); err != nil { - stdlog.Fatalf("Failed to initialize config: %s", err) - } - if err := logger.InitGlobalLogger(parameter.NodeConfig); err != nil { - stdlog.Fatalf("Failed to initialize config: %s", err) - } -} - -func TestTangle(t *testing.T) { - dir, err := ioutil.TempDir("", t.Name()) - require.NoError(t, err) - defer os.Remove(dir) - // use the tempdir for the database - parameter.NodeConfig.Set(database.CFG_DIRECTORY, dir) - - // start a test node - node.Start(node.Plugins(PLUGIN)) - defer node.Shutdown() - - t.Run("ReadTransactionHashesForAddressFromDatabase", func(t *testing.T) { - tx1 := value_transaction.New() - tx1.SetAddress("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") - tx1.SetTimestamp(uint(time.Now().UnixNano())) - require.NoError(t, tx1.DoProofOfWork(testMWM)) - - tx2 := value_transaction.New() - tx2.SetTimestamp(uint(time.Now().UnixNano())) - require.NoError(t, tx2.DoProofOfWork(testMWM)) - - transactionReceived(&gossip.TransactionReceivedEvent{Data: tx1.GetBytes()}) - - txAddr, err := ReadTransactionHashesForAddressFromDatabase(tx1.GetAddress()) - require.NoError(t, err) - require.ElementsMatch(t, []trinary.Hash{tx1.GetHash()}, txAddr) - }) - - t.Run("ProofOfWork", func(t *testing.T) { - tx1 := value_transaction.New() - tx1.SetTimestamp(uint(time.Now().UnixNano())) - require.NoError(t, tx1.DoProofOfWork(1)) - - tx2 := value_transaction.New() - tx2.SetTimestamp(uint(time.Now().UnixNano())) - require.NoError(t, tx2.DoProofOfWork(testMWM)) - - var counter int32 - closure := events.NewClosure(func(transaction *value_transaction.ValueTransaction) { - atomic.AddInt32(&counter, 1) - }) - Events.TransactionSolid.Attach(closure) - defer Events.TransactionSolid.Detach(closure) - - transactionReceived(&gossip.TransactionReceivedEvent{Data: tx1.GetBytes()}) - transactionReceived(&gossip.TransactionReceivedEvent{Data: tx2.GetBytes()}) - - time.Sleep(100 * time.Millisecond) - require.EqualValues(t, 1, counter) - }) - - t.Run("Solidifier", func(t *testing.T) { - transaction1 := value_transaction.New() - transaction1.SetTimestamp(uint(time.Now().UnixNano())) - require.NoError(t, transaction1.DoProofOfWork(testMWM)) - - transaction2 := value_transaction.New() - transaction2.SetTimestamp(uint(time.Now().UnixNano())) - transaction2.SetBranchTransactionHash(transaction1.GetHash()) - require.NoError(t, transaction2.DoProofOfWork(testMWM)) - - transaction3 := value_transaction.New() - transaction3.SetTimestamp(uint(time.Now().UnixNano())) - transaction3.SetBranchTransactionHash(transaction2.GetHash()) - require.NoError(t, transaction3.DoProofOfWork(testMWM)) - - transaction4 := value_transaction.New() - transaction4.SetTimestamp(uint(time.Now().UnixNano())) - transaction4.SetBranchTransactionHash(transaction3.GetHash()) - require.NoError(t, transaction4.DoProofOfWork(testMWM)) - - var counter int32 - closure := events.NewClosure(func(tx *value_transaction.ValueTransaction) { - atomic.AddInt32(&counter, 1) - log.Infof("Transaction solid: hash=%s", tx.GetHash()) - }) - Events.TransactionSolid.Attach(closure) - defer Events.TransactionSolid.Detach(closure) - - // only transaction3 should be requested - SetRequester(RequesterFunc(func(hash trinary.Hash) { - if transaction3.GetHash() == hash { - // return the transaction data - transactionReceived(&gossip.TransactionReceivedEvent{Data: transaction3.GetBytes()}) - } - })) - - transactionReceived(&gossip.TransactionReceivedEvent{Data: transaction1.GetBytes()}) - transactionReceived(&gossip.TransactionReceivedEvent{Data: transaction2.GetBytes()}) - // transactionReceived(&gossip.TransactionReceivedEvent{Data: transaction3.GetBytes()}) - transactionReceived(&gossip.TransactionReceivedEvent{Data: transaction4.GetBytes()}) - - time.Sleep(100 * time.Millisecond) - require.EqualValues(t, 4, counter) - }) -} - -// transactionReceived mocks the TransactionReceived event by allowing lower mwm -func transactionReceived(ev *gossip.TransactionReceivedEvent) { - metaTx := meta_transaction.FromBytes(ev.Data) - if metaTx.GetWeightMagnitude() < testMWM { - log.Warnf("invalid weight magnitude: %d / %d", metaTx.GetWeightMagnitude(), testMWM) - return - } - processMetaTransaction(metaTx) -} diff --git a/plugins/tangle/tangle.go b/plugins/tangle/tangle.go new file mode 100644 index 0000000000000000000000000000000000000000..6862e9aa484d0a421c9d98c2c82f818861e08f6d --- /dev/null +++ b/plugins/tangle/tangle.go @@ -0,0 +1,71 @@ +package tangle + +import ( + "github.com/iotaledger/goshimmer/packages/binary/storageprefix" + "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" + "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" + "github.com/iotaledger/goshimmer/packages/binary/tangle/transactionrequester" + "github.com/iotaledger/goshimmer/packages/shutdown" + "github.com/iotaledger/hive.go/daemon" + "github.com/iotaledger/hive.go/events" + + "github.com/iotaledger/goshimmer/packages/binary/tangle" + + "github.com/iotaledger/hive.go/logger" + "github.com/iotaledger/hive.go/node" +) + +var PLUGIN = node.NewPlugin("Tangle", node.Enabled, configure, run) + +var TransactionParser *transactionparser.TransactionParser + +var TransactionRequester *transactionrequester.TransactionRequester + +var TipSelector *tipselector.TipSelector + +var Instance *tangle.Tangle + +var log *logger.Logger + +func configure(*node.Plugin) { + log = logger.NewLogger("Tangle") + + // create instances + TransactionParser = transactionparser.New() + TransactionRequester = transactionrequester.New() + TipSelector = tipselector.New() + Instance = tangle.New(storageprefix.Mainnet) + + // setup TransactionParser + TransactionParser.Events.TransactionParsed.Attach(events.NewClosure(func(transaction *transaction.Transaction) { + Instance.AttachTransaction(transaction) + })) + + // setup TransactionRequester + Instance.Events.TransactionMissing.Attach(events.NewClosure(TransactionRequester.ScheduleRequest)) + Instance.Events.MissingTransactionReceived.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { + cachedTransactionMetadata.Release() + + cachedTransaction.Consume(func(transaction *transaction.Transaction) { + TransactionRequester.StopRequest(transaction.GetId()) + }) + })) + + // setup TipSelector + Instance.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) { + cachedTransactionMetadata.Release() + + cachedTransaction.Consume(TipSelector.AddTip) + })) +} + +func run(*node.Plugin) { + daemon.BackgroundWorker("Tangle", func(shutdownSignal <-chan struct{}) { + <-shutdownSignal + + TransactionParser.Shutdown() + Instance.Shutdown() + }, shutdown.ShutdownPriorityTangle) +} diff --git a/plugins/tangle/transaction.go b/plugins/tangle/transaction.go deleted file mode 100644 index bff7b6b726d8bda3b4f3fdc4278f0a3bbe80a254..0000000000000000000000000000000000000000 --- a/plugins/tangle/transaction.go +++ /dev/null @@ -1,124 +0,0 @@ -package tangle - -import ( - "fmt" - - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/hive.go/lru_cache" - "github.com/iotaledger/hive.go/typeutils" - "github.com/iotaledger/iota.go/trinary" -) - -// region public api /////////////////////////////////////////////////////////////////////////////////////////////////// - -func GetTransaction(transactionHash trinary.Trytes, computeIfAbsent ...func(trinary.Trytes) *value_transaction.ValueTransaction) (result *value_transaction.ValueTransaction, err error) { - if cacheResult := transactionCache.ComputeIfAbsent(transactionHash, func() interface{} { - if transaction, dbErr := getTransactionFromDatabase(transactionHash); dbErr != nil { - err = dbErr - - return nil - } else if transaction != nil { - return transaction - } else { - if len(computeIfAbsent) >= 1 { - return computeIfAbsent[0](transactionHash) - } - - return nil - } - }); !typeutils.IsInterfaceNil(cacheResult) { - result = cacheResult.(*value_transaction.ValueTransaction) - } - - return -} - -func ContainsTransaction(transactionHash trinary.Trytes) (result bool, err error) { - if transactionCache.Contains(transactionHash) { - result = true - } else { - result, err = databaseContainsTransaction(transactionHash) - } - - return -} - -func StoreTransaction(transaction *value_transaction.ValueTransaction) { - transactionCache.Set(transaction.GetHash(), transaction) -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region lru cache //////////////////////////////////////////////////////////////////////////////////////////////////// - -var transactionCache = lru_cache.NewLRUCache(TRANSACTION_CACHE_SIZE, &lru_cache.LRUCacheOptions{ - EvictionCallback: onEvictTransactions, - EvictionBatchSize: 200, -}) - -func onEvictTransactions(_ interface{}, values interface{}) { - // TODO: replace with apply - for _, obj := range values.([]interface{}) { - if tx := obj.(*value_transaction.ValueTransaction); tx.GetModified() { - if err := storeTransactionInDatabase(tx); err != nil { - panic(err) - } - } - } -} - -func FlushTransactionCache() { - transactionCache.DeleteAll() -} - -const ( - TRANSACTION_CACHE_SIZE = 500 -) - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region database ///////////////////////////////////////////////////////////////////////////////////////////////////// - -var transactionDatabase database.Database - -func configureTransactionDatabase() { - if db, err := database.Get(database.DBPrefixTransaction, database.GetBadgerInstance()); err != nil { - panic(err) - } else { - transactionDatabase = db - } -} - -func storeTransactionInDatabase(transaction *value_transaction.ValueTransaction) error { - if transaction.GetModified() { - if err := transactionDatabase.Set(database.Entry{Key: typeutils.StringToBytes(transaction.GetHash()), Value: transaction.MetaTransaction.GetBytes()}); err != nil { - return fmt.Errorf("%w: failed to store transaction: %s", ErrDatabaseError, err.Error()) - } - transaction.SetModified(false) - } - - return nil -} - -func getTransactionFromDatabase(transactionHash trinary.Trytes) (*value_transaction.ValueTransaction, error) { - txData, err := transactionDatabase.Get(typeutils.StringToBytes(transactionHash)) - if err != nil { - if err == database.ErrKeyNotFound { - return nil, nil - } - return nil, fmt.Errorf("%w: failed to retrieve transaction: %s", ErrDatabaseError, err) - } - - return value_transaction.FromBytes(txData.Value), nil -} - -func databaseContainsTransaction(transactionHash trinary.Trytes) (bool, error) { - if contains, err := transactionDatabase.Contains(typeutils.StringToBytes(transactionHash)); err != nil { - return contains, fmt.Errorf("%w: failed to check if the transaction exists: %s", ErrDatabaseError, err) - } else { - return contains, nil - } -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/tangle/transaction_metadata.go b/plugins/tangle/transaction_metadata.go deleted file mode 100644 index 152f0126da1f00dd741d2c9953743a8010e9f764..0000000000000000000000000000000000000000 --- a/plugins/tangle/transaction_metadata.go +++ /dev/null @@ -1,134 +0,0 @@ -package tangle - -import ( - "fmt" - - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/goshimmer/packages/model/transactionmetadata" - "github.com/iotaledger/hive.go/lru_cache" - "github.com/iotaledger/hive.go/typeutils" - "github.com/iotaledger/iota.go/trinary" -) - -// region public api /////////////////////////////////////////////////////////////////////////////////////////////////// - -func GetTransactionMetadata(transactionHash trinary.Trytes, computeIfAbsent ...func(trinary.Trytes) *transactionmetadata.TransactionMetadata) (result *transactionmetadata.TransactionMetadata, err error) { - if cacheResult := transactionMetadataCache.ComputeIfAbsent(transactionHash, func() interface{} { - if transactionMetadata, dbErr := getTransactionMetadataFromDatabase(transactionHash); dbErr != nil { - err = dbErr - - return nil - } else if transactionMetadata != nil { - return transactionMetadata - } else { - if len(computeIfAbsent) >= 1 { - return computeIfAbsent[0](transactionHash) - } - - return nil - } - }); !typeutils.IsInterfaceNil(cacheResult) { - result = cacheResult.(*transactionmetadata.TransactionMetadata) - } - - return -} - -func ContainsTransactionMetadata(transactionHash trinary.Trytes) (result bool, err error) { - if transactionMetadataCache.Contains(transactionHash) { - result = true - } else { - result, err = databaseContainsTransactionMetadata(transactionHash) - } - - return -} - -func StoreTransactionMetadata(transactionMetadata *transactionmetadata.TransactionMetadata) { - transactionMetadataCache.Set(transactionMetadata.GetHash(), transactionMetadata) -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region lru cache //////////////////////////////////////////////////////////////////////////////////////////////////// - -var transactionMetadataCache = lru_cache.NewLRUCache(TRANSACTION_METADATA_CACHE_SIZE, &lru_cache.LRUCacheOptions{ - EvictionCallback: onEvictTransactionMetadatas, - EvictionBatchSize: 200, -}) - -func onEvictTransactionMetadatas(_ interface{}, values interface{}) { - // TODO: replace with apply - for _, obj := range values.([]interface{}) { - if txMetadata := obj.(*transactionmetadata.TransactionMetadata); txMetadata.GetModified() { - if err := storeTransactionMetadataInDatabase(txMetadata); err != nil { - panic(err) - } - } - } -} - -func FlushTransactionMetadata() { - transactionCache.DeleteAll() -} - -const ( - TRANSACTION_METADATA_CACHE_SIZE = 500 -) - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region database ///////////////////////////////////////////////////////////////////////////////////////////////////// - -var transactionMetadataDatabase database.Database - -func configureTransactionMetaDataDatabase() { - if db, err := database.Get(database.DBPrefixTransactionMetadata, database.GetBadgerInstance()); err != nil { - panic(err) - } else { - transactionMetadataDatabase = db - } -} - -func storeTransactionMetadataInDatabase(metadata *transactionmetadata.TransactionMetadata) error { - if metadata.GetModified() { - if marshaledMetadata, err := metadata.Marshal(); err != nil { - return err - } else { - if err := transactionMetadataDatabase.Set(database.Entry{Key: typeutils.StringToBytes(metadata.GetHash()), Value: marshaledMetadata}); err != nil { - return fmt.Errorf("%w: failed to store transaction metadata: %s", ErrDatabaseError, err) - } - - metadata.SetModified(false) - } - } - - return nil -} - -func getTransactionMetadataFromDatabase(transactionHash trinary.Trytes) (*transactionmetadata.TransactionMetadata, error) { - txMetadata, err := transactionMetadataDatabase.Get(typeutils.StringToBytes(transactionHash)) - if err != nil { - if err == database.ErrKeyNotFound { - return nil, nil - } - return nil, fmt.Errorf("%w: failed to retrieve transaction: %s", ErrDatabaseError, err) - } - - var result transactionmetadata.TransactionMetadata - if err := result.Unmarshal(txMetadata.Value); err != nil { - panic(err) - } - - return &result, nil -} - -func databaseContainsTransactionMetadata(transactionHash trinary.Trytes) (bool, error) { - if contains, err := transactionMetadataDatabase.Contains(typeutils.StringToBytes(transactionHash)); err != nil { - return contains, fmt.Errorf("%w: failed to check if the transaction metadata exists: %s", ErrDatabaseError, err) - } else { - return contains, nil - } -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/tangle/tx_per_address.go b/plugins/tangle/tx_per_address.go deleted file mode 100644 index 092a75248419251137c6205be0abf108b9b495df..0000000000000000000000000000000000000000 --- a/plugins/tangle/tx_per_address.go +++ /dev/null @@ -1,59 +0,0 @@ -package tangle - -import ( - "fmt" - - "github.com/iotaledger/goshimmer/packages/database" - "github.com/iotaledger/hive.go/typeutils" - "github.com/iotaledger/iota.go/trinary" -) - -var ( - transactionsHashesForAddressDatabase database.Database -) - -func configureTransactionHashesForAddressDatabase() { - if db, err := database.Get(database.DBPrefixAddressTransactions, database.GetBadgerInstance()); err != nil { - panic(err) - } else { - transactionsHashesForAddressDatabase = db - } -} - -type TxHashForAddress struct { - Address trinary.Hash - TxHash trinary.Hash -} - -func StoreTransactionHashForAddressInDatabase(address *TxHashForAddress) error { - if err := transactionsHashesForAddressDatabase.Set(database.Entry{ - Key: databaseKeyForHashPrefixedHash(address.Address, address.TxHash), - Value: []byte{}, - }); err != nil { - return fmt.Errorf("%w: failed to store tx for address in database: %s", ErrDatabaseError, err) - } - return nil -} - -func DeleteTransactionHashForAddressInDatabase(address *TxHashForAddress) error { - if err := transactionsHashesForAddressDatabase.Delete( - databaseKeyForHashPrefixedHash(address.Address, address.TxHash), - ); err != nil { - return fmt.Errorf("%w: failed to delete tx for address: %s", ErrDatabaseError, err) - } - - return nil -} - -func ReadTransactionHashesForAddressFromDatabase(address trinary.Hash) ([]trinary.Hash, error) { - var transactionHashes []trinary.Hash - err := transactionsHashesForAddressDatabase.StreamForEachPrefixKeyOnly(databaseKeyForHashPrefix(address), func(key database.KeyOnlyEntry) error { - transactionHashes = append(transactionHashes, typeutils.BytesToString(key.Key)) - return nil - }) - - if err != nil { - return nil, fmt.Errorf("%w: failed to read tx per address from database: %s", ErrDatabaseError, err) - } - return transactionHashes, nil -} diff --git a/plugins/tangle/unsolidTxs.go b/plugins/tangle/unsolidTxs.go deleted file mode 100644 index 36924fa75ff8ce1a757fc1f96695822ae03e6969..0000000000000000000000000000000000000000 --- a/plugins/tangle/unsolidTxs.go +++ /dev/null @@ -1,59 +0,0 @@ -package tangle - -import ( - "sync" - "time" -) - -type UnsolidTxs struct { - internal map[string]Info - sync.RWMutex -} - -type Info struct { - lastRequest time.Time - counter int -} - -func NewUnsolidTxs() *UnsolidTxs { - return &UnsolidTxs{ - internal: make(map[string]Info), - } -} - -func (u *UnsolidTxs) Add(hash string) bool { - u.Lock() - defer u.Unlock() - _, contains := u.internal[hash] - if contains { - return false - } - info := Info{ - lastRequest: time.Now(), - counter: 1, - } - u.internal[hash] = info - return true -} - -func (u *UnsolidTxs) Remove(hash string) { - u.Lock() - delete(u.internal, hash) - u.Unlock() -} - -func (u *UnsolidTxs) Update(targetTime time.Time) (result []string) { - u.Lock() - for k, v := range u.internal { - if v.lastRequest.Before(targetTime) { - result = append(result, k) - - v.lastRequest = time.Now() - v.counter++ - - u.internal[k] = v - } - } - u.Unlock() - return result -} diff --git a/plugins/tipselection/plugin.go b/plugins/tipselection/plugin.go deleted file mode 100644 index 7587075e303638b84e24fe51494eeff6e257ac8f..0000000000000000000000000000000000000000 --- a/plugins/tipselection/plugin.go +++ /dev/null @@ -1,27 +0,0 @@ -package tipselection - -import ( - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/plugins/tangle" - "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/hive.go/node" - "github.com/iotaledger/iota.go/trinary" -) - -var PLUGIN = node.NewPlugin("Tipselection", node.Enabled, configure, run) - -func configure(*node.Plugin) { - tipSet = make(map[trinary.Hash]struct{}) - - tangle.Events.TransactionSolid.Attach(events.NewClosure(func(transaction *value_transaction.ValueTransaction) { - mutex.Lock() - defer mutex.Unlock() - - delete(tipSet, transaction.GetBranchTransactionHash()) - delete(tipSet, transaction.GetTrunkTransactionHash()) - tipSet[transaction.GetHash()] = struct{}{} - })) -} - -func run(*node.Plugin) { -} diff --git a/plugins/tipselection/tipselection.go b/plugins/tipselection/tipselection.go deleted file mode 100644 index 95cb4bc1b523637286be4eabb9692458bc07627f..0000000000000000000000000000000000000000 --- a/plugins/tipselection/tipselection.go +++ /dev/null @@ -1,54 +0,0 @@ -package tipselection - -import ( - "math/rand" - "sync" - - "github.com/iotaledger/goshimmer/packages/model/meta_transaction" - "github.com/iotaledger/iota.go/trinary" -) - -var ( - tipSet map[trinary.Hash]struct{} - mutex sync.RWMutex -) - -func GetRandomTip(excluding ...trinary.Hash) trinary.Trytes { - mutex.RLock() - defer mutex.RUnlock() - - numTips := len(tipSet) - if numTips == 0 { - return meta_transaction.BRANCH_NULL_HASH - } - - var ignore trinary.Hash - if len(excluding) > 0 { - ignore = excluding[0] - } - if _, contains := tipSet[ignore]; contains { - if numTips == 1 { - return ignore - } - numTips -= 1 - } - - i := rand.Intn(numTips) - for k := range tipSet { - if k == ignore { - continue - } - if i == 0 { - return k - } - i-- - } - panic("unreachable") -} - -func GetTipsCount() int { - mutex.RLock() - defer mutex.RUnlock() - - return len(tipSet) -} diff --git a/plugins/tipselection/tipselection_test.go b/plugins/tipselection/tipselection_test.go deleted file mode 100644 index cb18e47815cde237bcfdedd9dac431d4156af5fb..0000000000000000000000000000000000000000 --- a/plugins/tipselection/tipselection_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package tipselection - -import ( - "log" - "testing" - - "github.com/iotaledger/goshimmer/packages/model/meta_transaction" - "github.com/iotaledger/goshimmer/packages/model/value_transaction" - "github.com/iotaledger/goshimmer/plugins/tangle" - "github.com/iotaledger/hive.go/logger" - "github.com/spf13/viper" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func init() { - if err := logger.InitGlobalLogger(viper.New()); err != nil { - log.Fatal(err) - } -} - -func TestEmptyTipSet(t *testing.T) { - configure(nil) - assert.Equal(t, 0, GetTipsCount()) - assert.Equal(t, meta_transaction.BRANCH_NULL_HASH, GetRandomTip()) -} - -func TestSingleTip(t *testing.T) { - configure(nil) - - tx := value_transaction.New() - tx.SetValue(int64(1)) - tx.SetBranchTransactionHash(meta_transaction.BRANCH_NULL_HASH) - tx.SetTrunkTransactionHash(meta_transaction.BRANCH_NULL_HASH) - - tangle.Events.TransactionSolid.Trigger(tx) - - assert.Equal(t, 1, GetTipsCount()) - - tip1 := GetRandomTip() - assert.NotNil(t, tip1) - tip2 := GetRandomTip(tip1) - assert.NotNil(t, tip2) - assert.Equal(t, tip1, tip2) -} - -func TestGetRandomTip(t *testing.T) { - configure(nil) - - tx := value_transaction.New() - tx.SetValue(int64(1)) - tx.SetBranchTransactionHash(meta_transaction.BRANCH_NULL_HASH) - tx.SetTrunkTransactionHash(meta_transaction.BRANCH_NULL_HASH) - - tangle.Events.TransactionSolid.Trigger(tx) - - tx = value_transaction.New() - tx.SetValue(int64(2)) - tx.SetBranchTransactionHash(meta_transaction.BRANCH_NULL_HASH) - tx.SetTrunkTransactionHash(meta_transaction.BRANCH_NULL_HASH) - - tangle.Events.TransactionSolid.Trigger(tx) - - assert.Equal(t, 2, GetTipsCount()) - - tip1 := GetRandomTip() - require.NotNil(t, tip1) - tip2 := GetRandomTip(tip1) - require.NotNil(t, tip2) - require.NotEqual(t, tip1, tip2) - - tx = value_transaction.New() - tx.SetValue(int64(3)) - tx.SetBranchTransactionHash(tip1) - tx.SetTrunkTransactionHash(tip2) - - tangle.Events.TransactionSolid.Trigger(tx) - - assert.Equal(t, 1, GetTipsCount()) - assert.Equal(t, tx.GetHash(), GetRandomTip()) -} diff --git a/plugins/webapi/findTransactionHashes/plugin.go b/plugins/webapi/findTransactionHashes/plugin.go index 7ae655f84217564fa4811c0fd9025670ef4284d2..29d573f148589cfafcb9b2c49ee26e083611d8e5 100644 --- a/plugins/webapi/findTransactionHashes/plugin.go +++ b/plugins/webapi/findTransactionHashes/plugin.go @@ -3,7 +3,6 @@ package findTransactionHashes import ( "net/http" - "github.com/iotaledger/goshimmer/plugins/tangle" "github.com/iotaledger/goshimmer/plugins/webapi" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/node" @@ -24,24 +23,29 @@ func configure(plugin *node.Plugin) { // If a node doesn't have any transaction hash for a given address in its ledger, // the value at the index of that address is empty. func findTransactionHashes(c echo.Context) error { - var request Request - - if err := c.Bind(&request); err != nil { - log.Info(err.Error()) - return c.JSON(http.StatusBadRequest, Response{Error: err.Error()}) - } - log.Debug("Received:", request.Addresses) - result := make([][]trinary.Trytes, len(request.Addresses)) - - for i, address := range request.Addresses { - txs, err := tangle.ReadTransactionHashesForAddressFromDatabase(address) - if err != nil { - return c.JSON(http.StatusInternalServerError, Response{Error: err.Error()}) + return c.JSON(http.StatusInternalServerError, Response{Error: "TODO: ADD LOGIC ACCORDING TO VALUE TANGLE"}) + + // TODO: ADD LOGIC ACCORDING TO VALUE TANGLE + /* + var request Request + + if err := c.Bind(&request); err != nil { + log.Info(err.Error()) + return c.JSON(http.StatusBadRequest, Response{Error: err.Error()}) + } + log.Debug("Received:", request.Addresses) + result := make([][]trinary.Trytes, len(request.Addresses)) + + for i, address := range request.Addresses { + txs, err := tangle_old.ReadTransactionHashesForAddressFromDatabase(address) + if err != nil { + return c.JSON(http.StatusInternalServerError, Response{Error: err.Error()}) + } + result[i] = append(result[i], txs...) } - result[i] = append(result[i], txs...) - } - return c.JSON(http.StatusOK, Response{Transactions: result}) + return c.JSON(http.StatusOK, Response{Transactions: result}) + */ } type Response struct { diff --git a/plugins/webapi/getTransactionObjectsByHash/plugin.go b/plugins/webapi/getTransactionObjectsByHash/plugin.go index e2b0e766658d8f15765fbb017f31174a7001160d..3432944c504ea16c1eca80ad8d92bffc5314881f 100644 --- a/plugins/webapi/getTransactionObjectsByHash/plugin.go +++ b/plugins/webapi/getTransactionObjectsByHash/plugin.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "github.com/iotaledger/goshimmer/plugins/tangle" + "github.com/iotaledger/goshimmer/plugins/tangle_old" "github.com/iotaledger/goshimmer/plugins/webapi" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/node" @@ -37,7 +37,7 @@ func getTransactionObjectsByHash(c echo.Context) error { log.Debug("Received:", request.Hashes) for _, hash := range request.Hashes { - tx, err := tangle.GetTransaction(hash) + tx, err := tangle_old.GetTransaction(hash) if err != nil { return c.JSON(http.StatusInternalServerError, Response{Error: err.Error()}) } diff --git a/plugins/webapi/getTransactionTrytesByHash/plugin.go b/plugins/webapi/getTransactionTrytesByHash/plugin.go index 8cb797782e73b90a74d0227429c4b1deac2a830f..e13c39c0bd65b899bebcd62d062ec2255870f6a5 100644 --- a/plugins/webapi/getTransactionTrytesByHash/plugin.go +++ b/plugins/webapi/getTransactionTrytesByHash/plugin.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "github.com/iotaledger/goshimmer/plugins/tangle" + "github.com/iotaledger/goshimmer/plugins/tangle_old" "github.com/iotaledger/goshimmer/plugins/webapi" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/node" @@ -35,7 +35,7 @@ func getTransactionTrytesByHash(c echo.Context) error { log.Debug("Received:", request.Hashes) for _, hash := range request.Hashes { - tx, err := tangle.GetTransaction(hash) + tx, err := tangle_old.GetTransaction(hash) if err != nil { return c.JSON(http.StatusInternalServerError, Response{Error: err.Error()}) }