Skip to content
Snippets Groups Projects
Commit c98fefd7 authored by Hans Moog's avatar Hans Moog
Browse files

Feat: ledgerstate consumers now contain the addresses

parent 48538f23
No related branches found
No related tags found
No related merge requests found
......@@ -70,7 +70,7 @@ func Test(t *testing.T) {
addressHash4, NewColoredBalance(eth, 1000),
))
time.Sleep(1 * time.Second)
time.Sleep(3 * time.Second)
ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool {
object.Consume(func(object objectstorage.StorableObject) {
......
......@@ -130,37 +130,48 @@ func (reality *Reality) BookTransfer(transfer *Transfer) error {
return reality.bookTransfer(transfer.GetHash(), reality.ledgerState.getTransferInputs(transfer), transfer.GetOutputs())
}
func (reality *Reality) consumeInputs(inputs []*objectstorage.CachedObject, transferHash TransferHash, outputs map[AddressHash][]*ColoredBalance) (conflicting bool, err error) {
for _, input := range inputs {
consumedTransferOutput := input.Get().(*TransferOutput)
inputConflicting, consumersToElevate, consumeErr := consumedTransferOutput.addConsumer(transferHash, outputs)
if consumeErr != nil {
err = consumeErr
return
}
if inputConflicting {
for transferHash, consumerToElevate := range consumersToElevate {
// elevate previous liked transactions
fmt.Println(transferHash, consumerToElevate)
}
}
conflicting = conflicting || inputConflicting
}
return
}
func (reality *Reality) bookTransfer(transferHash TransferHash, inputs []*objectstorage.CachedObject, outputs map[AddressHash][]*ColoredBalance) error {
// check if transfer is valid within this reality
if err := reality.checkTransferBalances(inputs, outputs); err != nil {
return err
}
// mark inputs as spent / trigger double spend detection
conflicting := false
for _, input := range inputs {
consumedTransferOutput := input.Get().(*TransferOutput)
inputConflicting, err := consumedTransferOutput.addConsumer(transferHash)
conflicting, err := reality.consumeInputs(inputs, transferHash, outputs)
if err != nil {
return err
}
conflicting = conflicting || inputConflicting
}
if conflicting {
fmt.Println("CONFLICT DETECTED")
var targetRealityId RealityId
copy(targetRealityId[:], transferHash[:])
cachedTargetReality := reality.CreateReality(targetRealityId)
cachedTargetReality.Store()
cachedTargetReality.Get().(*Reality).bookTransferOutputs(transferHash, outputs)
cachedTargetReality.Release()
} else {
// book new transfer outputs into target reality
reality.bookTransferOutputs(transferHash, outputs)
}
......
......@@ -4,8 +4,6 @@ import (
"encoding/binary"
"sync"
"github.com/iotaledger/goshimmer/packages/errors"
"github.com/iotaledger/goshimmer/packages/objectstorage"
"github.com/iotaledger/goshimmer/packages/stringify"
)
......@@ -15,13 +13,14 @@ type TransferOutput struct {
addressHash AddressHash
balances []*ColoredBalance
realityId RealityId
consumers map[TransferHash]empty
consumers map[TransferHash][]AddressHash
storageKey []byte
ledgerState *LedgerState
realityIdMutex sync.RWMutex
consumersMutex sync.RWMutex
bookingMutex sync.Mutex
}
func NewTransferOutput(ledgerState *LedgerState, realityId RealityId, transferHash TransferHash, addressHash AddressHash, balances ...*ColoredBalance) *TransferOutput {
......@@ -30,13 +29,19 @@ func NewTransferOutput(ledgerState *LedgerState, realityId RealityId, transferHa
addressHash: addressHash,
balances: balances,
realityId: realityId,
consumers: make(map[TransferHash]empty),
consumers: make(map[TransferHash][]AddressHash),
storageKey: append(transferHash[:], addressHash[:]...),
ledgerState: ledgerState,
}
}
func (transferOutput *TransferOutput) GetTransferHash() (transferHash TransferHash) {
transferHash = transferOutput.transferHash
return
}
func (transferOutput *TransferOutput) GetRealityId() (realityId RealityId) {
transferOutput.realityIdMutex.RLock()
realityId = transferOutput.realityId
......@@ -45,6 +50,10 @@ func (transferOutput *TransferOutput) GetRealityId() (realityId RealityId) {
return
}
func (transferOutput *TransferOutput) GetAddressHash() (addressHash AddressHash) {
return transferOutput.addressHash
}
func (transferOutput *TransferOutput) SetRealityId(realityId RealityId) {
transferOutput.realityIdMutex.Lock()
transferOutput.realityId = realityId
......@@ -55,7 +64,7 @@ func (transferOutput *TransferOutput) GetBalances() []*ColoredBalance {
return transferOutput.balances
}
func (transferOutput *TransferOutput) addConsumer(consumer TransferHash) (conflicting bool, err error) {
func (transferOutput *TransferOutput) addConsumer(consumer TransferHash, outputs map[AddressHash][]*ColoredBalance) (isConflicting bool, consumersToElevate map[TransferHash][]AddressHash, err error) {
transferOutput.consumersMutex.RLock()
if _, exist := transferOutput.consumers[consumer]; exist {
transferOutput.consumersMutex.RUnlock()
......@@ -63,42 +72,73 @@ func (transferOutput *TransferOutput) addConsumer(consumer TransferHash) (confli
transferOutput.consumersMutex.RUnlock()
transferOutput.consumersMutex.Lock()
if conflicting = len(transferOutput.consumers) != 0; !conflicting {
if markAsSpentErr := transferOutput.markAsSpent(); markAsSpentErr != nil {
err = markAsSpentErr
switch len(transferOutput.consumers) {
case 0:
isConflicting = false
consumersToElevate = nil
err = transferOutput.markAsSpent()
case 1:
isConflicting = true
consumersToElevate = make(map[TransferHash][]AddressHash, 1)
for transferHash, addresses := range transferOutput.consumers {
consumersToElevate[transferHash] = addresses
}
err = nil
default:
isConflicting = true
consumersToElevate = nil
err = nil
}
consumers := make([]AddressHash, len(outputs))
i := 0
for addressHash, _ := range outputs {
consumers[i] = addressHash
i++
}
transferOutput.consumers[consumer] = void
transferOutput.consumers[consumer] = consumers
transferOutput.consumersMutex.Unlock()
}
return
}
func (transferOutput *TransferOutput) getConsumers() (consumers map[TransferHash]empty) {
transferOutput.consumersMutex.RLock()
consumers = transferOutput.consumers
transferOutput.consumersMutex.RUnlock()
func (transferOutput *TransferOutput) moveToReality(realityId RealityId) error {
transferOutput.bookingMutex.Lock()
return
currentBookingKey := generateTransferOutputBookingStorageKey(transferOutput.GetRealityId(), transferOutput.addressHash, len(transferOutput.consumers) >= 1, transferOutput.transferHash)
if oldTransferOutputBooking, err := transferOutput.ledgerState.transferOutputBookings.Load(currentBookingKey); err != nil {
transferOutput.bookingMutex.Unlock()
return err
} else {
transferOutput.ledgerState.storeTransferOutputBooking(newTransferOutputBooking(realityId, transferOutput.addressHash, len(transferOutput.consumers) >= 1, transferOutput.transferHash)).Release()
oldTransferOutputBooking.Delete().Release()
}
transferOutput.bookingMutex.Unlock()
return nil
}
func (transferOutput *TransferOutput) markAsSpent() error {
currentBookingKey := generateTransferOutputBookingStorageKey(transferOutput.realityId, transferOutput.addressHash, false, transferOutput.transferHash)
transferOutput.bookingMutex.Lock()
currentBookingKey := generateTransferOutputBookingStorageKey(transferOutput.GetRealityId(), transferOutput.addressHash, false, transferOutput.transferHash)
if oldTransferOutputBooking, err := transferOutput.ledgerState.transferOutputBookings.Load(currentBookingKey); err != nil {
transferOutput.bookingMutex.Unlock()
if cachedTransferOutputBooking, err := transferOutput.ledgerState.transferOutputBookings.Load(currentBookingKey); err != nil {
return err
} else if !cachedTransferOutputBooking.Exists() {
return errors.New("could not find TransferOutputBooking")
} else {
transferOutputBooking := cachedTransferOutputBooking.Get().(*TransferOutputBooking)
transferOutput.ledgerState.storeTransferOutputBooking(newTransferOutputBooking(transferOutputBooking.GetRealityId(), transferOutputBooking.GetAddressHash(), true, transferOutputBooking.GetTransferHash())).Release()
transferOutput.ledgerState.storeTransferOutputBooking(newTransferOutputBooking(transferOutput.GetRealityId(), transferOutput.addressHash, true, transferOutput.transferHash)).Release()
cachedTransferOutputBooking.Delete()
cachedTransferOutputBooking.Release()
oldTransferOutputBooking.Delete().Release()
}
transferOutput.bookingMutex.Unlock()
return nil
}
......@@ -137,9 +177,18 @@ func (transferOutput *TransferOutput) MarshalBinary() ([]byte, error) {
offset := realityIdLength + 4 + balanceCount*coloredBalanceLength
binary.LittleEndian.PutUint32(result[offset:], uint32(consumerCount))
offset += 4
for consumer := range transferOutput.consumers {
copy(result[offset:], consumer[:transferHashLength])
for transferHash, addresses := range transferOutput.consumers {
copy(result[offset:], transferHash[:transferHashLength])
offset += transferHashLength
binary.LittleEndian.PutUint32(result[offset:], uint32(len(addresses)))
offset += 4
for _, addressHash := range addresses {
copy(result[offset:], addressHash[:addressHashLength])
offset += addressHashLength
}
}
return result, nil
......@@ -189,17 +238,33 @@ func (transferOutput *TransferOutput) unmarshalBalances(serializedBalances []byt
return balances, nil
}
func (transferOutput *TransferOutput) unmarshalConsumers(serializedConsumers []byte) (map[TransferHash]empty, error) {
consumerCount := int(binary.LittleEndian.Uint32(serializedConsumers))
func (transferOutput *TransferOutput) unmarshalConsumers(serializedConsumers []byte) (map[TransferHash][]AddressHash, error) {
offset := 0
consumers := make(map[TransferHash]empty, consumerCount)
consumerCount := int(binary.LittleEndian.Uint32(serializedConsumers[offset:]))
offset += 4
consumers := make(map[TransferHash][]AddressHash, consumerCount)
for i := 0; i < consumerCount; i++ {
transferHash := TransferHash{}
if err := transferHash.UnmarshalBinary(serializedConsumers[4+i*transferHashLength:]); err != nil {
if err := transferHash.UnmarshalBinary(serializedConsumers[offset:]); err != nil {
return nil, err
}
offset += transferHashLength
addressHashCount := int(binary.LittleEndian.Uint32(serializedConsumers[offset:]))
offset += 4
consumers[transferHash] = void
consumers[transferHash] = make([]AddressHash, addressHashCount)
for i := 0; i < addressHashCount; i++ {
addressHash := AddressHash{}
if err := addressHash.UnmarshalBinary(serializedConsumers[offset:]); err != nil {
return nil, err
}
offset += addressHashLength
consumers[transferHash][i] = addressHash
}
}
return consumers, nil
......
......@@ -3,5 +3,5 @@ package ledgerstate
// empty structs consume 0 memory and are therefore better in map based set implementations that i.e. bool
type empty struct{}
// void represents an empty value that consumed 0 memory
// void represents an empty value that consumes 0 memory
var void empty
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment