Skip to content
Snippets Groups Projects
missingoutput.go 4.79 KiB
package tangle

import (
	"time"

	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address"
	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
	"github.com/iotaledger/hive.go/marshalutil"
	"github.com/iotaledger/hive.go/objectstorage"
)

// MissingOutputKeyPartitions defines the "layout" of the key. This enables prefix iterations in the objectstorage.
var MissingOutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, transaction.IDLength}...)

// MissingOutput represents an Output that was referenced by a Transaction, but that is missing in our object storage.
type MissingOutput struct {
	objectstorage.StorableObjectFlags

	outputID     transaction.OutputID
	missingSince time.Time
}

// NewMissingOutput creates a new MissingOutput object, that .
func NewMissingOutput(outputID transaction.OutputID) *MissingOutput {
	return &MissingOutput{
		outputID:     outputID,
		missingSince: time.Now(),
	}
}

// MissingOutputFromBytes unmarshals a MissingOutput from a sequence of bytes - it either creates a new object or fills
// the optionally provided one with the parsed information.
func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, consumedBytes int, err error) {
	marshalUtil := marshalutil.New(bytes)
	result, err = ParseMissingOutput(marshalUtil, optionalTargetObject...)
	consumedBytes = marshalUtil.ReadOffset()

	return
}

// ParseMissingOutput unmarshals a MissingOutput using the given marshalUtil (for easier marshaling/unmarshaling).
func ParseMissingOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error) {
	parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) {
		return MissingOutputFromStorageKey(data, optionalTargetObject...)
	})
	if parseErr != nil {
		err = parseErr

		return
	}

	result = parsedObject.(*MissingOutput)
	_, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) {
		parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data)

		return
	})

	return
}

// MissingOutputFromStorageKey gets called when we restore a MissingOutput from the storage. The content will be
// unmarshaled by an external caller using the binary.ObjectStorageValue interface.
func MissingOutputFromStorageKey(key []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, consumedBytes int, err error) {
	// determine the target object that will hold the unmarshaled information
	switch len(optionalTargetObject) {
	case 0:
		result = &MissingOutput{}
	case 1:
		result = optionalTargetObject[0]
	default:
		panic("too many arguments in call to MissingOutputFromStorageKey")
	}

	// parse the properties that are stored in the key
	marshalUtil := marshalutil.New(key)
	if result.outputID, err = transaction.ParseOutputID(marshalUtil); err != nil {
		return
	}

	return
}

// ID returns the id of the Output that is missing.
func (missingOutput *MissingOutput) ID() transaction.OutputID {
	return missingOutput.outputID
}

// MissingSince returns the Time since the transaction was first reported as being missing.
func (missingOutput *MissingOutput) MissingSince() time.Time {
	return missingOutput.missingSince
}

// Bytes marshals the MissingOutput into a sequence of bytes.
func (missingOutput *MissingOutput) Bytes() []byte {
	return marshalutil.New(transaction.OutputIDLength + marshalutil.TIME_SIZE).
		WriteBytes(missingOutput.ObjectStorageKey()).
		WriteBytes(missingOutput.ObjectStorageValue()).
		Bytes()
}

// ObjectStorageKey returns the key that is used to store the object in the object storage.
func (missingOutput *MissingOutput) ObjectStorageKey() []byte {
	return missingOutput.outputID.Bytes()
}

// ObjectStorageValue returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler
// interface.
func (missingOutput *MissingOutput) ObjectStorageValue() []byte {
	return marshalutil.New(marshalutil.TIME_SIZE).
		WriteTime(missingOutput.MissingSince()).
		Bytes()
}

// UnmarshalObjectStorageValue restores the values of a MissingOutput from a sequence of bytes using the  encoding.BinaryUnmarshaler
// interface.
func (missingOutput *MissingOutput) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) {
	marshalUtil := marshalutil.New(data)
	if missingOutput.missingSince, err = marshalUtil.ReadTime(); err != nil {
		return
	}
	consumedBytes = marshalUtil.ReadOffset()

	return
}

// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
func (missingOutput *MissingOutput) Update(other objectstorage.StorableObject) {
	panic("implement me")
}

// Interface contract: make compiler warn if the interface is not implemented correctly.
var _ objectstorage.StorableObject = &MissingOutput{}