diff --git a/go.mod b/go.mod index d65cf1acc15f196883e4bc197833e596c55f3781..6f415327efd874ccdf06ab1a92b2a60dae45e273 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.13 require ( github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/dgraph-io/badger v1.6.0 + github.com/dgraph-io/badger/v2 v2.0.0 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/emicklei/dot v0.10.1 github.com/ethereum/go-ethereum v1.9.3 @@ -14,7 +15,7 @@ require ( github.com/golang/protobuf v1.3.2 // indirect github.com/google/open-location-code/go v0.0.0-20190903173953-119bc96a3a51 github.com/gorilla/websocket v1.4.1 - github.com/iotaledger/hive.go v0.0.0-20191227143712-0ef454eb5509 + github.com/iotaledger/hive.go v0.0.0-20200101211541-ea7950f4c2f2 github.com/iotaledger/iota.go v1.0.0-beta.9 github.com/kr/text v0.1.0 github.com/labstack/echo v3.3.10+incompatible @@ -23,11 +24,11 @@ require ( github.com/mr-tron/base58 v1.1.3 github.com/oasislabs/ed25519 v0.0.0-20191122104632-9d9ffc15f526 github.com/panjf2000/ants/v2 v2.2.2 - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.8.1 github.com/rivo/tview v0.0.0-20190829161255-f8bc69b90341 github.com/rivo/uniseg v0.1.0 // indirect - github.com/sasha-s/go-deadlock v0.2.0 // indirect + github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.5.0 github.com/stretchr/testify v1.4.0 golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 diff --git a/go.sum b/go.sum index 432405f948c81be01dfc2ef19b9c15430ee6f46d..87df5300ce1af58a0f0951ba3eeaf0a71e2274ad 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -13,6 +15,7 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -28,6 +31,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger/v2 v2.0.0 h1:Cr05o2TUd2IcLbEY0aGd8mbjm1YyQpy+dswo3BcDXrE= +github.com/dgraph-io/badger/v2 v2.0.0/go.mod h1:YoRSIp1LmAJ7zH7tZwRvjNMUYLxB4wl3ebYkaIruZ04= +github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e h1:aeUNgwup7PnDOBAD1BOKAqzb/W/NksOj6r3dwKKuqfg= +github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e/go.mod h1:edzKIzGvqUCMzhTVWbiTSe75zD9Xxq0GtSBtFmaUTZs= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -64,6 +71,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -85,6 +93,14 @@ github.com/iotaledger/hive.go v0.0.0-20191208004610-567900b261bd h1:hh8iusLOBylW github.com/iotaledger/hive.go v0.0.0-20191208004610-567900b261bd/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20= github.com/iotaledger/hive.go v0.0.0-20191227143712-0ef454eb5509 h1:5mztG+IZqH6Y25YVxf+oXMBhtUWDBXnobjTnz4dW82c= github.com/iotaledger/hive.go v0.0.0-20191227143712-0ef454eb5509/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20= +github.com/iotaledger/hive.go v0.0.0-20191229015822-a119170bec84 h1:pZawocQ/B7HQYhizd9CANf42vqPhdd+P1Xg12ORR6cY= +github.com/iotaledger/hive.go v0.0.0-20191229015822-a119170bec84/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20= +github.com/iotaledger/hive.go v0.0.0-20191229233341-c3732738ee20 h1:ZIJAeQSEdmVbmZNIW2198IwD23+wBteb4WE4pyjxk+c= +github.com/iotaledger/hive.go v0.0.0-20191229233341-c3732738ee20/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20= +github.com/iotaledger/hive.go v0.0.0-20200101185538-ae70241fee7f h1:vxfLVJOsHHEbsooLij/JN+ues0AglB1pB8Dui/C3TUg= +github.com/iotaledger/hive.go v0.0.0-20200101185538-ae70241fee7f/go.mod h1:vrZrvGaWT1o5kz3Jj2B/PcUtqsFzZnLWrO3zEsGSuwk= +github.com/iotaledger/hive.go v0.0.0-20200101211541-ea7950f4c2f2 h1:S84ohGcHKq6NFOY77HUXLvqYfOveJhzzphSeimTUtTw= +github.com/iotaledger/hive.go v0.0.0-20200101211541-ea7950f4c2f2/go.mod h1:vrZrvGaWT1o5kz3Jj2B/PcUtqsFzZnLWrO3zEsGSuwk= github.com/iotaledger/iota.go v1.0.0-beta.9 h1:c654s9pkdhMBkABUvWg+6k91MEBbdtmZXP1xDfQpajg= github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -163,6 +179,7 @@ github.com/simia-tech/env v0.1.0/go.mod h1:eVRQ7W5NXXHifpPAcTJ3r5EmoGgMn++dXfSVb github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= @@ -257,6 +274,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= diff --git a/packages/binary/tangle/solidifier.go b/packages/binary/tangle/solidifier.go new file mode 100644 index 0000000000000000000000000000000000000000..417b6033fff4b4ce617b21a62c300f7986df7e2c --- /dev/null +++ b/packages/binary/tangle/solidifier.go @@ -0,0 +1,128 @@ +package tangle + +import ( + "container/list" + + "github.com/iotaledger/goshimmer/packages/binary/tangle/approvers" + "github.com/iotaledger/goshimmer/packages/binary/transaction" + "github.com/iotaledger/goshimmer/packages/binary/transactionmetadata" + "github.com/iotaledger/hive.go/async" + "github.com/iotaledger/hive.go/objectstorage" +) + +type solidifier struct { + tangle *Tangle + + workerPool async.WorkerPool +} + +func newSolidifier(tangle *Tangle) (result *solidifier) { + result = &solidifier{ + tangle: tangle, + } + + result.workerPool.Tune(1024) + + return +} + +func (solidifier *solidifier) Shutdown() { + solidifier.workerPool.ShutdownGracefully() +} + +func (solidifier *solidifier) Solidify(cachedTransaction *objectstorage.CachedObject, cachedTransactionMetadata *objectstorage.CachedObject) { + solidifier.workerPool.Submit(func() { solidifier.solidify(cachedTransaction, cachedTransactionMetadata) }) +} + +func (solidifier *solidifier) solidify(cachedTransaction *objectstorage.CachedObject, cachedTransactionMetadata *objectstorage.CachedObject) { + // initialize the stack + solidificationStack := list.New() + solidificationStack.PushBack([2]*objectstorage.CachedObject{cachedTransaction, cachedTransactionMetadata}) + + // process transactions that are supposed to be checked for solidity recursively + for solidificationStack.Len() > 0 { + // pop first element from stack + currentSolidificationEntry := solidificationStack.Front() + currentCachedTransaction := currentSolidificationEntry.Value.([2]*objectstorage.CachedObject)[0] + currentCachedTransactionMetadata := currentSolidificationEntry.Value.([2]*objectstorage.CachedObject)[1] + solidificationStack.Remove(currentSolidificationEntry) + + // retrieve transaction from cached result + var currentTransaction *transaction.Transaction + if _tmp := currentCachedTransaction.Get(); _tmp != nil { + currentTransaction = _tmp.(*transaction.Transaction) + } else { + currentCachedTransaction.Release() + currentCachedTransactionMetadata.Release() + + continue + } + + // retrieve metadata from cached result + var currentTransactionMetadata *transactionmetadata.TransactionMetadata + if _tmp := currentCachedTransactionMetadata.Get(); _tmp != nil { + currentTransactionMetadata = _tmp.(*transactionmetadata.TransactionMetadata) + } else { + currentCachedTransaction.Release() + currentCachedTransactionMetadata.Release() + + continue + } + + // if current transaction is solid and was not marked as solid before: mark as solid and propagate + if solidifier.isTransactionSolid(currentTransaction, currentTransactionMetadata) && currentTransactionMetadata.SetSolid(true) { + // fmt.Println("SOLID", currentTransaction.GetId()) + + solidifier.tangle.GetApprovers(currentTransaction.GetId()).Consume(func(object objectstorage.StorableObject) { + for approverTransactionId := range object.(*approvers.Approvers).Get() { + solidificationStack.PushBack([2]*objectstorage.CachedObject{ + solidifier.tangle.GetTransaction(approverTransactionId), + solidifier.tangle.GetTransactionMetadata(approverTransactionId), + }) + } + }) + } + + // release cached results + currentCachedTransaction.Release() + currentCachedTransactionMetadata.Release() + } +} + +func (solidifier *solidifier) isTransactionSolid(transaction *transaction.Transaction, transactionMetadata *transactionmetadata.TransactionMetadata) bool { + if transaction == nil || transaction.IsDeleted() { + return false + } + + if transactionMetadata == nil || transactionMetadata.IsDeleted() { + return false + } + + if transactionMetadata.IsSolid() { + return true + } + + // 1. check tangle solidity + if solidifier.isTransactionSolidInTangle(transaction.GetTrunkTransactionId()) && solidifier.isTransactionSolidInTangle(transaction.GetBranchTransactionId()) { + // 2. check payload solidity + return true + } + + return false +} + +func (solidifier *solidifier) isTransactionSolidInTangle(transactionId transaction.Id) bool { + if transactionId != transaction.EmptyId { + cachedTransactionMetadata := solidifier.tangle.GetTransactionMetadata(transactionId) + + if transactionMetadata := cachedTransactionMetadata.Get().(*transactionmetadata.TransactionMetadata); transactionMetadata == nil || transactionMetadata.IsDeleted() || !transactionMetadata.IsSolid() { + cachedTransactionMetadata.Release() + + return false + } + + cachedTransactionMetadata.Release() + } + + return true +} diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go index 5197c2eb9d18697f8af7be141ab91decc5955734..ee1e9cee68f7f389026bc12a3fd022c0274f1990 100644 --- a/packages/binary/tangle/tangle.go +++ b/packages/binary/tangle/tangle.go @@ -3,29 +3,119 @@ package tangle import ( "github.com/iotaledger/goshimmer/packages/binary/tangle/approvers" "github.com/iotaledger/goshimmer/packages/binary/transaction" + "github.com/iotaledger/goshimmer/packages/binary/transactionmetadata" + "github.com/iotaledger/goshimmer/packages/storageprefix" + "github.com/iotaledger/hive.go/async" "github.com/iotaledger/hive.go/objectstorage" ) type Tangle struct { - transactionStorage *objectstorage.ObjectStorage - approversStorage *objectstorage.ObjectStorage + solidifier *solidifier + transactionStorage *objectstorage.ObjectStorage + transactionMetadataStorage *objectstorage.ObjectStorage + approversStorage *objectstorage.ObjectStorage + + verifyTransactionsWorkerPool async.WorkerPool + storeTransactionsWorkerPool async.WorkerPool } -func New(storageId string) *Tangle { - return &Tangle{ - transactionStorage: objectstorage.New(storageId+"TANGLE_TRANSACTION_STORAGE", transactionFactory), - approversStorage: objectstorage.New(storageId+"TANGLE_APPROVERS_STORAGE", approversFactory), +func New(storageId []byte) (result *Tangle) { + result = &Tangle{ + transactionStorage: objectstorage.New(append(storageId, storageprefix.TangleTransaction...), transactionFactory), + transactionMetadataStorage: objectstorage.New(append(storageId, storageprefix.TangleTransactionMetadata...), transactionFactory), + approversStorage: objectstorage.New(append(storageId, storageprefix.TangleApprovers...), approversFactory), } + + result.solidifier = newSolidifier(result) + + return } -func transactionFactory(key []byte) objectstorage.StorableObject { - result := transaction.FromStorage(key) +func (tangle *Tangle) Prune() error { + if err := tangle.transactionStorage.Prune(); err != nil { + return err + } - return result + if err := tangle.transactionMetadataStorage.Prune(); err != nil { + return err + } + + if err := tangle.approversStorage.Prune(); err != nil { + return err + } + + return nil } -func approversFactory(key []byte) objectstorage.StorableObject { - result := approvers.FromStorage(key) +func (tangle *Tangle) AttachTransaction(transaction *transaction.Transaction) { + tangle.verifyTransactionsWorkerPool.Submit(func() { tangle.verifyTransaction(transaction) }) +} - return result +func (tangle *Tangle) GetTransaction(transactionId transaction.Id) *objectstorage.CachedObject { + return tangle.transactionStorage.Load(transactionId[:]) +} + +func (tangle *Tangle) GetTransactionMetadata(transactionId transaction.Id) *objectstorage.CachedObject { + return tangle.transactionMetadataStorage.Load(transactionId[:]) +} + +func (tangle *Tangle) GetApprovers(transactionId transaction.Id) *objectstorage.CachedObject { + return tangle.approversStorage.Load(transactionId[:]) +} + +func (tangle *Tangle) verifyTransaction(transaction *transaction.Transaction) { + if !transaction.VerifySignature() { + // err = errors.New("transaction has invalid signature") + + return + } + + tangle.storeTransactionsWorkerPool.Submit(func() { tangle.storeTransaction(transaction) }) +} + +func (tangle *Tangle) storeTransaction(transaction *transaction.Transaction) { + cachedTransaction, transactionIsNew := tangle.transactionStorage.StoreIfAbsent(transaction.GetStorageKey(), transaction) + if !transactionIsNew { + return + } + + cachedTransactionMetadata := tangle.createTransactionMetadata(transaction) + + tangle.addTransactionToApprovers(transaction, transaction.GetTrunkTransactionId()) + tangle.addTransactionToApprovers(transaction, transaction.GetBranchTransactionId()) + + tangle.solidifier.Solidify(cachedTransaction, cachedTransactionMetadata) +} + +// Marks the tangle as stopped, so it will not accept any new transactions, and then waits for all backgroundTasks to +// finish. +func (tangle *Tangle) Shutdown() *Tangle { + tangle.verifyTransactionsWorkerPool.ShutdownGracefully() + tangle.storeTransactionsWorkerPool.ShutdownGracefully() + + tangle.solidifier.Shutdown() + + return tangle +} + +func (tangle *Tangle) createTransactionMetadata(transaction *transaction.Transaction) *objectstorage.CachedObject { + transactionMetadata := transactionmetadata.New(transaction.GetId()) + + return tangle.transactionMetadataStorage.Store(transactionMetadata) +} + +func (tangle *Tangle) addTransactionToApprovers(transaction *transaction.Transaction, trunkTransactionId transaction.Id) { + tangle.approversStorage.ComputeIfAbsent(trunkTransactionId[:], func([]byte) objectstorage.StorableObject { + return approvers.New(trunkTransactionId) + }).Consume(func(object objectstorage.StorableObject) { + object.(*approvers.Approvers).Add(transaction.GetId()) + }) +} + +func transactionFactory(key []byte) objectstorage.StorableObject { + return transaction.FromStorage(key) +} + +func approversFactory(key []byte) objectstorage.StorableObject { + return approvers.FromStorage(key) } diff --git a/packages/binary/tangle/tangle_test.go b/packages/binary/tangle/tangle_test.go new file mode 100644 index 0000000000000000000000000000000000000000..94e19ba97788e7f87bbfd7a25b0a7fd0727db456 --- /dev/null +++ b/packages/binary/tangle/tangle_test.go @@ -0,0 +1,58 @@ +package tangle + +import ( + "fmt" + "testing" + + "github.com/iotaledger/goshimmer/packages/binary/identity" + "github.com/iotaledger/goshimmer/packages/binary/transaction" + "github.com/iotaledger/goshimmer/packages/binary/transaction/payload/data" +) + +func BenchmarkTangle_AttachTransaction(b *testing.B) { + tangle := New([]byte("TEST_BINARY_TANGLE")) + if err := tangle.Prune(); err != nil { + b.Error(err) + + return + } + + transactionBytes := make([][]byte, b.N) + for i := 0; i < b.N; i++ { + transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data"))).GetBytes() + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + if txToAttach, err := transaction.FromBytes(transactionBytes[i]); err != nil { + b.Error(err) + + return + } else { + tangle.AttachTransaction(txToAttach) + } + } + + tangle.Shutdown() +} + +func TestTangle_AttachTransaction(t *testing.T) { + tangle := New([]byte("TEST_BINARY_TANGLE")) + if err := tangle.Prune(); err != nil { + t.Error(err) + + return + } + + newTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data"))) + newTransaction2 := transaction.New(newTransaction1.GetId(), transaction.EmptyId, identity.Generate(), data.New([]byte("some other data"))) + + fmt.Println("ATTACH", newTransaction2.GetId()) + tangle.AttachTransaction(newTransaction2) + + fmt.Println("ATTACH", newTransaction1.GetId()) + tangle.AttachTransaction(newTransaction1) + + tangle.Shutdown() +} diff --git a/packages/binary/transaction/test/transaction_test.go b/packages/binary/transaction/test/transaction_test.go index c04c62b4627198f3db813e98c57e516a161638a1..15a4be905482fb370a11b1f75f134e0cd4095f41 100644 --- a/packages/binary/transaction/test/transaction_test.go +++ b/packages/binary/transaction/test/transaction_test.go @@ -2,9 +2,12 @@ package test import ( "fmt" + "runtime" "sync" "testing" + "github.com/iotaledger/goshimmer/packages/binary/async" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins" @@ -23,6 +26,9 @@ import ( ) func BenchmarkVerifyDataTransactions(b *testing.B) { + var pool async.WorkerPool + pool.Tune(runtime.NumCPU() * 2) + transactions := make([][]byte, b.N) for i := 0; i < b.N; i++ { tx := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data"))) @@ -34,31 +40,26 @@ func BenchmarkVerifyDataTransactions(b *testing.B) { } } - var wg sync.WaitGroup - b.ResetTimer() for i := 0; i < b.N; i++ { - wg.Add(1) - currentIndex := i - if err := ants.Submit(func() { + pool.Submit(func() { if tx, err := transaction.FromBytes(transactions[currentIndex]); err != nil { b.Error(err) } else { tx.VerifySignature() } - - wg.Done() - }); err != nil { - b.Error(err) - } + }) } - wg.Wait() + pool.Shutdown() } func BenchmarkVerifyValueTransactions(b *testing.B) { + var pool async.WorkerPool + pool.Tune(runtime.NumCPU() * 2) + keyPairOfSourceAddress := ed25119.GenerateKeyPair() keyPairOfTargetAddress := ed25119.GenerateKeyPair() @@ -76,32 +77,26 @@ func BenchmarkVerifyValueTransactions(b *testing.B) { } } - var wg sync.WaitGroup - b.ResetTimer() for i := 0; i < b.N; i++ { - wg.Add(1) - currentIndex := i - if err := ants.Submit(func() { + pool.Submit(func() { if tx, err := transaction.FromBytes(transactions[currentIndex]); err != nil { b.Error(err) } else { tx.VerifySignature() tx.GetPayload().(*valuetransfer.ValueTransfer).VerifySignatures() } - - wg.Done() - }); err != nil { - b.Error(err) - } + }) } - wg.Wait() + pool.Shutdown() } func BenchmarkVerifySignature(b *testing.B) { + pool, _ := ants.NewPool(80, ants.WithNonblocking(false)) + transactions := make([]*transaction.Transaction, b.N) for i := 0; i < b.N; i++ { transactions[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("test"))) @@ -116,12 +111,14 @@ func BenchmarkVerifySignature(b *testing.B) { wg.Add(1) currentIndex := i - if err := ants.Submit(func() { + if err := pool.Submit(func() { transactions[currentIndex].VerifySignature() wg.Done() }); err != nil { b.Error(err) + + return } } diff --git a/packages/binary/transaction/transaction.go b/packages/binary/transaction/transaction.go index 57ed71539a04311b6c4d383ebc34ec7cb2b41268..6ad2526587b724bfa25147758f80312fbbe22acf 100644 --- a/packages/binary/transaction/transaction.go +++ b/packages/binary/transaction/transaction.go @@ -99,6 +99,14 @@ func (transaction *Transaction) GetId() (result Id) { return } +func (transaction *Transaction) GetTrunkTransactionId() Id { + return transaction.trunkTransactionId +} + +func (transaction *Transaction) GetBranchTransactionId() Id { + return transaction.branchTransactionId +} + func (transaction *Transaction) GetPayload() payload.Payload { return transaction.payload } diff --git a/packages/binary/transactionmetadata/transactionmetadata.go b/packages/binary/transactionmetadata/transactionmetadata.go new file mode 100644 index 0000000000000000000000000000000000000000..f79599e4221a5973721d0fc5e5ddb76e072d63b7 --- /dev/null +++ b/packages/binary/transactionmetadata/transactionmetadata.go @@ -0,0 +1,73 @@ +package transactionmetadata + +import ( + "sync" + "time" + + "github.com/iotaledger/goshimmer/packages/binary/transaction" + "github.com/iotaledger/hive.go/objectstorage" +) + +type TransactionMetadata struct { + objectstorage.StorableObjectFlags + + transactionId transaction.Id + receivedTime time.Time + solid bool + solidificationTime time.Time + + solidMutex sync.RWMutex +} + +func New(transactionId transaction.Id) *TransactionMetadata { + return &TransactionMetadata{ + transactionId: transactionId, + receivedTime: time.Now(), + } +} + +func (transactionMetadata *TransactionMetadata) IsSolid() (result bool) { + transactionMetadata.solidMutex.RLock() + result = transactionMetadata.solid + transactionMetadata.solidMutex.RUnlock() + + return +} + +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 + + transactionMetadata.SetModified() + + modified = true + } + transactionMetadata.solidMutex.Unlock() + + } else { + transactionMetadata.solidMutex.RUnlock() + } + + return +} + +func (transactionMetadata *TransactionMetadata) GetStorageKey() []byte { + return transactionMetadata.transactionId[:] +} + +func (transactionMetadata *TransactionMetadata) Update(other objectstorage.StorableObject) { + +} + +func (transactionMetadata *TransactionMetadata) MarshalBinary() ([]byte, error) { + return nil, nil +} + +func (transactionMetadata *TransactionMetadata) UnmarshalBinary([]byte) error { + return nil +} diff --git a/packages/ledgerstate/ledgerstate.go b/packages/ledgerstate/ledgerstate.go index 2faad9c2b978ba4b30bc85c6639ae53fff06912d..48d48147ddb2cc3b58bf664442d9c7d793b2d807 100644 --- a/packages/ledgerstate/ledgerstate.go +++ b/packages/ledgerstate/ledgerstate.go @@ -7,6 +7,8 @@ import ( "strings" "time" + "github.com/iotaledger/goshimmer/packages/storageprefix" + "github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins" "github.com/iotaledger/goshimmer/packages/binary/address" @@ -31,13 +33,13 @@ type LedgerState struct { conflictSets *objectstorage.ObjectStorage } -func NewLedgerState(storageId string) *LedgerState { +func NewLedgerState(storageId []byte) *LedgerState { result := &LedgerState{ - storageId: []byte(storageId), - transferOutputs: objectstorage.New(storageId+"TRANSFER_OUTPUTS", transfer.OutputFactory, objectstorage.CacheTime(1*time.Second)), - transferOutputBookings: objectstorage.New(storageId+"TRANSFER_OUTPUT_BOOKING", transfer.OutputBookingFactory, objectstorage.CacheTime(1*time.Second)), - realities: objectstorage.New(storageId+"REALITIES", realityFactory, objectstorage.CacheTime(1*time.Second)), - conflictSets: objectstorage.New(storageId+"CONFLICT_SETS", conflict.Factory, objectstorage.CacheTime(1*time.Second)), + storageId: storageId, + transferOutputs: objectstorage.New(append(storageId, storageprefix.LedgerStateTransferOutput...), transfer.OutputFactory, objectstorage.CacheTime(1*time.Second)), + transferOutputBookings: objectstorage.New(append(storageId, storageprefix.LedgerStateTransferOutputBooking...), transfer.OutputBookingFactory, objectstorage.CacheTime(1*time.Second)), + realities: objectstorage.New(append(storageId, storageprefix.LedgerStateReality...), realityFactory, objectstorage.CacheTime(1*time.Second)), + conflictSets: objectstorage.New(append(storageId, storageprefix.LedgerStateConflictSet...), conflict.Factory, objectstorage.CacheTime(1*time.Second)), } mainReality := newReality(reality.MAIN_ID) @@ -59,17 +61,14 @@ func (ledgerState *LedgerState) AddTransferOutput(transferHash transfer.Hash, ad } func (ledgerState *LedgerState) GetTransferOutput(transferOutputReference *transfer.OutputReference) *objectstorage.CachedObject { - if cachedTransferOutput, err := ledgerState.transferOutputs.Load(transferOutputReference.GetStorageKey()); err != nil { - panic(err) - } else { - if cachedTransferOutput.Exists() { - if transferOutput := cachedTransferOutput.Get().(*transfer.Output); transferOutput != nil { - transferOutput.OutputBookings = ledgerState.transferOutputBookings - } + cachedTransferOutput := ledgerState.transferOutputs.Load(transferOutputReference.GetStorageKey()) + if cachedTransferOutput.Exists() { + if transferOutput := cachedTransferOutput.Get().(*transfer.Output); transferOutput != nil { + transferOutput.OutputBookings = ledgerState.transferOutputBookings } - - return cachedTransferOutput } + + return cachedTransferOutput } func (ledgerState *LedgerState) ForEachConflictSet(callback func(object *objectstorage.CachedObject) bool) { @@ -130,29 +129,22 @@ func (ledgerState *LedgerState) CreateReality(id reality.Id) { newReality := newReality(id, reality.MAIN_ID) newReality.ledgerState = ledgerState - if mainReality, mainRealityErr := ledgerState.realities.Load(reality.MAIN_ID[:]); mainRealityErr != nil { - panic(mainRealityErr) - } else { - mainReality.Consume(func(object objectstorage.StorableObject) { - object.(*Reality).RegisterSubReality(id) - }) - } + ledgerState.realities.Load(reality.MAIN_ID[:]).Consume(func(object objectstorage.StorableObject) { + object.(*Reality).RegisterSubReality(id) + }) ledgerState.realities.Store(newReality).Release() } func (ledgerState *LedgerState) GetReality(id reality.Id) *objectstorage.CachedObject { - if cachedObject, err := ledgerState.realities.Load(id[:]); err != nil { - panic(err) - } else { - if cachedObject.Exists() { - if reality := cachedObject.Get().(*Reality); reality != nil { - reality.ledgerState = ledgerState - } + cachedObject := ledgerState.realities.Load(id[:]) + if cachedObject.Exists() { + if reality := cachedObject.Get().(*Reality); reality != nil { + reality.ledgerState = ledgerState } - - return cachedObject } + + return cachedObject } func (ledgerState *LedgerState) BookTransfer(transfer *transfer.Transfer) (err error) { @@ -249,21 +241,15 @@ func (ledgerState *LedgerState) GenerateRealityVisualization(pngFilename string) func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *objectstorage.CachedObject { switch len(realityIds) { case 0: - if loadedReality, loadedRealityErr := ledgerState.realities.Load(reality.MAIN_ID[:]); loadedRealityErr != nil { - panic(loadedRealityErr) - } else { - loadedReality.Get().(*Reality).ledgerState = ledgerState + loadedReality := ledgerState.realities.Load(reality.MAIN_ID[:]) + loadedReality.Get().(*Reality).ledgerState = ledgerState - return loadedReality - } + return loadedReality case 1: - if loadedReality, loadedRealityErr := ledgerState.realities.Load(realityIds[0][:]); loadedRealityErr != nil { - panic(loadedRealityErr) - } else { - loadedReality.Get().(*Reality).ledgerState = ledgerState + loadedReality := ledgerState.realities.Load(realityIds[0][:]) + loadedReality.Get().(*Reality).ledgerState = ledgerState - return loadedReality - } + return loadedReality default: aggregatedRealities := make(map[reality.Id]*objectstorage.CachedObject) @@ -275,10 +261,8 @@ func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *ob } // load reality or abort if it fails - cachedReality, loadingErr := ledgerState.realities.Load(realityId[:]) - if loadingErr != nil { - panic(loadingErr) - } else if !cachedReality.Exists() { + cachedReality := ledgerState.realities.Load(realityId[:]) + if !cachedReality.Exists() { panic(errors.New("referenced reality does not exist: " + realityId.String())) } @@ -340,7 +324,7 @@ func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *ob aggregatedRealityId := ledgerState.generateAggregatedRealityId(ledgerState.sortRealityIds(parentConflictRealities)) newAggregatedRealityCreated := false - if newCachedAggregatedReality, err := ledgerState.realities.ComputeIfAbsent(aggregatedRealityId[:], func(key []byte) (object objectstorage.StorableObject, e error) { + newCachedAggregatedReality := ledgerState.realities.ComputeIfAbsent(aggregatedRealityId[:], func(key []byte) (object objectstorage.StorableObject) { aggregatedReality := newReality(aggregatedRealityId, aggregatedRealityParentIds...) aggregatedReality.ledgerState = ledgerState aggregatedReality.SetPreferred(aggregatedRealityIsPreferred) @@ -355,24 +339,22 @@ func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *ob newAggregatedRealityCreated = true - return aggregatedReality, nil - }); err != nil { - panic(err) - } else { - if !newAggregatedRealityCreated { - aggregatedReality := newCachedAggregatedReality.Get().(*Reality) - - for _, realityId := range aggregatedRealityParentIds { - if aggregatedReality.AddParentReality(realityId) { - ledgerState.GetReality(realityId).Consume(func(object objectstorage.StorableObject) { - object.(*Reality).RegisterSubReality(aggregatedRealityId) - }) - } + return aggregatedReality + }) + + if !newAggregatedRealityCreated { + aggregatedReality := newCachedAggregatedReality.Get().(*Reality) + + for _, realityId := range aggregatedRealityParentIds { + if aggregatedReality.AddParentReality(realityId) { + ledgerState.GetReality(realityId).Consume(func(object objectstorage.StorableObject) { + object.(*Reality).RegisterSubReality(aggregatedRealityId) + }) } } - - return newCachedAggregatedReality } + + return newCachedAggregatedReality } } diff --git a/packages/ledgerstate/ledgerstate_test.go b/packages/ledgerstate/ledgerstate_test.go index c1d2df5423b689130bf6d23e67360eb93d428871..bcac9f2fe5ae44a49594fe11e191a23640705eae 100644 --- a/packages/ledgerstate/ledgerstate_test.go +++ b/packages/ledgerstate/ledgerstate_test.go @@ -12,7 +12,6 @@ import ( "github.com/iotaledger/goshimmer/packages/ledgerstate/reality" "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" "github.com/iotaledger/hive.go/objectstorage" - "github.com/iotaledger/hive.go/parameter" ) var ( @@ -33,14 +32,8 @@ var ( pendingReality = reality.NewId("PENDING") ) -func init() { - if err := parameter.FetchConfig(false); err != nil { - panic(err) - } -} - func Benchmark(b *testing.B) { - ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput( + ledgerState := NewLedgerState([]byte("testLedger")).Prune().AddTransferOutput( transferHash1, addressHash1, coloredcoins.NewColoredBalance(eth, 1024), ) @@ -64,7 +57,7 @@ func Benchmark(b *testing.B) { } func Test(t *testing.T) { - ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput( + ledgerState := NewLedgerState([]byte("testLedger")).Prune().AddTransferOutput( transferHash1, addressHash1, coloredcoins.NewColoredBalance(eth, 1337), coloredcoins.NewColoredBalance(iota_, 1338), ) @@ -102,7 +95,7 @@ func Test(t *testing.T) { time.Sleep(1000 * time.Millisecond) - objectstorage.WaitForWritesToFlush() + ledgerState.transferOutputs.WaitForWritesToFlush() ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool { object.Consume(func(object objectstorage.StorableObject) { @@ -130,7 +123,7 @@ func generateRandomAddressHash() address.Address { } func initializeLedgerStateWithBalances(numberOfBalances int) (ledgerState *LedgerState, result []*transfer.OutputReference) { - ledgerState = NewLedgerState("testLedger").Prune() + ledgerState = NewLedgerState([]byte("testLedger")).Prune() for i := 0; i < numberOfBalances; i++ { transferHash := generateRandomTransferHash() @@ -239,7 +232,7 @@ func TestAggregateAggregatedRealities(t *testing.T) { time.Sleep(2000 * time.Millisecond) - objectstorage.WaitForWritesToFlush() + ledgerState.transferOutputs.WaitForWritesToFlush() _ = ledgerState.GenerateRealityVisualization("realities1.png") _ = NewVisualizer(ledgerState).RenderTransferOutputs("outputs1.png") @@ -248,7 +241,7 @@ func TestAggregateAggregatedRealities(t *testing.T) { time.Sleep(2000 * time.Millisecond) - objectstorage.WaitForWritesToFlush() + ledgerState.transferOutputs.WaitForWritesToFlush() _ = ledgerState.GenerateRealityVisualization("realities2.png") _ = NewVisualizer(ledgerState).RenderTransferOutputs("outputs2.png") @@ -283,14 +276,14 @@ func TestElevateAggregatedReality(t *testing.T) { time.Sleep(1000 * time.Millisecond) - objectstorage.WaitForWritesToFlush() + ledgerState.transferOutputs.WaitForWritesToFlush() _ = ledgerState.GenerateRealityVisualization("realities.png") _ = NewVisualizer(ledgerState).RenderTransferOutputs("outputs.png") } func TestElevate(t *testing.T) { - ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput( + ledgerState := NewLedgerState([]byte("testLedger")).Prune().AddTransferOutput( transferHash1, addressHash1, coloredcoins.NewColoredBalance(eth, 1337), coloredcoins.NewColoredBalance(iota_, 1338), ) @@ -352,7 +345,7 @@ func TestElevate(t *testing.T) { time.Sleep(1000 * time.Millisecond) - objectstorage.WaitForWritesToFlush() + ledgerState.transferOutputs.WaitForWritesToFlush() ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool { object.Consume(func(object objectstorage.StorableObject) { diff --git a/packages/ledgerstate/outputs1.png b/packages/ledgerstate/outputs1.png index 639f9f9d70d5ff3d49ec4cfb86fd919dc28fe008..6da15b92f4a01206aa38ff8b10439123feb22e41 100644 Binary files a/packages/ledgerstate/outputs1.png and b/packages/ledgerstate/outputs1.png differ diff --git a/packages/ledgerstate/outputs2.png b/packages/ledgerstate/outputs2.png index b3de946340e39640db58e60567793234cea900ef..4628b918f78a8d522080837b68b29fb28159a0d8 100644 Binary files a/packages/ledgerstate/outputs2.png and b/packages/ledgerstate/outputs2.png differ diff --git a/packages/ledgerstate/reality.go b/packages/ledgerstate/reality.go index b6c17b8ecbc13c88642b6a1e180f5711245b65ff..09bb808a7df694f9c15af51fb5752fe77573fa89 100644 --- a/packages/ledgerstate/reality.go +++ b/packages/ledgerstate/reality.go @@ -596,9 +596,7 @@ func (mreality *Reality) processConflictingInput(input *transfer.Output, consume err = mreality.createRealityForPreviouslyUnconflictingConsumers(consumersToElevate, cachedConflict.Get().(*conflict.Conflict)) } else { - if cachedConflict, err = mreality.ledgerState.conflictSets.Load(conflictId[:]); err != nil { - return - } + cachedConflict = mreality.ledgerState.conflictSets.Load(conflictId[:]) } return @@ -611,7 +609,7 @@ func (mreality *Reality) createRealityForPreviouslyUnconflictingConsumers(consum // Retrieve the Reality for this Transfer or create one if no Reality exists, yet. var realityIsNew bool - if cachedElevatedReality, realityErr := mreality.ledgerState.realities.ComputeIfAbsent(elevatedRealityId[:], func(key []byte) (object objectstorage.StorableObject, e error) { + cachedElevatedReality := mreality.ledgerState.realities.ComputeIfAbsent(elevatedRealityId[:], func(key []byte) (object objectstorage.StorableObject) { newReality := newReality(elevatedRealityId, mreality.id) newReality.ledgerState = mreality.ledgerState newReality.SetPreferred() @@ -623,30 +621,29 @@ func (mreality *Reality) createRealityForPreviouslyUnconflictingConsumers(consum realityIsNew = true - return newReality, nil - }); realityErr != nil { - err = realityErr - } else { - cachedElevatedReality.Consume(func(object objectstorage.StorableObject) { - elevatedReality := object.(*Reality) - - // We register every Conflict with the Reality (independent if it is "new" or not), to reflect its - // association to all corresponding Conflicts. (Note: A Reality can be part of multiple Conflicts if the - // Transfer that is associated to this Reality consumes multiple inputs. - conflict.AddReality(elevatedRealityId) - elevatedReality.AddConflict(conflict.GetId()) - - // A transaction can consume multiple inputs. We only elevate the consumers of a Reality once (when the - // Reality is created the first time). - if realityIsNew { - for _, addressHash := range addressHashes { - if err = mreality.elevateTransferOutput(transfer.NewOutputReference(transferHash, addressHash), elevatedReality); err != nil { - return - } + return newReality + }) + + cachedElevatedReality.Consume(func(object objectstorage.StorableObject) { + elevatedReality := object.(*Reality) + + // We register every Conflict with the Reality (independent if it is "new" or not), to reflect its + // association to all corresponding Conflicts. (Note: A Reality can be part of multiple Conflicts if the + // Transfer that is associated to this Reality consumes multiple inputs. + conflict.AddReality(elevatedRealityId) + elevatedReality.AddConflict(conflict.GetId()) + + // A transaction can consume multiple inputs. We only elevate the consumers of a Reality once (when the + // Reality is created the first time). + if realityIsNew { + for _, addressHash := range addressHashes { + if err = mreality.elevateTransferOutput(transfer.NewOutputReference(transferHash, addressHash), elevatedReality); err != nil { + return } } - }) - } + } + }) + } return @@ -767,29 +764,26 @@ func (mreality *Reality) bookTransferOutput(transferOutput *transfer.Output) (er // remove old booking if the Output is currently booked in another reality if transferOutputRealityId != realityId { - if oldTransferOutputBooking, err := mreality.ledgerState.transferOutputBookings.Load(transfer.GenerateOutputBookingStorageKey(transferOutputRealityId, transferOutputAddressHash, transferOutput.IsSpent(), transferOutput.GetTransferHash())); err != nil { - return err - } else { - transferOutput.SetRealityId(realityId) + oldTransferOutputBooking := mreality.ledgerState.transferOutputBookings.Load(transfer.GenerateOutputBookingStorageKey(transferOutputRealityId, transferOutputAddressHash, transferOutput.IsSpent(), transferOutput.GetTransferHash())) + transferOutput.SetRealityId(realityId) - mreality.ledgerState.GetReality(transferOutputRealityId).Consume(func(object objectstorage.StorableObject) { - transferOutputReality := object.(*Reality) + mreality.ledgerState.GetReality(transferOutputRealityId).Consume(func(object objectstorage.StorableObject) { + transferOutputReality := object.(*Reality) - // decrease transferOutputCount and remove reality if it is empty - if transferOutputReality.DecreaseTransferOutputCount() == 0 && transferOutputReality.GetSubRealityIdCount() == 0 { - for _, cachedParentReality := range transferOutputReality.GetParentRealities() { - cachedParentReality.Consume(func(parentReality objectstorage.StorableObject) { - parentReality.(*Reality).UnregisterSubReality(transferOutputRealityId) - }) - } - transferOutputReality.Delete() + // decrease transferOutputCount and remove reality if it is empty + if transferOutputReality.DecreaseTransferOutputCount() == 0 && transferOutputReality.GetSubRealityIdCount() == 0 { + for _, cachedParentReality := range transferOutputReality.GetParentRealities() { + cachedParentReality.Consume(func(parentReality objectstorage.StorableObject) { + parentReality.(*Reality).UnregisterSubReality(transferOutputRealityId) + }) } - }) + transferOutputReality.Delete() + } + }) - oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) { - transferOutputBooking.Delete() - }) - } + oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) { + transferOutputBooking.Delete() + }) } // book the Output into the current Reality diff --git a/packages/ledgerstate/transfer/output.go b/packages/ledgerstate/transfer/output.go index 7ac692e6c1aaabec8871717b94ca234c436312aa..9afeefb67a0fc12618199b078a5cb32dfbc11f2a 100644 --- a/packages/ledgerstate/transfer/output.go +++ b/packages/ledgerstate/transfer/output.go @@ -137,17 +137,12 @@ func (transferOutput *Output) markAsSpent() error { transferOutput.bookingMutex.Lock() currentBookingKey := GenerateOutputBookingStorageKey(transferOutput.GetRealityId(), transferOutput.addressHash, false, transferOutput.transferHash) - if oldTransferOutputBooking, err := transferOutput.OutputBookings.Load(currentBookingKey); err != nil { - transferOutput.bookingMutex.Unlock() + oldTransferOutputBooking := transferOutput.OutputBookings.Load(currentBookingKey) + transferOutput.OutputBookings.Store(NewTransferOutputBooking(transferOutput.GetRealityId(), transferOutput.addressHash, true, transferOutput.transferHash)).Release() - return err - } else { - transferOutput.OutputBookings.Store(NewTransferOutputBooking(transferOutput.GetRealityId(), transferOutput.addressHash, true, transferOutput.transferHash)).Release() - - oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) { - transferOutputBooking.Delete() - }) - } + oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) { + transferOutputBooking.Delete() + }) transferOutput.bookingMutex.Unlock() diff --git a/packages/storageprefix/storageprefix.go b/packages/storageprefix/storageprefix.go new file mode 100644 index 0000000000000000000000000000000000000000..7b2378eb5fadb2971676ba395af6e0104dfb4385 --- /dev/null +++ b/packages/storageprefix/storageprefix.go @@ -0,0 +1,12 @@ +package storageprefix + +var ( + TangleTransaction = []byte{0} + TangleTransactionMetadata = []byte{6} + TangleApprovers = []byte{1} + + LedgerStateTransferOutput = []byte{2} + LedgerStateTransferOutputBooking = []byte{3} + LedgerStateReality = []byte{4} + LedgerStateConflictSet = []byte{5} +)