diff --git a/packages/ledgerstate/constants.go b/packages/ledgerstate/constants.go index 4370530401cbae8d93eabce6b35713e100a77251..692e0689a4b68c92d7760fc17daed020e8807e47 100644 --- a/packages/ledgerstate/constants.go +++ b/packages/ledgerstate/constants.go @@ -1,28 +1,9 @@ package ledgerstate import ( - "github.com/iotaledger/goshimmer/packages/binary/address" "github.com/iotaledger/goshimmer/packages/ledgerstate/reality" - "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" ) -const ( - UNSPENT = SpentIndicator(0) - SPENT = SpentIndicator(1) - - marshalTransferOutputBookingRealityIdStart = 0 - marshalTransferOutputBookingRealityIdEnd = marshalTransferOutputBookingRealityIdStart + reality.IdLength - marshalTransferOutputBookingAddressHashStart = marshalTransferOutputBookingRealityIdEnd - marshalTransferOutputBookingAddressHashEnd = marshalTransferOutputBookingAddressHashStart + address.Length - marshalTransferOutputBookingSpentStart = marshalTransferOutputBookingAddressHashEnd - marshalTransferOutputBookingSpentEnd = marshalTransferOutputBookingSpentStart + 1 - marshalTransferOutputBookingTransferHashStart = marshalTransferOutputBookingSpentEnd - marshalTransferOutputBookingTransferHashEnd = marshalTransferOutputBookingTransferHashStart + transfer.HashLength - marshalTransferOutputBookingTotalLength = marshalTransferOutputBookingTransferHashEnd -) - -type SpentIndicator byte - var ( MAIN_REALITY_ID = reality.NewId("MAIN_REALITY") ) diff --git a/packages/ledgerstate/ledgerstate.go b/packages/ledgerstate/ledgerstate.go index 0635956e1069feeef5e81f31d6b6542c091f9512..8bf724d957109459c187199012813e8dcac28460 100644 --- a/packages/ledgerstate/ledgerstate.go +++ b/packages/ledgerstate/ledgerstate.go @@ -34,8 +34,8 @@ type LedgerState struct { func NewLedgerState(storageId string) *LedgerState { result := &LedgerState{ storageId: []byte(storageId), - transferOutputs: objectstorage.New(storageId+"TRANSFER_OUTPUTS", transferOutputFactory, objectstorage.CacheTime(1*time.Second)), - transferOutputBookings: objectstorage.New(storageId+"TRANSFER_OUTPUT_BOOKING", transferOutputBookingFactory, objectstorage.CacheTime(1*time.Second)), + 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)), } @@ -52,7 +52,7 @@ func (ledgerState *LedgerState) AddTransferOutput(transferHash transfer.Hash, ad ledgerState.GetReality(MAIN_REALITY_ID).Consume(func(object objectstorage.StorableObject) { mainReality := object.(*Reality) - mainReality.bookTransferOutput(NewTransferOutput(ledgerState, reality.EmptyId, transferHash, addressHash, balances...)) + mainReality.bookTransferOutput(transfer.NewTransferOutput(ledgerState.transferOutputBookings, reality.EmptyId, transferHash, addressHash, balances...)) }) return ledgerState @@ -63,8 +63,8 @@ func (ledgerState *LedgerState) GetTransferOutput(transferOutputReference *trans panic(err) } else { if cachedTransferOutput.Exists() { - if transferOutput := cachedTransferOutput.Get().(*TransferOutput); transferOutput != nil { - transferOutput.ledgerState = ledgerState + if transferOutput := cachedTransferOutput.Get().(*transfer.Output); transferOutput != nil { + transferOutput.OutputBookings = ledgerState.transferOutputBookings } } @@ -95,7 +95,7 @@ func (ledgerState *LedgerState) ForEachTransferOutput(callback func(object *obje if searchBookings { for _, prefix := range prefixes { if err := ledgerState.transferOutputBookings.ForEach(func(key []byte, cachedObject *objectstorage.CachedObject) bool { - booking := cachedObject.Get().(*TransferOutputBooking) + booking := cachedObject.Get().(*transfer.OutputBooking) cachedObject.Release() return callback(ledgerState.GetTransferOutput(transfer.NewOutputReference(booking.GetTransferHash(), booking.GetAddressHash()))) @@ -107,7 +107,7 @@ func (ledgerState *LedgerState) ForEachTransferOutput(callback func(object *obje if len(prefixes) >= 1 { for _, prefix := range prefixes { if err := ledgerState.transferOutputs.ForEach(func(key []byte, cachedObject *objectstorage.CachedObject) bool { - cachedObject.Get().(*TransferOutput).ledgerState = ledgerState + cachedObject.Get().(*transfer.Output).OutputBookings = ledgerState.transferOutputBookings return callback(cachedObject) }, prefix); err != nil { @@ -116,7 +116,7 @@ func (ledgerState *LedgerState) ForEachTransferOutput(callback func(object *obje } } else { if err := ledgerState.transferOutputs.ForEach(func(key []byte, cachedObject *objectstorage.CachedObject) bool { - cachedObject.Get().(*TransferOutput).ledgerState = ledgerState + cachedObject.Get().(*transfer.Output).OutputBookings = ledgerState.transferOutputBookings return callback(cachedObject) }); err != nil { @@ -418,11 +418,11 @@ func (ledgerState *LedgerState) generateFilterPrefixes(filters []interface{}) ([ filteredAddresses = append(filteredAddresses, typeCastedValue) case transfer.Hash: filteredTransfers = append(filteredTransfers, typeCastedValue) - case SpentIndicator: + case transfer.SpentIndicator: switch typeCastedValue { - case SPENT: + case transfer.SPENT: filterSpent = true - case UNSPENT: + case transfer.UNSPENT: filterUnspent = true default: panic("unknown SpentIndicator") @@ -445,9 +445,9 @@ func (ledgerState *LedgerState) generateFilterPrefixes(filters []interface{}) ([ if filterSpent != filterUnspent { spentPrefix := append([]byte{}, addressPrefix...) if filterSpent { - spentPrefix = append(spentPrefix, byte(SPENT)) + spentPrefix = append(spentPrefix, byte(transfer.SPENT)) } else { - spentPrefix = append(spentPrefix, byte(UNSPENT)) + spentPrefix = append(spentPrefix, byte(transfer.UNSPENT)) } // TODO: FILTER TRANSFER HASH @@ -482,14 +482,10 @@ func (ledgerState *LedgerState) generateFilterPrefixes(filters []interface{}) ([ return prefixes, false } -func (ledgerState *LedgerState) storeTransferOutput(transferOutput *TransferOutput) *objectstorage.CachedObject { +func (ledgerState *LedgerState) storeTransferOutput(transferOutput *transfer.Output) *objectstorage.CachedObject { return ledgerState.transferOutputs.Store(transferOutput) } -func (ledgerState *LedgerState) storeTransferOutputBooking(transferOutputBooking *TransferOutputBooking) *objectstorage.CachedObject { - return ledgerState.transferOutputBookings.Store(transferOutputBooking) -} - func (ledgerState *LedgerState) sortRealityIds(aggregatedRealities map[reality.Id]*objectstorage.CachedObject) []reality.Id { counter := 0 sortedRealityIds := make([]reality.Id, len(aggregatedRealities)) @@ -528,7 +524,7 @@ func (ledgerState *LedgerState) generateAggregatedRealityId(sortedRealityIds []r func (ledgerState *LedgerState) getTargetReality(inputs []*objectstorage.CachedObject) *objectstorage.CachedObject { realityIds := make([]reality.Id, len(inputs)) for i, input := range inputs { - realityIds[i] = input.Get().(*TransferOutput).GetRealityId() + realityIds[i] = input.Get().(*transfer.Output).GetRealityId() } return ledgerState.AggregateRealities(realityIds...) @@ -545,24 +541,6 @@ func (ledgerState *LedgerState) getTransferInputs(transfer *transfer.Transfer) [ return result } -func transferOutputFactory(key []byte) objectstorage.StorableObject { - result := &TransferOutput{ - storageKey: make([]byte, len(key)), - } - copy(result.storageKey, key) - - return result -} - -func transferOutputBookingFactory(key []byte) objectstorage.StorableObject { - result := &TransferOutputBooking{ - storageKey: make([]byte, len(key)), - } - copy(result.storageKey, key) - - return result -} - func realityFactory(key []byte) objectstorage.StorableObject { result := &Reality{ storageKey: make([]byte, len(key)), diff --git a/packages/ledgerstate/ledgerstate_test.go b/packages/ledgerstate/ledgerstate_test.go index 9f187dc15c6c69d4cc55d3a3e6ba26a51e01368a..c1d2df5423b689130bf6d23e67360eb93d428871 100644 --- a/packages/ledgerstate/ledgerstate_test.go +++ b/packages/ledgerstate/ledgerstate_test.go @@ -106,7 +106,7 @@ func Test(t *testing.T) { ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool { object.Consume(func(object objectstorage.StorableObject) { - fmt.Println(object.(*TransferOutput)) + fmt.Println(object.(*transfer.Output)) }) return true @@ -161,7 +161,7 @@ func spend(ledgerState *LedgerState, transferOutputReferences ...*transfer.Outpu transfer1 := transfer.NewTransfer(transferHash) for _, transferOutputReference := range transferOutputReferences { ledgerState.GetTransferOutput(transferOutputReference).Consume(func(object objectstorage.StorableObject) { - transferOutput := object.(*TransferOutput) + transferOutput := object.(*transfer.Output) for _, coloredBalance := range transferOutput.GetBalances() { totalInputBalance += coloredBalance.GetBalance() @@ -191,7 +191,7 @@ func multiSpend(ledgerState *LedgerState, outputCount int, transferOutputReferen totalInputBalance := uint64(0) for _, transferOutputReference := range transferOutputReferences { ledgerState.GetTransferOutput(transferOutputReference).Consume(func(object objectstorage.StorableObject) { - transferOutput := object.(*TransferOutput) + transferOutput := object.(*transfer.Output) for _, coloredBalance := range transferOutput.GetBalances() { totalInputBalance += coloredBalance.GetBalance() @@ -356,7 +356,7 @@ func TestElevate(t *testing.T) { ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool { object.Consume(func(object objectstorage.StorableObject) { - fmt.Println(object.(*TransferOutput)) + fmt.Println(object.(*transfer.Output)) }) return true diff --git a/packages/ledgerstate/outputs.png b/packages/ledgerstate/outputs.png index ce7f548b9857d355346331a8008d96e8f6de8cb7..4ef22e7241420c274afc5c857af241d0bbdf5ee2 100644 Binary files a/packages/ledgerstate/outputs.png and b/packages/ledgerstate/outputs.png differ diff --git a/packages/ledgerstate/outputs1.png b/packages/ledgerstate/outputs1.png index a6229704104a7d5650f31e3e0cb29f9f48ae1680..1aa2d13490e2d8775daa3e656fb0e7c0295c9a80 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 519d74e560be00d067d74190b6235e40afbad358..989e5eb91f2f4ff3e458e642e7db6603e0211738 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 de16e625c002c23cb6810d90ee9dde926e08d363..b6c17b8ecbc13c88642b6a1e180f5711245b65ff 100644 --- a/packages/ledgerstate/reality.go +++ b/packages/ledgerstate/reality.go @@ -479,7 +479,7 @@ func (mreality *Reality) verifyTransfer(inputs []*objectstorage.CachedObject, ou return errors.New("missing input in transfer") } - input := cachedInput.Get().(*TransferOutput) + input := cachedInput.Get().(*transfer.Output) if !mreality.DescendsFrom(input.GetRealityId()) { return errors.New("the referenced funds do not exist in this reality") } @@ -515,9 +515,9 @@ func (mreality *Reality) consumeInputs(inputs objectstorage.CachedObjects, trans conflicts = make(objectstorage.CachedObjects, 0) for _, input := range inputs { - consumedInput := input.Get().(*TransferOutput) + consumedInput := input.Get().(*transfer.Output) - if consumersToElevate, consumeErr := consumedInput.addConsumer(transferHash, outputs); consumeErr != nil { + if consumersToElevate, consumeErr := consumedInput.AddConsumer(transferHash, outputs); consumeErr != nil { err = consumeErr return @@ -554,14 +554,14 @@ func (mreality *Reality) createTransferOutputs(transferHash transfer.Hash, outpu } for addressHash, coloredBalances := range outputs { - if err = targetReality.bookTransferOutput(NewTransferOutput(mreality.ledgerState, reality.EmptyId, transferHash, addressHash, coloredBalances...)); err != nil { + if err = targetReality.bookTransferOutput(transfer.NewTransferOutput(mreality.ledgerState.transferOutputBookings, reality.EmptyId, transferHash, addressHash, coloredBalances...)); err != nil { return } } }) } else { for addressHash, coloredBalances := range outputs { - if err = mreality.bookTransferOutput(NewTransferOutput(mreality.ledgerState, reality.EmptyId, transferHash, addressHash, coloredBalances...)); err != nil { + if err = mreality.bookTransferOutput(transfer.NewTransferOutput(mreality.ledgerState.transferOutputBookings, reality.EmptyId, transferHash, addressHash, coloredBalances...)); err != nil { return } } @@ -588,7 +588,7 @@ func (mreality *Reality) collectParentConflictRealities(parentConflictRealities // Utility function that processes a conflicting input by retrieving the corresponding conflict. // If there is a non-empty list of consumers to elevate, we elevate them. -func (mreality *Reality) processConflictingInput(input *TransferOutput, consumersToElevate map[transfer.Hash][]address.Address) (cachedConflict *objectstorage.CachedObject, err error) { +func (mreality *Reality) processConflictingInput(input *transfer.Output, consumersToElevate map[transfer.Hash][]address.Address) (cachedConflict *objectstorage.CachedObject, err error) { conflictId := conflict.NewId(input.GetTransferHash(), input.GetAddressHash()) if len(consumersToElevate) >= 1 { @@ -655,15 +655,15 @@ func (mreality *Reality) createRealityForPreviouslyUnconflictingConsumers(consum // Private utility function that elevates a transfer output to the given reality. func (mreality *Reality) elevateTransferOutput(transferOutputReference *transfer.OutputReference, newReality *Reality) (err error) { if cachedTransferOutputToElevate := mreality.ledgerState.GetTransferOutput(transferOutputReference); !cachedTransferOutputToElevate.Exists() { - err = errors.New("could not find TransferOutput to elevate") + err = errors.New("could not find Output to elevate") } else { cachedTransferOutputToElevate.Consume(func(object objectstorage.StorableObject) { - transferOutputToElevate := object.(*TransferOutput) + transferOutputToElevate := object.(*transfer.Output) if currentTransferOutputRealityId := transferOutputToElevate.GetRealityId(); currentTransferOutputRealityId == mreality.GetId() { err = mreality.elevateTransferOutputOfCurrentReality(transferOutputToElevate, newReality) } else if cachedNestedReality := mreality.ledgerState.GetReality(currentTransferOutputRealityId); !cachedNestedReality.Exists() { - err = errors.New("could not find nested reality to elevate TransferOutput") + err = errors.New("could not find nested reality to elevate Output") } else { cachedNestedReality.Consume(func(nestedReality objectstorage.StorableObject) { err = nestedReality.(*Reality).elevateTransferOutputOfNestedReality(transferOutputToElevate, mreality.GetId(), newReality.GetId()) @@ -676,7 +676,7 @@ func (mreality *Reality) elevateTransferOutput(transferOutputReference *transfer } // Private utility function that elevates the transfer output from the current reality to the new reality. -func (mreality *Reality) elevateTransferOutputOfCurrentReality(transferOutput *TransferOutput, newReality *Reality) (err error) { +func (mreality *Reality) elevateTransferOutputOfCurrentReality(transferOutput *transfer.Output, newReality *Reality) (err error) { for transferHash, addresses := range transferOutput.GetConsumers() { for _, addressHash := range addresses { if elevateErr := mreality.elevateTransferOutput(transfer.NewOutputReference(transferHash, addressHash), newReality); elevateErr != nil { @@ -736,7 +736,7 @@ func (mreality *Reality) RegisterSubReality(realityId reality.Id) { } } -func (mreality *Reality) elevateTransferOutputOfNestedReality(transferOutput *TransferOutput, oldParentRealityId reality.Id, newParentRealityId reality.Id) (err error) { +func (mreality *Reality) elevateTransferOutputOfNestedReality(transferOutput *transfer.Output, oldParentRealityId reality.Id, newParentRealityId reality.Id) (err error) { if !mreality.IsAggregated() { mreality.replaceParentReality(oldParentRealityId, newParentRealityId) } else { @@ -750,12 +750,12 @@ func (mreality *Reality) elevateTransferOutputOfNestedReality(transferOutput *Tr return } -func (mreality *Reality) bookTransferOutput(transferOutput *TransferOutput) (err error) { +func (mreality *Reality) bookTransferOutput(transferOutput *transfer.Output) (err error) { // retrieve required variables realityId := mreality.id transferOutputRealityId := transferOutput.GetRealityId() transferOutputAddressHash := transferOutput.GetAddressHash() - transferOutputSpent := len(transferOutput.consumers) >= 1 + transferOutputSpent := transferOutput.IsSpent() transferOutputTransferHash := transferOutput.GetTransferHash() // store the transferOutput if it is "new" @@ -765,9 +765,9 @@ func (mreality *Reality) bookTransferOutput(transferOutput *TransferOutput) (err mreality.ledgerState.storeTransferOutput(transferOutput).Release() } else - // remove old booking if the TransferOutput is currently booked in another reality + // remove old booking if the Output is currently booked in another reality if transferOutputRealityId != realityId { - if oldTransferOutputBooking, err := mreality.ledgerState.transferOutputBookings.Load(generateTransferOutputBookingStorageKey(transferOutputRealityId, transferOutputAddressHash, len(transferOutput.consumers) >= 1, transferOutput.GetTransferHash())); err != nil { + if oldTransferOutputBooking, err := mreality.ledgerState.transferOutputBookings.Load(transfer.GenerateOutputBookingStorageKey(transferOutputRealityId, transferOutputAddressHash, transferOutput.IsSpent(), transferOutput.GetTransferHash())); err != nil { return err } else { transferOutput.SetRealityId(realityId) @@ -792,9 +792,9 @@ func (mreality *Reality) bookTransferOutput(transferOutput *TransferOutput) (err } } - // book the TransferOutput into the current Reality + // book the Output into the current Reality if transferOutputRealityId != realityId { - mreality.ledgerState.storeTransferOutputBooking(newTransferOutputBooking(realityId, transferOutputAddressHash, transferOutputSpent, transferOutputTransferHash)).Release() + mreality.ledgerState.transferOutputBookings.Store(transfer.NewTransferOutputBooking(realityId, transferOutputAddressHash, transferOutputSpent, transferOutputTransferHash)).Release() mreality.IncreaseTransferOutputCount() } diff --git a/packages/ledgerstate/transfer/constants.go b/packages/ledgerstate/transfer/constants.go new file mode 100644 index 0000000000000000000000000000000000000000..03b144466dda030547b996bf1188c3259bdb86b6 --- /dev/null +++ b/packages/ledgerstate/transfer/constants.go @@ -0,0 +1,23 @@ +package transfer + +import ( + "github.com/iotaledger/goshimmer/packages/binary/address" + "github.com/iotaledger/goshimmer/packages/ledgerstate/reality" +) + +const ( + UNSPENT = SpentIndicator(0) + SPENT = SpentIndicator(1) + + marshalTransferOutputBookingRealityIdStart = 0 + marshalTransferOutputBookingRealityIdEnd = marshalTransferOutputBookingRealityIdStart + reality.IdLength + marshalTransferOutputBookingAddressHashStart = marshalTransferOutputBookingRealityIdEnd + marshalTransferOutputBookingAddressHashEnd = marshalTransferOutputBookingAddressHashStart + address.Length + marshalTransferOutputBookingSpentStart = marshalTransferOutputBookingAddressHashEnd + marshalTransferOutputBookingSpentEnd = marshalTransferOutputBookingSpentStart + 1 + marshalTransferOutputBookingTransferHashStart = marshalTransferOutputBookingSpentEnd + marshalTransferOutputBookingTransferHashEnd = marshalTransferOutputBookingTransferHashStart + HashLength + marshalTransferOutputBookingTotalLength = marshalTransferOutputBookingTransferHashEnd +) + +type SpentIndicator byte diff --git a/packages/ledgerstate/transfer_output.go b/packages/ledgerstate/transfer/output.go similarity index 68% rename from packages/ledgerstate/transfer_output.go rename to packages/ledgerstate/transfer/output.go index 1d6cabff4458ddff0b5a7ca23c6faa5fd6d829b1..7ac692e6c1aaabec8871717b94ca234c436312aa 100644 --- a/packages/ledgerstate/transfer_output.go +++ b/packages/ledgerstate/transfer/output.go @@ -1,58 +1,54 @@ -package ledgerstate +package transfer import ( "encoding/binary" "sync" + "github.com/iotaledger/goshimmer/packages/binary/address" "github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins" - "github.com/iotaledger/goshimmer/packages/ledgerstate/reality" - - "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" - - "github.com/iotaledger/goshimmer/packages/binary/address" - "github.com/iotaledger/goshimmer/packages/stringify" + "github.com/iotaledger/hive.go/objectstorage" ) -type TransferOutput struct { +type Output struct { objectstorage.StorableObjectFlags - transferHash transfer.Hash + transferHash Hash addressHash address.Address balances []*coloredcoins.ColoredBalance realityId reality.Id - consumers map[transfer.Hash][]address.Address + consumers map[Hash][]address.Address - storageKey []byte - ledgerState *LedgerState + storageKey []byte + OutputBookings *objectstorage.ObjectStorage realityIdMutex sync.RWMutex consumersMutex sync.RWMutex bookingMutex sync.Mutex } -func NewTransferOutput(ledgerState *LedgerState, realityId reality.Id, transferHash transfer.Hash, addressHash address.Address, balances ...*coloredcoins.ColoredBalance) *TransferOutput { - return &TransferOutput{ +func NewTransferOutput(outputBookings *objectstorage.ObjectStorage, realityId reality.Id, transferHash Hash, addressHash address.Address, balances ...*coloredcoins.ColoredBalance) *Output { + return &Output{ transferHash: transferHash, addressHash: addressHash, balances: balances, realityId: realityId, - consumers: make(map[transfer.Hash][]address.Address), + consumers: make(map[Hash][]address.Address), - storageKey: append(transferHash[:], addressHash[:]...), - ledgerState: ledgerState, + storageKey: append(transferHash[:], addressHash[:]...), + OutputBookings: outputBookings, } } -func (transferOutput *TransferOutput) GetTransferHash() (transferHash transfer.Hash) { +func (transferOutput *Output) GetTransferHash() (transferHash Hash) { transferHash = transferOutput.transferHash return } -func (transferOutput *TransferOutput) GetRealityId() (realityId reality.Id) { +func (transferOutput *Output) GetRealityId() (realityId reality.Id) { transferOutput.realityIdMutex.RLock() realityId = transferOutput.realityId transferOutput.realityIdMutex.RUnlock() @@ -60,11 +56,11 @@ func (transferOutput *TransferOutput) GetRealityId() (realityId reality.Id) { return } -func (transferOutput *TransferOutput) GetAddressHash() (addressHash address.Address) { +func (transferOutput *Output) GetAddressHash() (addressHash address.Address) { return transferOutput.addressHash } -func (transferOutput *TransferOutput) SetRealityId(realityId reality.Id) { +func (transferOutput *Output) SetRealityId(realityId reality.Id) { transferOutput.realityIdMutex.RLock() if transferOutput.realityId != realityId { transferOutput.realityIdMutex.RUnlock() @@ -81,12 +77,12 @@ func (transferOutput *TransferOutput) SetRealityId(realityId reality.Id) { } } -func (transferOutput *TransferOutput) GetBalances() []*coloredcoins.ColoredBalance { +func (transferOutput *Output) GetBalances() []*coloredcoins.ColoredBalance { return transferOutput.balances } -func (transferOutput *TransferOutput) GetConsumers() (consumers map[transfer.Hash][]address.Address) { - consumers = make(map[transfer.Hash][]address.Address) +func (transferOutput *Output) GetConsumers() (consumers map[Hash][]address.Address) { + consumers = make(map[Hash][]address.Address) transferOutput.consumersMutex.RLock() for transferHash, addresses := range transferOutput.consumers { @@ -98,7 +94,7 @@ func (transferOutput *TransferOutput) GetConsumers() (consumers map[transfer.Has return } -func (transferOutput *TransferOutput) addConsumer(consumer transfer.Hash, outputs map[address.Address][]*coloredcoins.ColoredBalance) (consumersToElevate map[transfer.Hash][]address.Address, err error) { +func (transferOutput *Output) AddConsumer(consumer Hash, outputs map[address.Address][]*coloredcoins.ColoredBalance) (consumersToElevate map[Hash][]address.Address, err error) { transferOutput.consumersMutex.RLock() if _, exist := transferOutput.consumers[consumer]; exist { transferOutput.consumersMutex.RUnlock() @@ -111,13 +107,13 @@ func (transferOutput *TransferOutput) addConsumer(consumer transfer.Hash, output consumersToElevate = nil err = transferOutput.markAsSpent() case 1: - consumersToElevate = make(map[transfer.Hash][]address.Address, 1) + consumersToElevate = make(map[Hash][]address.Address, 1) for transferHash, addresses := range transferOutput.consumers { consumersToElevate[transferHash] = addresses } err = nil default: - consumersToElevate = make(map[transfer.Hash][]address.Address) + consumersToElevate = make(map[Hash][]address.Address) err = nil } consumers := make([]address.Address, len(outputs)) @@ -137,16 +133,16 @@ func (transferOutput *TransferOutput) addConsumer(consumer transfer.Hash, output return } -func (transferOutput *TransferOutput) markAsSpent() error { +func (transferOutput *Output) markAsSpent() error { transferOutput.bookingMutex.Lock() - currentBookingKey := generateTransferOutputBookingStorageKey(transferOutput.GetRealityId(), transferOutput.addressHash, false, transferOutput.transferHash) - if oldTransferOutputBooking, err := transferOutput.ledgerState.transferOutputBookings.Load(currentBookingKey); err != nil { + currentBookingKey := GenerateOutputBookingStorageKey(transferOutput.GetRealityId(), transferOutput.addressHash, false, transferOutput.transferHash) + if oldTransferOutputBooking, err := transferOutput.OutputBookings.Load(currentBookingKey); err != nil { transferOutput.bookingMutex.Unlock() return err } else { - transferOutput.ledgerState.storeTransferOutputBooking(newTransferOutputBooking(transferOutput.GetRealityId(), transferOutput.addressHash, true, transferOutput.transferHash)).Release() + transferOutput.OutputBookings.Store(NewTransferOutputBooking(transferOutput.GetRealityId(), transferOutput.addressHash, true, transferOutput.transferHash)).Release() oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) { transferOutputBooking.Delete() @@ -158,8 +154,8 @@ func (transferOutput *TransferOutput) markAsSpent() error { return nil } -func (transferOutput *TransferOutput) String() string { - return stringify.Struct("TransferOutput", +func (transferOutput *Output) String() string { + return stringify.Struct("Output", stringify.StructField("transferHash", transferOutput.transferHash.String()), stringify.StructField("addressHash", transferOutput.addressHash.String()), stringify.StructField("balances", transferOutput.balances), @@ -170,20 +166,20 @@ func (transferOutput *TransferOutput) String() string { // region support object storage /////////////////////////////////////////////////////////////////////////////////////// -func (transferOutput *TransferOutput) GetStorageKey() []byte { +func (transferOutput *Output) GetStorageKey() []byte { return transferOutput.storageKey } -func (transferOutput *TransferOutput) Update(other objectstorage.StorableObject) {} +func (transferOutput *Output) Update(other objectstorage.StorableObject) {} -func (transferOutput *TransferOutput) MarshalBinary() ([]byte, error) { +func (transferOutput *Output) MarshalBinary() ([]byte, error) { transferOutput.realityIdMutex.RLock() transferOutput.consumersMutex.RLock() balanceCount := len(transferOutput.balances) consumerCount := len(transferOutput.consumers) - serializedLength := reality.IdLength + 4 + balanceCount*coloredcoins.BalanceLength + 4 + consumerCount*transfer.HashLength + serializedLength := reality.IdLength + 4 + balanceCount*coloredcoins.BalanceLength + 4 + consumerCount*HashLength for _, addresses := range transferOutput.consumers { serializedLength += 4 for range addresses { @@ -207,8 +203,8 @@ func (transferOutput *TransferOutput) MarshalBinary() ([]byte, error) { binary.LittleEndian.PutUint32(result[offset:], uint32(consumerCount)) offset += 4 for transferHash, addresses := range transferOutput.consumers { - copy(result[offset:], transferHash[:transfer.HashLength]) - offset += transfer.HashLength + copy(result[offset:], transferHash[:HashLength]) + offset += HashLength binary.LittleEndian.PutUint32(result[offset:], uint32(len(addresses))) offset += 4 @@ -225,12 +221,12 @@ func (transferOutput *TransferOutput) MarshalBinary() ([]byte, error) { return result, nil } -func (transferOutput *TransferOutput) UnmarshalBinary(serializedObject []byte) error { - if err := transferOutput.transferHash.UnmarshalBinary(transferOutput.storageKey[:transfer.HashLength]); err != nil { +func (transferOutput *Output) UnmarshalBinary(serializedObject []byte) error { + if err := transferOutput.transferHash.UnmarshalBinary(transferOutput.storageKey[:HashLength]); err != nil { return err } - if err := transferOutput.addressHash.UnmarshalBinary(transferOutput.storageKey[transfer.HashLength:]); err != nil { + if err := transferOutput.addressHash.UnmarshalBinary(transferOutput.storageKey[HashLength:]); err != nil { return err } @@ -253,7 +249,15 @@ func (transferOutput *TransferOutput) UnmarshalBinary(serializedObject []byte) e return nil } -func (transferOutput *TransferOutput) unmarshalBalances(serializedBalances []byte) ([]*coloredcoins.ColoredBalance, error) { +func (transferOutput *Output) IsSpent() (result bool) { + transferOutput.consumersMutex.RLock() + result = len(transferOutput.consumers) >= 1 + transferOutput.consumersMutex.RUnlock() + + return +} + +func (transferOutput *Output) unmarshalBalances(serializedBalances []byte) ([]*coloredcoins.ColoredBalance, error) { balanceCount := int(binary.LittleEndian.Uint32(serializedBalances)) balances := make([]*coloredcoins.ColoredBalance, balanceCount) @@ -269,19 +273,19 @@ func (transferOutput *TransferOutput) unmarshalBalances(serializedBalances []byt return balances, nil } -func (transferOutput *TransferOutput) unmarshalConsumers(serializedConsumers []byte) (map[transfer.Hash][]address.Address, error) { +func (transferOutput *Output) unmarshalConsumers(serializedConsumers []byte) (map[Hash][]address.Address, error) { offset := 0 consumerCount := int(binary.LittleEndian.Uint32(serializedConsumers[offset:])) offset += 4 - consumers := make(map[transfer.Hash][]address.Address, consumerCount) + consumers := make(map[Hash][]address.Address, consumerCount) for i := 0; i < consumerCount; i++ { - transferHash := transfer.Hash{} + transferHash := Hash{} if err := transferHash.UnmarshalBinary(serializedConsumers[offset:]); err != nil { return nil, err } - offset += transfer.HashLength + offset += HashLength addressHashCount := int(binary.LittleEndian.Uint32(serializedConsumers[offset:])) offset += 4 @@ -302,3 +306,12 @@ func (transferOutput *TransferOutput) unmarshalConsumers(serializedConsumers []b } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func OutputFactory(key []byte) objectstorage.StorableObject { + result := &Output{ + storageKey: make([]byte, len(key)), + } + copy(result.storageKey, key) + + return result +} diff --git a/packages/ledgerstate/transfer/output_booking.go b/packages/ledgerstate/transfer/output_booking.go new file mode 100644 index 0000000000000000000000000000000000000000..e18a77c1d807bde5afd0e86869345731090b0c5a --- /dev/null +++ b/packages/ledgerstate/transfer/output_booking.go @@ -0,0 +1,35 @@ +package transfer + +import ( + "github.com/iotaledger/goshimmer/packages/binary/address" + "github.com/iotaledger/goshimmer/packages/ledgerstate/reality" + "github.com/iotaledger/hive.go/objectstorage" +) + +// region private utility methods ////////////////////////////////////////////////////////////////////////////////////// + +func GenerateOutputBookingStorageKey(realityId reality.Id, addressHash address.Address, spent bool, transferHash Hash) (storageKey []byte) { + storageKey = make([]byte, reality.IdLength+address.Length+1+HashLength) + + copy(storageKey[marshalTransferOutputBookingRealityIdStart:marshalTransferOutputBookingRealityIdEnd], realityId[:reality.IdLength]) + copy(storageKey[marshalTransferOutputBookingAddressHashStart:marshalTransferOutputBookingAddressHashEnd], addressHash[:address.Length]) + if spent { + storageKey[marshalTransferOutputBookingSpentStart] = byte(SPENT) + } else { + storageKey[marshalTransferOutputBookingSpentStart] = byte(UNSPENT) + } + copy(storageKey[marshalTransferOutputBookingTransferHashStart:marshalTransferOutputBookingTransferHashEnd], transferHash[:HashLength]) + + return +} + +// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func OutputBookingFactory(key []byte) objectstorage.StorableObject { + result := &OutputBooking{ + storageKey: make([]byte, len(key)), + } + copy(result.storageKey, key) + + return result +} diff --git a/packages/ledgerstate/transfer_output_test.go b/packages/ledgerstate/transfer/output_test.go similarity index 75% rename from packages/ledgerstate/transfer_output_test.go rename to packages/ledgerstate/transfer/output_test.go index c808933b83b4a87c66b3c687584822a0d71e89fa..5bf1746964ca8579ed29a09b199b1b9a6de78d73 100644 --- a/packages/ledgerstate/transfer_output_test.go +++ b/packages/ledgerstate/transfer/output_test.go @@ -1,12 +1,10 @@ -package ledgerstate +package transfer import ( "testing" "github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins" - "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" - "github.com/iotaledger/goshimmer/packages/ledgerstate/reality" "github.com/iotaledger/goshimmer/packages/binary/address" @@ -15,10 +13,10 @@ import ( ) func TestTransferOutput_MarshalUnmarshal(t *testing.T) { - transferOutput := NewTransferOutput(nil, reality.NewId("REALITY"), transfer.NewHash("RECEIVE"), address.New([]byte("ADDRESS1")), coloredcoins.NewColoredBalance(coloredcoins.NewColor("IOTA"), 44), coloredcoins.NewColoredBalance(coloredcoins.NewColor("BTC"), 88)) - transferOutput.consumers = make(map[transfer.Hash][]address.Address) + transferOutput := NewTransferOutput(nil, reality.NewId("REALITY"), NewHash("RECEIVE"), address.New([]byte("ADDRESS1")), coloredcoins.NewColoredBalance(coloredcoins.NewColor("IOTA"), 44), coloredcoins.NewColoredBalance(coloredcoins.NewColor("BTC"), 88)) + transferOutput.consumers = make(map[Hash][]address.Address) - spendTransferHash := transfer.NewHash("SPEND") + spendTransferHash := NewHash("SPEND") transferOutput.consumers[spendTransferHash] = make([]address.Address, 2) transferOutput.consumers[spendTransferHash][0] = address.New([]byte("ADDRESS2")) transferOutput.consumers[spendTransferHash][1] = address.New([]byte("ADDRESS3")) @@ -28,7 +26,7 @@ func TestTransferOutput_MarshalUnmarshal(t *testing.T) { t.Error(err) } - unmarshaledTransferOutput := TransferOutput{storageKey: transferOutput.GetStorageKey()} + unmarshaledTransferOutput := Output{storageKey: transferOutput.GetStorageKey()} if err := unmarshaledTransferOutput.UnmarshalBinary(marshaledData); err != nil { t.Error(err) } diff --git a/packages/ledgerstate/transfer_output_booking.go b/packages/ledgerstate/transfer/transfer_output_booking.go similarity index 53% rename from packages/ledgerstate/transfer_output_booking.go rename to packages/ledgerstate/transfer/transfer_output_booking.go index 390d76582e453069a97471b6908ce6fd255eefd4..663f1aa99f0d27b2f6d2f60665d75188b1faf458 100644 --- a/packages/ledgerstate/transfer_output_booking.go +++ b/packages/ledgerstate/transfer/transfer_output_booking.go @@ -1,58 +1,57 @@ -package ledgerstate +package transfer import ( "github.com/iotaledger/goshimmer/packages/binary/address" "github.com/iotaledger/goshimmer/packages/errors" "github.com/iotaledger/goshimmer/packages/ledgerstate/reality" - "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" "github.com/iotaledger/goshimmer/packages/stringify" "github.com/iotaledger/hive.go/objectstorage" ) // region struct + constructor + public api //////////////////////////////////////////////////////////////////////////// -type TransferOutputBooking struct { +type OutputBooking struct { objectstorage.StorableObjectFlags realityId reality.Id addressHash address.Address spent bool - transferHash transfer.Hash + transferHash Hash storageKey []byte } -func newTransferOutputBooking(realityId reality.Id, addressHash address.Address, spent bool, transferHash transfer.Hash) (result *TransferOutputBooking) { - result = &TransferOutputBooking{ +func NewTransferOutputBooking(realityId reality.Id, addressHash address.Address, spent bool, transferHash Hash) (result *OutputBooking) { + result = &OutputBooking{ realityId: realityId, addressHash: addressHash, spent: spent, transferHash: transferHash, - storageKey: generateTransferOutputBookingStorageKey(realityId, addressHash, spent, transferHash), + storageKey: GenerateOutputBookingStorageKey(realityId, addressHash, spent, transferHash), } return } -func (booking *TransferOutputBooking) GetRealityId() reality.Id { +func (booking *OutputBooking) GetRealityId() reality.Id { return booking.realityId } -func (booking *TransferOutputBooking) GetAddressHash() address.Address { +func (booking *OutputBooking) GetAddressHash() address.Address { return booking.addressHash } -func (booking *TransferOutputBooking) IsSpent() bool { +func (booking *OutputBooking) IsSpent() bool { return booking.spent } -func (booking *TransferOutputBooking) GetTransferHash() transfer.Hash { +func (booking *OutputBooking) GetTransferHash() Hash { return booking.transferHash } -func (booking *TransferOutputBooking) String() string { - return stringify.Struct("TransferOutputBooking", +func (booking *OutputBooking) String() string { + return stringify.Struct("OutputBooking", stringify.StructField("realityId", booking.realityId), stringify.StructField("addressHash", booking.addressHash), stringify.StructField("spent", booking.spent), @@ -64,13 +63,13 @@ func (booking *TransferOutputBooking) String() string { // region support object storage /////////////////////////////////////////////////////////////////////////////////////// -func (booking *TransferOutputBooking) GetStorageKey() []byte { +func (booking *OutputBooking) GetStorageKey() []byte { return booking.storageKey } -func (booking *TransferOutputBooking) Update(other objectstorage.StorableObject) { - if otherBooking, ok := other.(*TransferOutputBooking); !ok { - panic("Update method expects a *TransferOutputBooking") +func (booking *OutputBooking) Update(other objectstorage.StorableObject) { + if otherBooking, ok := other.(*OutputBooking); !ok { + panic("Update method expects a *OutputBooking") } else { booking.realityId = otherBooking.realityId booking.addressHash = otherBooking.addressHash @@ -79,11 +78,11 @@ func (booking *TransferOutputBooking) Update(other objectstorage.StorableObject) } } -func (booking *TransferOutputBooking) MarshalBinary() ([]byte, error) { +func (booking *OutputBooking) MarshalBinary() ([]byte, error) { return []byte{}, nil } -func (booking *TransferOutputBooking) UnmarshalBinary(data []byte) error { +func (booking *OutputBooking) UnmarshalBinary(data []byte) error { if len(booking.storageKey) < marshalTransferOutputBookingTotalLength { return errors.New("unmarshal failed: the length of the key is to short") } @@ -113,22 +112,3 @@ func (booking *TransferOutputBooking) UnmarshalBinary(data []byte) error { } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// region private utility methods ////////////////////////////////////////////////////////////////////////////////////// - -func generateTransferOutputBookingStorageKey(realityId reality.Id, addressHash address.Address, spent bool, transferHash transfer.Hash) (storageKey []byte) { - storageKey = make([]byte, reality.IdLength+address.Length+1+transfer.HashLength) - - copy(storageKey[marshalTransferOutputBookingRealityIdStart:marshalTransferOutputBookingRealityIdEnd], realityId[:reality.IdLength]) - copy(storageKey[marshalTransferOutputBookingAddressHashStart:marshalTransferOutputBookingAddressHashEnd], addressHash[:address.Length]) - if spent { - storageKey[marshalTransferOutputBookingSpentStart] = byte(SPENT) - } else { - storageKey[marshalTransferOutputBookingSpentStart] = byte(UNSPENT) - } - copy(storageKey[marshalTransferOutputBookingTransferHashStart:marshalTransferOutputBookingTransferHashEnd], transferHash[:transfer.HashLength]) - - return -} - -// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/ledgerstate/visualizer.go b/packages/ledgerstate/visualizer.go index b9bc8b13e8d4ab1b66ac99dc28f2c7390022f2da..58adaae6c2cf14b8c674da21432dc644fbe608b4 100644 --- a/packages/ledgerstate/visualizer.go +++ b/packages/ledgerstate/visualizer.go @@ -34,7 +34,7 @@ func (visualizer *Visualizer) RenderTransferOutputs(pngFileName string) error { visualizer.ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool { object.Consume(func(object objectstorage.StorableObject) { - visualizer.drawTransferOutput(object.(*TransferOutput)) + visualizer.drawTransferOutput(object.(*transfer.Output)) }) return true @@ -51,7 +51,7 @@ func (visualizer *Visualizer) reset() *Visualizer { return visualizer } -func (visualizer *Visualizer) drawTransferOutput(transferOutput *TransferOutput) dot.Node { +func (visualizer *Visualizer) drawTransferOutput(transferOutput *transfer.Output) dot.Node { transferOutputIdentifier := visualizer.generateTransferOutputId(transferOutput) transferOutputNode, transferOutputDrawn := visualizer.transferOutputNodes[transferOutputIdentifier] @@ -63,7 +63,7 @@ func (visualizer *Visualizer) drawTransferOutput(transferOutput *TransferOutput) for transferHash, addresses := range transferOutput.GetConsumers() { for _, addressHash := range addresses { visualizer.ledgerState.GetTransferOutput(transfer.NewOutputReference(transferHash, addressHash)).Consume(func(object objectstorage.StorableObject) { - transferOutputNode.Edge(visualizer.drawTransferOutput(object.(*TransferOutput))) + transferOutputNode.Edge(visualizer.drawTransferOutput(object.(*transfer.Output))) }) } } @@ -74,7 +74,7 @@ func (visualizer *Visualizer) drawTransferOutput(transferOutput *TransferOutput) return transferOutputNode } -func (visualizer *Visualizer) generateTransferOutputId(transferOutput *TransferOutput) (result transferOutputId) { +func (visualizer *Visualizer) generateTransferOutputId(transferOutput *transfer.Output) (result transferOutputId) { transferHash := transferOutput.GetTransferHash() addressHash := transferOutput.GetAddressHash()