Skip to content
Snippets Groups Projects
Unverified Commit aae4b1ec authored by Hans Moog's avatar Hans Moog Committed by GitHub
Browse files

Message refactor (#322)

* Feat: refactored message + started to add tests

* Refactor: go mod tidy

* Refactor: continued to refactor message

* Feat: updated to last hive.go + added Signature() methid

* Feat: go mod tidy

* Feat: added mutex to the signature write in Bytes()

* Fix: fixed Signature method

* Feat: refactored message methods

* Feat: refactored output

* Fix: fixed signature mismatch in tangle factory methods

* Refactor: go mod tidy

* Feat: added solditification logic to value tangle

* Feat: fixed some code related to objectstorage factories

* Feat: model refactor

* Fix: fixed a bug in the models of the valuetangle

* Feat: refactored storageprefix framework

* Feat: refactored some code

* Refactor: additional refactor in OS logic

* Refactor: refactored MissingPayload model

* Refactor: refactored further models
parent 24fbbae4
No related branches found
No related tags found
No related merge requests found
Showing
with 369 additions and 221 deletions
......@@ -10,7 +10,7 @@ require (
github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2
github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0
github.com/gorilla/websocket v1.4.1
github.com/iotaledger/hive.go v0.0.0-20200330121034-e4a505bcf2cd
github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0
github.com/iotaledger/iota.go v1.0.0-beta.14
github.com/labstack/echo v3.3.10+incompatible
github.com/labstack/gommon v0.3.0 // indirect
......
package tangle
const (
PrefixMessage byte = iota
PrefixMessageMetadata
PrefixApprovers
PrefixMissingMessage
)
......@@ -20,8 +20,6 @@ const (
)
type Tangle struct {
storageId []byte
messageStorage *objectstorage.ObjectStorage
messageMetadataStorage *objectstorage.ObjectStorage
approverStorage *objectstorage.ObjectStorage
......@@ -47,13 +45,14 @@ func missingMessageFactory(key []byte) (objectstorage.StorableObject, error, int
}
// Constructor for the tangle.
func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
func New(badgerInstance *badger.DB) (result *Tangle) {
osFactory := objectstorage.NewFactory(badgerInstance, storageprefix.MessageLayer)
result = &Tangle{
storageId: storageId,
messageStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0Message...), messageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
messageMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0MessageMetadata...), MessageMetadataFromStorageKey, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
approverStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0Approvers...), approverFactory, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(message.IdLength, message.IdLength), objectstorage.LeakDetectionEnabled(false)),
missingMessageStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0MissingMessage...), missingMessageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
messageStorage: osFactory.New(PrefixMessage, messageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
messageMetadataStorage: osFactory.New(PrefixMessageMetadata, MessageMetadataFromStorageKey, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
approverStorage: osFactory.New(PrefixApprovers, approverFactory, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(message.IdLength, message.IdLength), objectstorage.LeakDetectionEnabled(false)),
missingMessageStorage: osFactory.New(PrefixMissingMessage, missingMessageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
Events: *newEvents(),
}
......@@ -63,11 +62,6 @@ func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
return
}
// Returns the storage id of this tangle (can be used to create ontologies that follow the storage of the main tangle).
func (tangle *Tangle) StorageId() []byte {
return tangle.storageId
}
// Attaches a new transaction to the tangle.
func (tangle *Tangle) AttachMessage(transaction *message.Message) {
tangle.storeMessageWorkerPool.Submit(func() { tangle.storeMessageWorker(transaction) })
......
......@@ -24,7 +24,7 @@ func BenchmarkTangle_AttachTransaction(b *testing.B) {
// use the tempdir for the database
config.Node.Set(database.CFG_DIRECTORY, dir)
tangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE"))
tangle := New(database.GetBadgerInstance())
if err := tangle.Prune(); err != nil {
b.Error(err)
......@@ -55,7 +55,7 @@ func TestTangle_AttachTransaction(t *testing.T) {
// use the tempdir for the database
config.Node.Set(database.CFG_DIRECTORY, dir)
messageTangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE"))
messageTangle := New(database.GetBadgerInstance())
if err := messageTangle.Prune(); err != nil {
t.Error(err)
......
package storageprefix
var (
MainNet = []byte{0}
const (
// the following values are a list of prefixes defined as an enum
_ byte = iota
Layer0Message = []byte{1}
Layer0MessageMetadata = []byte{2}
Layer0Approvers = []byte{3}
Layer0MissingMessage = []byte{4}
ValueTransferPayload = []byte{5}
ValueTransferPayloadMetadata = []byte{6}
ValueTransferApprover = []byte{7}
ValueTransferMissingPayload = []byte{8}
ValueTransferAttachment = []byte{9}
ValueTransferConsumer = []byte{10}
ValueTangleOutputs = []byte{11}
LedgerStateTransferOutput = []byte{12}
LedgerStateTransferOutputBooking = []byte{13}
LedgerStateReality = []byte{14}
LedgerStateConflictSet = []byte{15}
// package specific prefixes used for the objectstorage in the corresponding packages
MessageLayer
ValueTransfers
)
......@@ -43,8 +43,16 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload,
return
}
func StorableObjectFromKey(key []byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
func FromStorageKey(key []byte, optionalTargetObject ...*Payload) (result *Payload, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
result = &Payload{}
case 1:
result = optionalTargetObject[0]
default:
panic("too many arguments in call to MissingPayloadFromStorageKey")
}
// parse the properties that are stored in the key
marshalUtil := marshalutil.New(key)
......@@ -53,7 +61,7 @@ func StorableObjectFromKey(key []byte) (result objectstorage.StorableObject, err
return
} else {
result.(*Payload).id = &payloadId
result.id = &payloadId
}
consumedBytes = marshalUtil.ReadOffset()
......@@ -127,7 +135,28 @@ func (payload *Payload) Transaction() *transaction.Transaction {
return payload.transaction
}
func (payload *Payload) Bytes() (bytes []byte) {
func (payload *Payload) Bytes() []byte {
return payload.ObjectStorageValue()
}
func (payload *Payload) String() string {
return stringify.Struct("Payload",
stringify.StructField("id", payload.Id()),
stringify.StructField("trunk", payload.TrunkId()),
stringify.StructField("branch", payload.BranchId()),
stringify.StructField("transfer", payload.Transaction()),
)
}
// region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
var Type = payload.Type(1)
func (payload *Payload) Type() payload.Type {
return Type
}
func (payload *Payload) ObjectStorageValue() (bytes []byte) {
// acquire lock for reading bytes
payload.bytesMutex.RLock()
......@@ -167,27 +196,6 @@ func (payload *Payload) Bytes() (bytes []byte) {
return
}
func (payload *Payload) String() string {
return stringify.Struct("Payload",
stringify.StructField("id", payload.Id()),
stringify.StructField("trunk", payload.TrunkId()),
stringify.StructField("branch", payload.BranchId()),
stringify.StructField("transfer", payload.Transaction()),
)
}
// region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
var Type = payload.Type(1)
func (payload *Payload) Type() payload.Type {
return Type
}
func (payload *Payload) ObjectStorageValue() []byte {
return payload.Bytes()
}
func (payload *Payload) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) {
marshalUtil := marshalutil.New(data)
......@@ -248,9 +256,7 @@ var _ payload.Payload = &Payload{}
// UnmarshalObjectStorageValue(data []byte) (err error) already implemented by Payload
func (payload *Payload) ObjectStorageKey() []byte {
id := payload.Id()
return id[:]
return payload.Id().Bytes()
}
func (payload *Payload) Update(other objectstorage.StorableObject) {
......
......@@ -36,6 +36,39 @@ func NewAttachment(transactionId transaction.Id, payloadId payload.Id) *Attachme
// AttachmentFromBytes unmarshals an Attachment from a sequence of bytes - it either creates a new object or fills the
// optionally provided one with the parsed information.
func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (result *Attachment, err error, consumedBytes int) {
marshalUtil := marshalutil.New(bytes)
result, err = ParseAttachment(marshalUtil, optionalTargetObject...)
consumedBytes = marshalUtil.ReadOffset()
return
}
// Parse is a wrapper for simplified unmarshaling of Attachments from a byte stream using the marshalUtil package.
func ParseAttachment(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Attachment) (result *Attachment, err error) {
if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
return AttachmentFromStorageKey(data, optionalTargetObject...)
}); parseErr != nil {
err = parseErr
return
} else {
result = parsedObject.(*Attachment)
}
if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
return
}); err != nil {
return
}
return
}
// AttachmentFromStorageKey gets called when we restore an Attachment from the storage - it parses the key bytes and
// returns the new object.
func AttachmentFromStorageKey(key []byte, optionalTargetObject ...*Attachment) (result *Attachment, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
......@@ -43,43 +76,23 @@ func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (res
case 1:
result = optionalTargetObject[0]
default:
panic("too many arguments in call to AttachmentFromBytes")
panic("too many arguments in call to AttachmentFromStorageKey")
}
// parse the bytes
marshalUtil := marshalutil.New(bytes)
// parse the properties that are stored in the key
marshalUtil := marshalutil.New(key)
if result.transactionId, err = transaction.ParseId(marshalUtil); err != nil {
return
}
if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
return
}
result.storageKey = marshalutil.New(bytes[:AttachmentLength]).Bytes(true)
consumedBytes = marshalUtil.ReadOffset()
result.storageKey = marshalutil.New(key[:consumedBytes]).Bytes(true)
return
}
// Parse is a wrapper for simplified unmarshaling of Attachments from a byte stream using the marshalUtil package.
func ParseAttachment(marshalUtil *marshalutil.MarshalUtil) (*Attachment, error) {
if attachment, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return AttachmentFromBytes(data) }); err != nil {
return nil, err
} else {
return attachment.(*Attachment), nil
}
}
// AttachmentFromStorageKey gets called when we restore an Attachment from the storage - it parses the key bytes and
// returns the new object.
func AttachmentFromStorageKey(keyBytes []byte) (objectstorage.StorableObject, error, int) {
result, err, _ := AttachmentFromBytes(keyBytes)
if err != nil {
return nil, err, 0
}
return result, nil, 0
}
// TransactionId returns the transaction id of this Attachment.
func (attachment *Attachment) TransactionId() transaction.Id {
return attachment.transactionId
......
......@@ -5,9 +5,12 @@ import (
"github.com/iotaledger/hive.go/objectstorage"
"github.com/iotaledger/hive.go/stringify"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
)
var ConsumerPartitionKeys = objectstorage.PartitionKey([]int{address.Length, transaction.IdLength, transaction.IdLength}...)
// Consumer stores the information which transaction output was consumed by which transaction. We need this to be able
// to perform reverse lookups from transaction outputs to their corresponding consuming transactions.
type Consumer struct {
......@@ -64,7 +67,7 @@ func ParseConsumer(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ..
return
}
func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (result objectstorage.StorableObject, err error, consumedBytes int) {
func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (result *Consumer, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
......@@ -77,14 +80,14 @@ func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (resu
// parse the properties that are stored in the key
marshalUtil := marshalutil.New(key)
if result.(*Consumer).consumedInput, err = transaction.ParseOutputId(marshalUtil); err != nil {
if result.consumedInput, err = transaction.ParseOutputId(marshalUtil); err != nil {
return
}
if result.(*Consumer).transactionId, err = transaction.ParseId(marshalUtil); err != nil {
if result.transactionId, err = transaction.ParseId(marshalUtil); err != nil {
return
}
result.(*Consumer).storageKey = marshalutil.New(key[:marshalUtil.ReadOffset()]).Bytes(true)
consumedBytes = marshalUtil.ReadOffset()
result.storageKey = marshalutil.New(key[:consumedBytes]).Bytes(true)
return
}
......
......@@ -6,9 +6,12 @@ import (
"github.com/iotaledger/hive.go/marshalutil"
"github.com/iotaledger/hive.go/objectstorage"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
)
var MissingOutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, transaction.IdLength}...)
// MissingPayload represents an Output that was referenced by a Transaction, but that is missing in our object storage.
type MissingOutput struct {
objectstorage.StorableObjectFlags
......@@ -28,40 +31,55 @@ func NewMissingOutput(outputId transaction.OutputId) *MissingOutput {
// 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, err error, consumedBytes int) {
// 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 MissingOutputFromBytes")
marshalUtil := marshalutil.New(bytes)
result, err = ParseMissingOutput(marshalUtil, optionalTargetObject...)
consumedBytes = marshalUtil.ReadOffset()
return
}
// parse the bytes
marshalUtil := marshalutil.New(bytes)
if result.outputId, err = transaction.ParseOutputId(marshalUtil); err != nil {
func ParseMissingOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error) {
if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
return MissingOutputFromStorageKey(data, optionalTargetObject...)
}); parseErr != nil {
err = parseErr
return
} else {
result = parsedObject.(*MissingOutput)
}
if result.missingSince, err = marshalUtil.ReadTime(); err != nil {
if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
return
}); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
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(keyBytes []byte) (objectstorage.StorableObject, error, int) {
outputId, err, _ := transaction.OutputIdFromBytes(keyBytes)
if err != nil {
panic(err)
func MissingOutputFromStorageKey(key []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error, consumedBytes int) {
// 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")
}
return &MissingOutput{
outputId: outputId,
}, nil, transaction.OutputIdLength
// 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.
......@@ -76,12 +94,10 @@ func (missingOutput *MissingOutput) MissingSince() time.Time {
// Bytes marshals the MissingOutput into a sequence of bytes.
func (missingOutput *MissingOutput) Bytes() []byte {
marshalUtil := marshalutil.New()
marshalUtil.WriteBytes(missingOutput.outputId.Bytes())
marshalUtil.WriteTime(missingOutput.missingSince)
return marshalUtil.Bytes()
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.
......@@ -92,13 +108,19 @@ func (missingOutput *MissingOutput) ObjectStorageKey() []byte {
// ObjectStorageValue returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler
// interface.
func (missingOutput *MissingOutput) ObjectStorageValue() []byte {
return missingOutput.Bytes()
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) (err error, consumedBytes int) {
_, err, consumedBytes = MissingOutputFromBytes(data, missingOutput)
marshalUtil := marshalutil.New(data)
if missingOutput.missingSince, err = marshalUtil.ReadTime(); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
return
}
......
......@@ -29,6 +29,38 @@ func NewMissingPayload(payloadId payload.Id) *MissingPayload {
// MissingPayloadFromBytes unmarshals an entry for a missing value transfer payload from a sequence of bytes.
// It either creates a new entry or fills the optionally provided one with the parsed information.
func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) {
marshalUtil := marshalutil.New(bytes)
result, err = ParseMissingPayload(marshalUtil, optionalTargetObject...)
consumedBytes = marshalUtil.ReadOffset()
return
}
func ParseMissingPayload(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error) {
if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
return MissingPayloadFromStorageKey(data, optionalTargetObject...)
}); parseErr != nil {
err = parseErr
return
} else {
result = parsedObject.(*MissingPayload)
}
if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
return
}); err != nil {
return
}
return
}
// MissingPayloadFromStorageKey gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and
// the content will be unmarshaled by an external caller using the binary.ObjectStorageValue interface.
func MissingPayloadFromStorageKey(key []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
......@@ -36,28 +68,19 @@ func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPaylo
case 1:
result = optionalTargetObject[0]
default:
panic("too many arguments in call to MissingPayloadFromBytes")
panic("too many arguments in call to MissingPayloadFromStorageKey")
}
// parse the bytes
marshalUtil := marshalutil.New(bytes)
// parse the properties that are stored in the key
marshalUtil := marshalutil.New(key)
if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
return
}
if result.missingSince, err = marshalUtil.ReadTime(); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
return
}
// MissingPayloadFromStorageKey gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and
// the content will be unmarshaled by an external caller using the binary.ObjectStorageValue interface.
func MissingPayloadFromStorageKey([]byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
return
}
// GetId returns the payload id, that is missing.
func (missingPayload *MissingPayload) GetId() payload.Id {
return missingPayload.payloadId
......@@ -70,12 +93,10 @@ func (missingPayload *MissingPayload) GetMissingSince() time.Time {
// Bytes marshals the missing payload into a sequence of bytes.
func (missingPayload *MissingPayload) Bytes() []byte {
marshalUtil := marshalutil.New()
marshalUtil.WriteBytes(missingPayload.payloadId.Bytes())
marshalUtil.WriteTime(missingPayload.missingSince)
return marshalUtil.Bytes()
return marshalutil.New(payload.IdLength + marshalutil.TIME_SIZE).
WriteBytes(missingPayload.ObjectStorageKey()).
WriteBytes(missingPayload.ObjectStorageValue()).
Bytes()
}
// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
......@@ -92,12 +113,18 @@ func (missingPayload *MissingPayload) ObjectStorageKey() []byte {
// ObjectStorageValue is required to match the encoding.BinaryMarshaler interface.
func (missingPayload *MissingPayload) ObjectStorageValue() (data []byte) {
return missingPayload.Bytes()
return marshalutil.New(marshalutil.TIME_SIZE).
WriteTime(missingPayload.missingSince).
Bytes()
}
// UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface.
func (missingPayload *MissingPayload) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) {
_, err, consumedBytes = MissingPayloadFromBytes(data, missingPayload)
marshalUtil := marshalutil.New(data)
if missingPayload.missingSince, err = marshalUtil.ReadTime(); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
return
}
......
package tangle
import (
"github.com/iotaledger/hive.go/objectstorage"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
)
const (
// the following values are a list of prefixes defined as an enum
_ byte = iota
// prefixes used for the objectstorage
osPayload
osPayloadMetadata
osMissingPayload
osApprover
osAttachment
osOutput
osMissingOutput
osConsumer
)
func osPayloadFactory(key []byte) (objectstorage.StorableObject, error, int) {
return payload.FromStorageKey(key)
}
func osPayloadMetadataFactory(key []byte) (objectstorage.StorableObject, error, int) {
return PayloadMetadataFromStorageKey(key)
}
func osMissingPayloadFactory(key []byte) (objectstorage.StorableObject, error, int) {
return MissingPayloadFromStorageKey(key)
}
func osPayloadApproverFactory(key []byte) (objectstorage.StorableObject, error, int) {
return PayloadApproverFromStorageKey(key)
}
func osAttachmentFactory(key []byte) (objectstorage.StorableObject, error, int) {
return AttachmentFromStorageKey(key)
}
func osOutputFactory(key []byte) (objectstorage.StorableObject, error, int) {
return transaction.OutputFromStorageKey(key)
}
func osMissingOutputFactory(key []byte) (objectstorage.StorableObject, error, int) {
return MissingOutputFromStorageKey(key)
}
func osConsumerFactory(key []byte) (objectstorage.StorableObject, error, int) {
return ConsumerFromStorageKey(key)
}
......@@ -31,28 +31,60 @@ func NewPayloadApprover(referencedPayload payload.Id, approvingPayload payload.I
}
}
// PayloadApproverFromStorageKey get's called when we restore transaction metadata from the storage.
// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalObjectStorageValue
// method.
func PayloadApproverFromStorageKey(idBytes []byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
marshalUtil := marshalutil.New(idBytes)
func PayloadApproverFromBytes(bytes []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error, consumedBytes int) {
marshalUtil := marshalutil.New(bytes)
result, err = ParsePayloadApprover(marshalUtil, optionalTargetObject...)
consumedBytes = marshalUtil.ReadOffset()
return
}
func ParsePayloadApprover(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error) {
if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
return PayloadApproverFromStorageKey(data, optionalTargetObject...)
}); parseErr != nil {
err = parseErr
referencedPayloadId, err := payload.ParseId(marshalUtil)
if err != nil {
return
} else {
result = parsedObject.(*PayloadApprover)
}
approvingPayloadId, err := payload.ParseId(marshalUtil)
if err != nil {
if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
return
}); err != nil {
return
}
result = &PayloadApprover{
referencedPayloadId: referencedPayloadId,
approvingPayloadId: approvingPayloadId,
storageKey: marshalUtil.Bytes(true),
return
}
// PayloadApproverFromStorageKey get's called when we restore transaction metadata from the storage.
// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalObjectStorageValue
// method.
func PayloadApproverFromStorageKey(key []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
result = &PayloadApprover{}
case 1:
result = optionalTargetObject[0]
default:
panic("too many arguments in call to PayloadApproverFromStorageKey")
}
// parse the properties that are stored in the key
marshalUtil := marshalutil.New(key)
if result.referencedPayloadId, err = payload.ParseId(marshalUtil); err != nil {
return
}
if result.approvingPayloadId, err = payload.ParseId(marshalUtil); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
result.storageKey = marshalutil.New(key[:consumedBytes]).Bytes(true)
return
}
......
......@@ -34,39 +34,52 @@ func NewPayloadMetadata(payloadId payload.Id) *PayloadMetadata {
// PayloadMetadataFromBytes unmarshals a container with the metadata of a value transfer payload from a sequence of bytes.
// It either creates a new container or fills the optionally provided container with the parsed information.
func PayloadMetadataFromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
result = &PayloadMetadata{}
case 1:
result = optionalTargetObject[0]
default:
panic("too many arguments in call to PayloadMetadataFromBytes")
}
// parse the bytes
marshalUtil := marshalutil.New(bytes)
if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
result, err = ParsePayloadMetadata(marshalUtil, optionalTargetObject...)
consumedBytes = marshalUtil.ReadOffset()
return
}
if result.solidificationTime, err = marshalUtil.ReadTime(); err != nil {
// ParsePayloadMetadata is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package.
func ParsePayloadMetadata(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error) {
if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
return PayloadMetadataFromStorageKey(data, optionalTargetObject...)
}); parseErr != nil {
err = parseErr
return
} else {
result = parsedObject.(*PayloadMetadata)
}
if result.solid, err = marshalUtil.ReadBool(); err != nil {
if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
return
}); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
return
}
// PayloadMetadataFromStorageKey gets called when we restore transaction metadata from the storage. The bytes and the content will be
// unmarshaled by an external caller using the binary.ObjectStorageValue interface.
func PayloadMetadataFromStorageKey(id []byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
func PayloadMetadataFromStorageKey(id []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
result = &PayloadMetadata{}
case 1:
result = optionalTargetObject[0]
default:
panic("too many arguments in call to PayloadMetadataFromStorageKey")
}
// parse the properties that are stored in the key
marshalUtil := marshalutil.New(id)
if result.(*PayloadMetadata).payloadId, err = payload.ParseId(marshalUtil); err != nil {
if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
......@@ -74,15 +87,6 @@ func PayloadMetadataFromStorageKey(id []byte) (result objectstorage.StorableObje
return
}
// ParsePayloadMetadata is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package.
func ParsePayloadMetadata(marshalUtil *marshalutil.MarshalUtil) (*PayloadMetadata, error) {
if payloadMetadata, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return PayloadMetadataFromBytes(data) }); err != nil {
return nil, err
} else {
return payloadMetadata.(*PayloadMetadata), nil
}
}
// GetPayloadId return the id of the payload that this metadata is associated to.
func (payloadMetadata *PayloadMetadata) GetPayloadId() payload.Id {
return payloadMetadata.payloadId
......@@ -136,13 +140,10 @@ func (payloadMetadata *PayloadMetadata) GetSoldificationTime() time.Time {
// Bytes marshals the metadata into a sequence of bytes.
func (payloadMetadata *PayloadMetadata) Bytes() []byte {
marshalUtil := marshalutil.New()
marshalUtil.WriteBytes(payloadMetadata.payloadId.Bytes())
marshalUtil.WriteTime(payloadMetadata.solidificationTime)
marshalUtil.WriteBool(payloadMetadata.solid)
return marshalUtil.Bytes()
return marshalutil.New(payload.IdLength + marshalutil.TIME_SIZE + marshalutil.BOOL_SIZE).
WriteBytes(payloadMetadata.ObjectStorageKey()).
WriteBytes(payloadMetadata.ObjectStorageValue()).
Bytes()
}
// String creates a human readable version of the metadata (for debug purposes).
......@@ -168,12 +169,22 @@ func (payloadMetadata *PayloadMetadata) Update(other objectstorage.StorableObjec
// ObjectStorageValue is required to match the encoding.BinaryMarshaler interface.
func (payloadMetadata *PayloadMetadata) ObjectStorageValue() []byte {
return payloadMetadata.Bytes()
return marshalutil.New(marshalutil.TIME_SIZE + marshalutil.BOOL_SIZE).
WriteTime(payloadMetadata.solidificationTime).
WriteBool(payloadMetadata.solid).
Bytes()
}
// UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface.
func (payloadMetadata *PayloadMetadata) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) {
_, err, consumedBytes = PayloadMetadataFromBytes(data, payloadMetadata)
marshalUtil := marshalutil.New(data)
if payloadMetadata.solidificationTime, err = marshalUtil.ReadTime(); err != nil {
return
}
if payloadMetadata.solid, err = marshalUtil.ReadBool(); err != nil {
return
}
consumedBytes = marshalUtil.ReadOffset()
return
}
......
......@@ -19,8 +19,6 @@ import (
// Tangle represents the value tangle that consists out of value payloads.
// It is an independent ontology, that lives inside the tangle.
type Tangle struct {
storageId []byte
payloadStorage *objectstorage.ObjectStorage
payloadMetadataStorage *objectstorage.ObjectStorage
approverStorage *objectstorage.ObjectStorage
......@@ -38,24 +36,21 @@ type Tangle struct {
cleanupWorkerPool async.WorkerPool
}
func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
result = &Tangle{
storageId: storageId,
func New(badgerInstance *badger.DB) (result *Tangle) {
osFactory := objectstorage.NewFactory(badgerInstance, storageprefix.ValueTransfers)
result = &Tangle{
// payload related storage
payloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayload...), payload.StorableObjectFromKey, objectstorage.CacheTime(time.Second)),
payloadMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayloadMetadata...), PayloadMetadataFromStorageKey, objectstorage.CacheTime(time.Second)),
missingPayloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingPayloadFromStorageKey, objectstorage.CacheTime(time.Second)),
approverStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferApprover...), PayloadApproverFromStorageKey, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)),
// transaction related storage
outputStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTangleOutputs...), outputFromStorageKey, objectstorage.PartitionKey(transaction.OutputKeyPartitions...), objectstorage.CacheTime(time.Second)),
missingOutputStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingOutputFromStorageKey, objectstorage.CacheTime(time.Second)),
consumerStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferConsumer...), consumerFromStorageKey, objectstorage.CacheTime(time.Second)),
attachmentStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferAttachment...), AttachmentFromStorageKey, objectstorage.CacheTime(time.Second)),
payloadStorage: osFactory.New(osPayload, osPayloadFactory, objectstorage.CacheTime(time.Second)),
payloadMetadataStorage: osFactory.New(osPayloadMetadata, osPayloadMetadataFactory, objectstorage.CacheTime(time.Second)),
missingPayloadStorage: osFactory.New(osMissingPayload, osMissingPayloadFactory, objectstorage.CacheTime(time.Second)),
approverStorage: osFactory.New(osApprover, osPayloadApproverFactory, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)),
// transaction related storage
attachmentStorage: osFactory.New(osAttachment, osAttachmentFactory, objectstorage.CacheTime(time.Second)),
outputStorage: osFactory.New(osOutput, osOutputFactory, transaction.OutputKeyPartitions, objectstorage.CacheTime(time.Second)),
missingOutputStorage: osFactory.New(osMissingOutput, osMissingOutputFactory, MissingOutputKeyPartitions, objectstorage.CacheTime(time.Second)),
consumerStorage: osFactory.New(osConsumer, osConsumerFactory, ConsumerPartitionKeys, objectstorage.CacheTime(time.Second)),
Events: *newEvents(),
}
......@@ -425,11 +420,3 @@ func (tangle *Tangle) isPayloadMarkedAsSolid(payloadId payload.Id) bool {
return true
}
func outputFromStorageKey(key []byte) (objectstorage.StorableObject, error, int) {
return transaction.OutputFromStorageKey(key)
}
func consumerFromStorageKey(key []byte) (objectstorage.StorableObject, error, int) {
return ConsumerFromStorageKey(key)
}
......@@ -45,7 +45,7 @@ func TestTangle_AttachPayload(t *testing.T) {
config.Node.Set(database.CFG_DIRECTORY, dir)
tangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE"))
tangle := New(database.GetBadgerInstance())
if err := tangle.Prune(); err != nil {
t.Error(err)
......
......@@ -11,7 +11,7 @@ import (
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance"
)
var OutputKeyPartitions = []int{address.Length, IdLength}
var OutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, IdLength}...)
// Output represents the output of a Transaction and contains the balances and the identifiers for this output.
type Output struct {
......@@ -76,7 +76,7 @@ func ParseOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*
// OutputFromStorageKey get's called when we restore a Output from the storage.
// In contrast to other database models, it unmarshals some information from the key so we simply store the key before
// it gets handed over to UnmarshalObjectStorageValue (by the ObjectStorage).
func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (result objectstorage.StorableObject, err error, consumedBytes int) {
func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (result *Output, err error, consumedBytes int) {
// determine the target object that will hold the unmarshaled information
switch len(optionalTargetObject) {
case 0:
......@@ -89,15 +89,15 @@ func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (res
// parse information
marshalUtil := marshalutil.New(keyBytes)
result.(*Output).address, err = address.Parse(marshalUtil)
result.address, err = address.Parse(marshalUtil)
if err != nil {
return
}
result.(*Output).transactionId, err = ParseId(marshalUtil)
result.transactionId, err = ParseId(marshalUtil)
if err != nil {
return
}
result.(*Output).storageKey = marshalutil.New(keyBytes[:OutputIdLength]).Bytes(true)
result.storageKey = marshalutil.New(keyBytes[:OutputIdLength]).Bytes(true)
consumedBytes = marshalUtil.ReadOffset()
return
......
......@@ -14,7 +14,6 @@ import (
"github.com/iotaledger/goshimmer/packages/binary/messagelayer/tipselector"
"github.com/iotaledger/goshimmer/packages/binary/messagelayer/transactionparser"
"github.com/iotaledger/goshimmer/packages/binary/messagelayer/transactionrequester"
"github.com/iotaledger/goshimmer/packages/binary/storageprefix"
"github.com/iotaledger/goshimmer/packages/database"
"github.com/iotaledger/goshimmer/packages/shutdown"
"github.com/iotaledger/goshimmer/plugins/autopeering/local"
......@@ -46,7 +45,7 @@ func configure(*node.Plugin) {
TransactionParser = transactionparser.New()
TransactionRequester = transactionrequester.New()
TipSelector = tipselector.New()
Tangle = tangle.New(database.GetBadgerInstance(), storageprefix.MainNet)
Tangle = tangle.New(database.GetBadgerInstance())
// Setup MessageFactory (behavior + logging))
MessageFactory = messagefactory.New(database.GetBadgerInstance(), local.GetInstance().LocalIdentity(), TipSelector, []byte(DB_SEQUENCE_NUMBER))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment