diff --git a/go.mod b/go.mod index 98fab30bc27e2ea7add0b2f062232c8f2191f4fc..dc7473f91ded16226ddffa67e57279919cf436d4 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/ethereum/go-ethereum v1.8.27 github.com/gdamore/tcell v1.1.2 github.com/go-zeromq/zmq4 v0.4.0 - github.com/golang/protobuf v1.3.1 // indirect + github.com/golang/protobuf v1.3.1 github.com/google/open-location-code/go v0.0.0-20190603181809-cf814bded323 github.com/iotaledger/iota.go v1.0.0-beta.6 github.com/labstack/echo v3.3.10+incompatible diff --git a/packages/mana/balance.go b/packages/mana/balance.go index 49b8a313e79e5c4debd7a9de72a052bb75b82601..b3fc2c5abadcfa94e32ea328540b6d9a7c0dadd0 100644 --- a/packages/mana/balance.go +++ b/packages/mana/balance.go @@ -163,7 +163,7 @@ func (balance *Balance) applyTransfer(transfer *Transfer) { // calculate mana gains var gainedMana uint64 for _, input := range transfer.inputs { - generatedMana, _ := balance.calculator.GenerateMana(input.coinAmount, transfer.spentTime-input.receivedTime) + generatedMana, _ := balance.calculator.GenerateMana(input.GetCoinAmount(), transfer.spentTime-input.GetReceivedTime()) gainedMana += generatedMana } diff --git a/packages/mana/balance_test.go b/packages/mana/balance_test.go index 65e5a3d3f2d135d0cbdd17c5c775c9a816cd0d75..f7c384b04f1f018a7f8f284757f9f71cd00f9213 100644 --- a/packages/mana/balance_test.go +++ b/packages/mana/balance_test.go @@ -13,26 +13,17 @@ func TestBalance_CleanupTransferHistory(t *testing.T) { // fill transfer history balance1 := NewBalance(calculator) balance1.BookTransfer(&Transfer{ - inputs: []*Input{{ - coinAmount: 1000, - receivedTime: 1000, - }}, + inputs: []*Input{NewInput(1000, 1000)}, spentTime: 1700, burnedMana: 10, }) balance1.BookTransfer(&Transfer{ - inputs: []*Input{{ - coinAmount: 1000, - receivedTime: 700, - }}, + inputs: []*Input{NewInput(1000, 700)}, spentTime: 1000, burnedMana: 0, }) balance1.BookTransfer(&Transfer{ - inputs: []*Input{{ - coinAmount: 1000, - receivedTime: 0, - }}, + inputs: []*Input{NewInput(1000, 0)}, spentTime: 700, burnedMana: 0, }) @@ -62,26 +53,17 @@ func TestBalance_AddTransfer(t *testing.T) { // spend coins multiple times balance1 := NewBalance(calculator) balance1.BookTransfer(&Transfer{ - inputs: []*Input{{ - coinAmount: 1000, - receivedTime: 1000, - }}, + inputs: []*Input{NewInput(1000, 1000)}, spentTime: 1700, burnedMana: 10, }) balance1.BookTransfer(&Transfer{ - inputs: []*Input{{ - coinAmount: 1000, - receivedTime: 700, - }}, + inputs: []*Input{NewInput(1000, 700)}, spentTime: 1000, burnedMana: 0, }) balance1.BookTransfer(&Transfer{ - inputs: []*Input{{ - coinAmount: 1000, - receivedTime: 0, - }}, + inputs: []*Input{NewInput(1000, 0)}, spentTime: 700, burnedMana: 0, }) @@ -89,10 +71,7 @@ func TestBalance_AddTransfer(t *testing.T) { // hold coins for the full time balance2 := NewBalance(calculator) balance2.BookTransfer(&Transfer{ - inputs: []*Input{{ - coinAmount: 1000, - receivedTime: 0, - }}, + inputs: []*Input{NewInput(1000, 0)}, spentTime: 1700, burnedMana: 10, }) diff --git a/packages/mana/errors.go b/packages/mana/errors.go index 258f8407ab2c2c82426834bb698968581dbebb46..b049eeaef8dc9c3f2de9e32f3ef50aa9f8a4241d 100644 --- a/packages/mana/errors.go +++ b/packages/mana/errors.go @@ -5,5 +5,6 @@ import ( ) var ( - ErrUnmarshalFailed = errors.New("unmarshal failed") + ErrUnmarshalFailed = errors.Wrap(errors.New("unmarshal failed"), "unmarshal failed") + ErrMarshalFailed = errors.Wrap(errors.New("marshal failed"), "marshal failed") ) diff --git a/packages/mana/input.go b/packages/mana/input.go index c28916606ff75e80a0a338b31389870c4baf7c0e..320702c4eff35314be7f8da50f4cda9fa23e370e 100644 --- a/packages/mana/input.go +++ b/packages/mana/input.go @@ -1,76 +1,95 @@ package mana import ( - "encoding/binary" - "fmt" + "sync" - "github.com/iotaledger/goshimmer/packages/marshal" + "github.com/golang/protobuf/proto" "github.com/iotaledger/goshimmer/packages/errors" + manaproto "github.com/iotaledger/goshimmer/packages/mana/proto" ) type Input struct { - coinAmount uint64 - receivedTime uint64 + coinAmount uint64 + coinAmountMutex sync.RWMutex + receivedTime uint64 + receivedTimeMutex sync.RWMutex } -func (input *Input) MarshalBinary() (data []byte, err errors.IdentifiableError) { - data = inputSchema.Marshal(input) - - return -} - -func (input *Input) UnmarshalBinary(data []byte) (err errors.IdentifiableError) { - if len(data) < INPUT_TOTAL_MARSHALED_SIZE { - err = ErrUnmarshalFailed.Derive("byte sequence of marshaled input is not long enough") +func NewInput(coinAmount uint64, receivedTime uint64) *Input { + return &Input{ + coinAmount: coinAmount, + receivedTime: receivedTime, } - - input.coinAmount = binary.BigEndian.Uint64(data[INPUT_COIN_AMOUNT_BYTE_OFFSET_START:INPUT_COIN_AMOUNT_BYTE_OFFSET_END]) - input.receivedTime = binary.BigEndian.Uint64(data[INPUT_RECEIVED_TIME_BYTE_OFFSET_START:INPUT_RECEIVED_TIME_BYTE_OFFSET_END]) - - return } func (input *Input) GetCoinAmount() uint64 { - return input_getCoinAmount(input) + input.coinAmountMutex.RLock() + defer input.coinAmountMutex.RUnlock() + + return input.coinAmount } -func input_getCoinAmount(input interface{}) uint64 { - return input.(*Input).coinAmount +func (input *Input) SetCoinAmount(coinAmount uint64) { + input.coinAmountMutex.Lock() + defer input.coinAmountMutex.Unlock() + + input.coinAmount = coinAmount } -func input_setCoinAmount(input interface{}, coinAmount uint64) { - input.(*Input).coinAmount = coinAmount +func (input *Input) GetReceivedTime() uint64 { + input.receivedTimeMutex.RLock() + defer input.receivedTimeMutex.RUnlock() + + return input.receivedTime } -func input_getReceivedTime(input interface{}) uint64 { - return input.(*Input).receivedTime +func (input *Input) SetReceivedTime(receivedTime uint64) { + input.receivedTimeMutex.Lock() + defer input.receivedTimeMutex.Unlock() + + input.receivedTime = receivedTime } -func input_setReceivedTime(input interface{}, receivedTime uint64) { - input.(*Input).coinAmount = receivedTime +func (input *Input) ToProto() (result *manaproto.Input) { + input.receivedTimeMutex.RLock() + input.coinAmountMutex.RLock() + defer input.receivedTimeMutex.RUnlock() + defer input.coinAmountMutex.RUnlock() + + return &manaproto.Input{ + CoinAmount: input.coinAmount, + ReceivedTime: input.receivedTime, + } } -var inputSchema = marshal.Schema( - marshal.Uint64(input_getCoinAmount, input_setCoinAmount), - marshal.Uint64(input_getReceivedTime, input_setReceivedTime), -) +func (input *Input) FromProto(proto *manaproto.Input) { + input.receivedTimeMutex.Lock() + input.coinAmountMutex.Lock() + defer input.receivedTimeMutex.Unlock() + defer input.coinAmountMutex.Unlock() -func init() { - fmt.Println((&Input{ - coinAmount: 10, - receivedTime: 20, - }).MarshalBinary()) + input.coinAmount = proto.CoinAmount + input.receivedTime = proto.ReceivedTime } -const ( - INPUT_COIN_AMOUNT_BYTE_OFFSET_START = 0 - INPUT_COIN_AMOUNT_BYTE_OFFSET_LENGTH = 8 - INPUT_COIN_AMOUNT_BYTE_OFFSET_END = INPUT_COIN_AMOUNT_BYTE_OFFSET_START + INPUT_COIN_AMOUNT_BYTE_OFFSET_LENGTH +func (input *Input) MarshalBinary() (result []byte, err errors.IdentifiableError) { + if marshaledData, marshalErr := proto.Marshal(input.ToProto()); marshalErr != nil { + err = ErrMarshalFailed.Derive(marshalErr, "marshal failed") + } else { + result = marshaledData + } + + return +} - INPUT_RECEIVED_TIME_BYTE_OFFSET_START = INPUT_COIN_AMOUNT_BYTE_OFFSET_END - INPUT_RECEIVED_TIME_BYTE_OFFSET_LENGTH = 8 - INPUT_RECEIVED_TIME_BYTE_OFFSET_END = INPUT_RECEIVED_TIME_BYTE_OFFSET_START + INPUT_RECEIVED_TIME_BYTE_OFFSET_LENGTH +func (input *Input) UnmarshalBinary(data []byte) (err errors.IdentifiableError) { + var unmarshaledProto manaproto.Input + if unmarshalError := proto.Unmarshal(data, &unmarshaledProto); unmarshalError != nil { + err = ErrUnmarshalFailed.Derive(unmarshalError, "unmarshal failed") + } else { + input.FromProto(&unmarshaledProto) + } - INPUT_TOTAL_MARSHALED_SIZE = INPUT_RECEIVED_TIME_BYTE_OFFSET_END -) + return +} diff --git a/packages/mana/input_test.go b/packages/mana/input_test.go index 997f0223121cdf557e5e1bb89243e1cb3c9d0bc1..b78ea6f03b00430deb65f859d67befdf68abc98f 100644 --- a/packages/mana/input_test.go +++ b/packages/mana/input_test.go @@ -1,27 +1,31 @@ package mana import ( + "github.com/magiconair/properties/assert" "testing" ) -func BenchmarkDirectReceiver(b *testing.B) { - input := &Input{ - coinAmount: 10, - receivedTime: 0, - } +func TestInput_MarshalUnmarshalBinary(t *testing.T) { + // create original input + originalInput := NewInput(1337, 1338) - for i := 0; i < b.N; i++ { - input.GetCoinAmount() - } -} + // marshal + marshaledInput, err := originalInput.MarshalBinary() + if err != nil { + t.Error(err) -func BenchmarkManualReceiver(b *testing.B) { - input := &Input{ - coinAmount: 10, - receivedTime: 0, + return } - for i := 0; i < b.N; i++ { - input_getCoinAmount(input) + // unmarshal + var unmarshaledInput Input + if err := unmarshaledInput.UnmarshalBinary(marshaledInput); err != nil { + t.Error(err) + + return } + + // compare result + assert.Equal(t, unmarshaledInput.GetCoinAmount(), originalInput.GetCoinAmount()) + assert.Equal(t, unmarshaledInput.GetReceivedTime(), originalInput.GetReceivedTime()) } diff --git a/packages/mana/proto/input.pb.go b/packages/mana/proto/input.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..4c1e004d7f0004ae9d06e09da6197dd61c70a4f1 --- /dev/null +++ b/packages/mana/proto/input.pb.go @@ -0,0 +1,85 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: input.proto + +package proto + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Input struct { + CoinAmount uint64 `protobuf:"varint,1,opt,name=coinAmount,proto3" json:"coinAmount,omitempty"` + ReceivedTime uint64 `protobuf:"varint,2,opt,name=receivedTime,proto3" json:"receivedTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Input) Reset() { *m = Input{} } +func (m *Input) String() string { return proto.CompactTextString(m) } +func (*Input) ProtoMessage() {} +func (*Input) Descriptor() ([]byte, []int) { + return fileDescriptor_db6f7669dced820e, []int{0} +} + +func (m *Input) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Input.Unmarshal(m, b) +} +func (m *Input) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Input.Marshal(b, m, deterministic) +} +func (m *Input) XXX_Merge(src proto.Message) { + xxx_messageInfo_Input.Merge(m, src) +} +func (m *Input) XXX_Size() int { + return xxx_messageInfo_Input.Size(m) +} +func (m *Input) XXX_DiscardUnknown() { + xxx_messageInfo_Input.DiscardUnknown(m) +} + +var xxx_messageInfo_Input proto.InternalMessageInfo + +func (m *Input) GetCoinAmount() uint64 { + if m != nil { + return m.CoinAmount + } + return 0 +} + +func (m *Input) GetReceivedTime() uint64 { + if m != nil { + return m.ReceivedTime + } + return 0 +} + +func init() { + proto.RegisterType((*Input)(nil), "proto.Input") +} + +func init() { proto.RegisterFile("input.proto", fileDescriptor_db6f7669dced820e) } + +var fileDescriptor_db6f7669dced820e = []byte{ + // 98 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0xcc, 0x2b, 0x28, + 0x2d, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0xde, 0x5c, 0xac, 0x9e, + 0x20, 0x51, 0x21, 0x39, 0x2e, 0xae, 0xe4, 0xfc, 0xcc, 0x3c, 0xc7, 0xdc, 0xfc, 0xd2, 0xbc, 0x12, + 0x09, 0x46, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x24, 0x11, 0x21, 0x25, 0x2e, 0x9e, 0xa2, 0xd4, 0xe4, + 0xd4, 0xcc, 0xb2, 0xd4, 0x94, 0x90, 0xcc, 0xdc, 0x54, 0x09, 0x26, 0xb0, 0x0a, 0x14, 0xb1, 0x24, + 0x36, 0xb0, 0x99, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x69, 0x89, 0xbd, 0x69, 0x00, + 0x00, 0x00, +} diff --git a/packages/mana/proto/input.proto b/packages/mana/proto/input.proto new file mode 100644 index 0000000000000000000000000000000000000000..0b4f943d0825645c40961597f7f28862fe4682f8 --- /dev/null +++ b/packages/mana/proto/input.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package proto; + +message Input { + uint64 coinAmount = 1; + uint64 receivedTime = 2; +}; \ No newline at end of file diff --git a/packages/mana/proto/transfer.pb.go b/packages/mana/proto/transfer.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..8cc0fa7677de8230d1e3991449096fc425ba117f --- /dev/null +++ b/packages/mana/proto/transfer.pb.go @@ -0,0 +1,95 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: transfer.proto + +package proto + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Transfer struct { + Inputs []*Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` + SpentTime uint64 `protobuf:"varint,2,opt,name=spentTime,proto3" json:"spentTime,omitempty"` + BurnedMana uint64 `protobuf:"varint,3,opt,name=burnedMana,proto3" json:"burnedMana,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Transfer) Reset() { *m = Transfer{} } +func (m *Transfer) String() string { return proto.CompactTextString(m) } +func (*Transfer) ProtoMessage() {} +func (*Transfer) Descriptor() ([]byte, []int) { + return fileDescriptor_96c3e6bcafb460d3, []int{0} +} + +func (m *Transfer) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Transfer.Unmarshal(m, b) +} +func (m *Transfer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Transfer.Marshal(b, m, deterministic) +} +func (m *Transfer) XXX_Merge(src proto.Message) { + xxx_messageInfo_Transfer.Merge(m, src) +} +func (m *Transfer) XXX_Size() int { + return xxx_messageInfo_Transfer.Size(m) +} +func (m *Transfer) XXX_DiscardUnknown() { + xxx_messageInfo_Transfer.DiscardUnknown(m) +} + +var xxx_messageInfo_Transfer proto.InternalMessageInfo + +func (m *Transfer) GetInputs() []*Input { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *Transfer) GetSpentTime() uint64 { + if m != nil { + return m.SpentTime + } + return 0 +} + +func (m *Transfer) GetBurnedMana() uint64 { + if m != nil { + return m.BurnedMana + } + return 0 +} + +func init() { + proto.RegisterType((*Transfer)(nil), "proto.Transfer") +} + +func init() { proto.RegisterFile("transfer.proto", fileDescriptor_96c3e6bcafb460d3) } + +var fileDescriptor_96c3e6bcafb460d3 = []byte{ + // 130 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2b, 0x29, 0x4a, 0xcc, + 0x2b, 0x4e, 0x4b, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x52, 0xdc, + 0x99, 0x79, 0x05, 0xa5, 0x25, 0x10, 0x31, 0xa5, 0x3c, 0x2e, 0x8e, 0x10, 0xa8, 0x2a, 0x21, 0x15, + 0x2e, 0x36, 0xb0, 0x54, 0xb1, 0x04, 0xa3, 0x02, 0xb3, 0x06, 0xb7, 0x11, 0x0f, 0x44, 0x8d, 0x9e, + 0x27, 0x48, 0x30, 0x08, 0x2a, 0x27, 0x24, 0xc3, 0xc5, 0x59, 0x5c, 0x90, 0x9a, 0x57, 0x12, 0x92, + 0x99, 0x9b, 0x2a, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, 0x12, 0x84, 0x10, 0x10, 0x92, 0xe3, 0xe2, 0x4a, + 0x2a, 0x2d, 0xca, 0x4b, 0x4d, 0xf1, 0x4d, 0xcc, 0x4b, 0x94, 0x60, 0x06, 0x4b, 0x23, 0x89, 0x24, + 0xb1, 0x81, 0x8d, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x61, 0xd4, 0xdc, 0x02, 0x9c, 0x00, + 0x00, 0x00, +} diff --git a/packages/mana/proto/transfer.proto b/packages/mana/proto/transfer.proto new file mode 100644 index 0000000000000000000000000000000000000000..951014d04d104381cd5e1a50d43f79ba46f6e67a --- /dev/null +++ b/packages/mana/proto/transfer.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +import "input.proto"; + +package proto; + +message Transfer { + repeated Input inputs = 1; + uint64 spentTime = 2; + uint64 burnedMana = 3; +}; \ No newline at end of file diff --git a/packages/mana/transfer.go b/packages/mana/transfer.go index 212235a6a0030b65bded2bc141dc27d163beb4a2..1597a076e325dcaf31b1bf280ed82a14d4ee709a 100644 --- a/packages/mana/transfer.go +++ b/packages/mana/transfer.go @@ -1,31 +1,81 @@ package mana import ( + "sync" + + "github.com/iotaledger/goshimmer/packages/marshaling" + + "github.com/golang/protobuf/proto" "github.com/iotaledger/goshimmer/packages/errors" + manaproto "github.com/iotaledger/goshimmer/packages/mana/proto" ) type Transfer struct { - inputs []*Input - spentTime uint64 - burnedMana uint64 + inputs []*Input + inputsMutex sync.RWMutex + spentTime uint64 + spentTimeMutex sync.RWMutex + burnedMana uint64 + burnedManaMutex sync.RWMutex +} + +func NewTransfer(inputs []*Input, spentTime uint64, burnedMana uint64) *Transfer { + return &Transfer{ + inputs: inputs, + spentTime: spentTime, + burnedMana: burnedMana, + } } -func (transfer *Transfer) MarshalBinary() (data []byte, err errors.IdentifiableError) { - data = make([]byte, INPUT_TOTAL_MARSHALED_SIZE) +// Returns a protobuf representation of this transfer. +func (transfer *Transfer) ToProto() (result proto.Message) { + transfer.inputsMutex.RLock() + transfer.spentTimeMutex.RLock() + transfer.burnedManaMutex.RLock() + defer transfer.inputsMutex.RUnlock() + defer transfer.spentTimeMutex.RUnlock() + defer transfer.burnedManaMutex.RUnlock() - return + protoTransfer := &manaproto.Transfer{ + Inputs: make([]*manaproto.Input, len(transfer.inputs)), + SpentTime: transfer.spentTime, + BurnedMana: transfer.burnedMana, + } + + for i, input := range transfer.inputs { + protoTransfer.Inputs[i] = input.ToProto() + } + + return protoTransfer } -func (transfer *Transfer) UnmarshalBinary(data []byte) (err errors.IdentifiableError) { - return +// Restores the values from a protobuf representation of a transfer. +func (transfer *Transfer) FromProto(proto proto.Message) { + transfer.inputsMutex.Lock() + transfer.spentTimeMutex.Lock() + transfer.burnedManaMutex.Lock() + defer transfer.inputsMutex.Unlock() + defer transfer.spentTimeMutex.Unlock() + defer transfer.burnedManaMutex.Unlock() + + protoTransfer := proto.(*manaproto.Transfer) + + transfer.inputs = make([]*Input, len(protoTransfer.Inputs)) + transfer.spentTime = protoTransfer.SpentTime + transfer.burnedMana = protoTransfer.BurnedMana + + for i, protoInput := range protoTransfer.Inputs { + var input Input + input.FromProto(protoInput) + + transfer.inputs[i] = &input + } } -const ( - TRANSFER_SPENT_TIME_BYTE_OFFSET_START = 0 - TRANSFER_SPENT_TIME_BYTE_OFFSET_LENGTH = 8 - TRANSFER_SPENT_TIME_BYTE_OFFSET_END = TRANSFER_SPENT_TIME_BYTE_OFFSET_START + TRANSFER_SPENT_TIME_BYTE_OFFSET_LENGTH +func (transfer *Transfer) MarshalBinary() ([]byte, errors.IdentifiableError) { + return marshaling.Marshal(transfer) +} - TRANSFER_BURNED_MANA_BYTE_OFFSET_START = INPUT_COIN_AMOUNT_BYTE_OFFSET_END - TRANSFER_BURNED_MANA_BYTE_OFFSET_LENGTH = 8 - TRANSFER_BURNED_MANA_BYTE_OFFSET_END = INPUT_RECEIVED_TIME_BYTE_OFFSET_START + INPUT_RECEIVED_TIME_BYTE_OFFSET_LENGTH -) +func (transfer *Transfer) UnmarshalBinary(data []byte) (err errors.IdentifiableError) { + return marshaling.Unmarshal(transfer, &manaproto.Transfer{}, data) +} diff --git a/packages/mana/transfer_test.go b/packages/mana/transfer_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f8b9616b5bb5feea79416cff6b299d81204c4ac3 --- /dev/null +++ b/packages/mana/transfer_test.go @@ -0,0 +1,32 @@ +package mana + +import ( + "testing" + + "github.com/magiconair/properties/assert" +) + +func TestTransfer_MarshalUnmarshalBinary(t *testing.T) { + // create original input + originalTransfer := NewTransfer([]*Input{}, 1337, 1338) + + // marshal + marshaledTransfer, err := originalTransfer.MarshalBinary() + if err != nil { + t.Error(err) + + return + } + + // unmarshal + var unmarshaledTransfer Transfer + if err := unmarshaledTransfer.UnmarshalBinary(marshaledTransfer); err != nil { + t.Error(err) + + return + } + + // compare result + assert.Equal(t, unmarshaledTransfer.spentTime, originalTransfer.spentTime) + assert.Equal(t, unmarshaledTransfer.burnedMana, originalTransfer.burnedMana) +} diff --git a/packages/marshal/encoder.go b/packages/marshal/encoder.go deleted file mode 100644 index 86990dc67a1d18927a26d95eafaf326b9e092c93..0000000000000000000000000000000000000000 --- a/packages/marshal/encoder.go +++ /dev/null @@ -1,26 +0,0 @@ -package marshal - -type Field interface { - Get(obj interface{}) interface{} - Marshal(obj interface{}, data []byte) []byte -} - -type encoder struct { - fields []Field -} - -func Schema(fields ...Field) *encoder { - return &encoder{ - fields: fields, - } -} - -func (encoder *encoder) Marshal(obj interface{}) []byte { - result := make([]byte, 0) - - for _, field := range encoder.fields { - result = append(result, field.Marshal(field.Get(obj), result)...) - } - - return result -} diff --git a/packages/marshal/uint64.go b/packages/marshal/uint64.go deleted file mode 100644 index 5bdd83254b5e39f27ea028581a638c3cab0f1b7a..0000000000000000000000000000000000000000 --- a/packages/marshal/uint64.go +++ /dev/null @@ -1,32 +0,0 @@ -package marshal - -import ( - "encoding/binary" -) - -func Uint64(getter uint64Getter, setter uint64Setter) *uint64Field { - return &uint64Field{ - getter: getter, - setter: setter, - } -} - -type uint64Getter func(receiver interface{}) uint64 -type uint64Setter func(receiver interface{}, val uint64) - -type uint64Field struct { - getter uint64Getter - setter uint64Setter -} - -func (uint64Field *uint64Field) Marshal(obj interface{}, data []byte) (result []byte) { - result = make([]byte, 8) - - binary.BigEndian.PutUint64(result, obj.(uint64)) - - return -} - -func (uint64Field *uint64Field) Get(obj interface{}) interface{} { - return uint64Field.getter(obj) -} diff --git a/packages/marshaling/errors.go b/packages/marshaling/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..73b27016e283cb154bfd11cdab942e75243dd241 --- /dev/null +++ b/packages/marshaling/errors.go @@ -0,0 +1,8 @@ +package marshaling + +import "github.com/iotaledger/goshimmer/packages/errors" + +var ( + ErrUnmarshalFailed = errors.Wrap(errors.New("unmarshal failed"), "unmarshal failed") + ErrMarshalFailed = errors.Wrap(errors.New("marshal failed"), "marshal failed") +) diff --git a/packages/marshaling/marshal.go b/packages/marshaling/marshal.go new file mode 100644 index 0000000000000000000000000000000000000000..807a4f43bca376bcf5ad2da51b51c14ad1c8a049 --- /dev/null +++ b/packages/marshaling/marshal.go @@ -0,0 +1,16 @@ +package marshaling + +import ( + "github.com/golang/protobuf/proto" + "github.com/iotaledger/goshimmer/packages/errors" +) + +func Marshal(serializable Serializable) (result []byte, err errors.IdentifiableError) { + if marshaledData, marshalErr := proto.Marshal(serializable.ToProto()); marshalErr != nil { + err = ErrMarshalFailed.Derive(marshalErr, "marshal failed") + } else { + result = marshaledData + } + + return +} diff --git a/packages/marshaling/types.go b/packages/marshaling/types.go new file mode 100644 index 0000000000000000000000000000000000000000..2a56555c2fbf7a68c8580443365dba70e8930721 --- /dev/null +++ b/packages/marshaling/types.go @@ -0,0 +1,8 @@ +package marshaling + +import "github.com/golang/protobuf/proto" + +type Serializable interface { + ToProto() (result proto.Message) + FromProto(proto proto.Message) +} diff --git a/packages/marshaling/unmarshal.go b/packages/marshaling/unmarshal.go new file mode 100644 index 0000000000000000000000000000000000000000..e03f1757489bde2fccc8c0232101a6696d6c9d4e --- /dev/null +++ b/packages/marshaling/unmarshal.go @@ -0,0 +1,16 @@ +package marshaling + +import ( + "github.com/golang/protobuf/proto" + "github.com/iotaledger/goshimmer/packages/errors" +) + +func Unmarshal(serializable Serializable, protobuf proto.Message, data []byte) (err errors.IdentifiableError) { + if unmarshalError := proto.Unmarshal(data, protobuf); unmarshalError != nil { + err = ErrUnmarshalFailed.Derive(unmarshalError, "unmarshal failed") + } else { + serializable.FromProto(protobuf) + } + + return +}