diff --git a/go.mod b/go.mod index aa3d705bcb4ec272cf43a25dde3e24f396368d2a..0dbff93702cc3c219d93d38413c19ea26a9cf060 100644 --- a/go.mod +++ b/go.mod @@ -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-20200305153009-d3408b2be05b + github.com/iotaledger/hive.go v0.0.0-20200316213914-76b7a4169e64 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 diff --git a/go.sum b/go.sum index d573f25b2ba5a39ed6bd477f703fe5b90044a923..18faf70e16059b5918e94f6078f178f1d63feba0 100644 --- a/go.sum +++ b/go.sum @@ -111,12 +111,8 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0 github.com/googollee/go-engine.io v1.4.1/go.mod h1:26oFqHsnuWIzNOM0T08x21eQOydBosKOCgK3tyhzPPI= github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2 h1:6LbNP1ft0muA4LgoPMvwbxFpVhsRAGimY0Rp+4L7Q1M= github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2/go.mod h1:iaugrHMOoal16IKAWvH6y6RrXXIzfOULxjNwvXBCV4o= -github.com/googollee/go-engine.io v1.4.3-0.20200220091802-9b2ab104b298 h1:mvWmnIGGum8tzT62pTdjxSxCMOyxE7qCToNijulH+zE= -github.com/googollee/go-engine.io v1.4.3-0.20200220091802-9b2ab104b298/go.mod h1:iaugrHMOoal16IKAWvH6y6RrXXIzfOULxjNwvXBCV4o= github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0 h1:7yrvhLv25w1vtVKrcg8CZAn4Pnkb6pzCAqnZ5y9O4q8= github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0/go.mod h1:yjlQxKcAZXZjpGwQVW/y1sgyL1ou+DdCpkswURDCRrU= -github.com/googollee/go-socket.io v1.4.3 h1:fdfTDEnr4YyO+ZM4W9qPKJijbxklcyoxzbmHP7LkQmQ= -github.com/googollee/go-socket.io v1.4.3/go.mod h1:MRKd5ouUDz3WpEDRnD44JEAytwK1utsJv59QJyjGCio= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= @@ -134,10 +130,8 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/iotaledger/hive.go v0.0.0-20200304073310-d71239623d46 h1:4v/lfoR5CiJKsG8HUuYeKbds+DPvpxxxSrKZYS7Qhrc= -github.com/iotaledger/hive.go v0.0.0-20200304073310-d71239623d46/go.mod h1:0LQvxKmfU4bcQcjYIAq3PRfsA5584U0AioAAas6/QU8= -github.com/iotaledger/hive.go v0.0.0-20200305153009-d3408b2be05b h1:TxHm2TTOG4Xgxdnp5qZsgXKCctnxdDeQgqT4NwPJPQ0= -github.com/iotaledger/hive.go v0.0.0-20200305153009-d3408b2be05b/go.mod h1:0LQvxKmfU4bcQcjYIAq3PRfsA5584U0AioAAas6/QU8= +github.com/iotaledger/hive.go v0.0.0-20200316213914-76b7a4169e64 h1:O+1g39PWKzskXCViRD07ePv6183gDbH81XoShbPTzuc= +github.com/iotaledger/hive.go v0.0.0-20200316213914-76b7a4169e64/go.mod h1:0LQvxKmfU4bcQcjYIAq3PRfsA5584U0AioAAas6/QU8= github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8= github.com/iotaledger/iota.go v1.0.0-beta.14 h1:Oeb28MfBuJEeXcGrLhTCJFtbsnc8y1u7xidsAmiOD5A= github.com/iotaledger/iota.go v1.0.0-beta.14/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8= diff --git a/packages/binary/identity/constants.go b/packages/binary/identity/constants.go deleted file mode 100644 index b8fb985060952f9cdca9bffc0a5b058f12b9d597..0000000000000000000000000000000000000000 --- a/packages/binary/identity/constants.go +++ /dev/null @@ -1,7 +0,0 @@ -package identity - -const ( - PublicKeySize = 32 - PrivateKeySize = 64 - SignatureSize = 64 -) diff --git a/packages/binary/identity/identity.go b/packages/binary/identity/identity.go deleted file mode 100644 index fd52c6f3ff73724dd4d2e9c9f17a738af25b09e3..0000000000000000000000000000000000000000 --- a/packages/binary/identity/identity.go +++ /dev/null @@ -1,48 +0,0 @@ -package identity - -import ( - "crypto/rand" - - "github.com/oasislabs/ed25519" -) - -type Identity struct { - Type Type - PublicKey []byte - PrivateKey []byte -} - -func New(publicKey []byte, optionalPrivateKey ...[]byte) *Identity { - this := &Identity{ - PublicKey: make([]byte, len(publicKey)), - } - - copy(this.PublicKey, publicKey) - - if len(optionalPrivateKey) == 0 { - this.Type = Public - } else { - this.Type = Private - this.PrivateKey = optionalPrivateKey[0] - } - - return this -} - -func Generate() *Identity { - if public, private, err := ed25519.GenerateKey(rand.Reader); err != nil { - panic(err) - } else { - return New(public, private) - } -} - -func (identity *Identity) Sign(data []byte) (sig []byte) { - sig = ed25519.Sign(identity.PrivateKey, data) - - return -} - -func (identity *Identity) VerifySignature(data []byte, signature []byte) bool { - return ed25519.Verify(identity.PublicKey, data, signature) -} diff --git a/packages/binary/identity/identity_test.go b/packages/binary/identity/identity_test.go deleted file mode 100644 index f5fc0d525240ef9d53eed0e5499b612e4398485a..0000000000000000000000000000000000000000 --- a/packages/binary/identity/identity_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package identity - -import ( - "sync" - "testing" - - "github.com/panjf2000/ants/v2" - - "github.com/stretchr/testify/assert" -) - -func BenchmarkIdentity_VerifySignature(b *testing.B) { - identity := Generate() - data := []byte("TESTDATA") - signature := identity.Sign(data) - - var wg sync.WaitGroup - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - wg.Add(1) - - _ = ants.Submit(func() { - identity.VerifySignature(data, signature) - - wg.Done() - }) - } - - wg.Wait() -} - -func Test(t *testing.T) { - identity := Generate() - - signature := identity.Sign([]byte("TESTDATA1")) - - assert.Equal(t, true, identity.VerifySignature([]byte("TESTDATA1"), signature)) - assert.Equal(t, false, identity.VerifySignature([]byte("TESTDATA2"), signature)) -} diff --git a/packages/binary/identity/type.go b/packages/binary/identity/type.go deleted file mode 100644 index cc207b0279d2b24bf0b86190431a3753f0b34124..0000000000000000000000000000000000000000 --- a/packages/binary/identity/type.go +++ /dev/null @@ -1,8 +0,0 @@ -package identity - -type Type int - -const ( - Private = Type(0) - Public = Type(1) -) diff --git a/packages/binary/marshalutil/marshalutil.bool.go b/packages/binary/marshalutil/marshalutil.bool.go new file mode 100644 index 0000000000000000000000000000000000000000..ab1467f13cd19330fa985206d6b5dc6daa175da9 --- /dev/null +++ b/packages/binary/marshalutil/marshalutil.bool.go @@ -0,0 +1,24 @@ +package marshalutil + +func (util *MarshalUtil) WriteBool(bool bool) { + writeEndOffset := util.expandWriteCapacity(1) + + if bool { + util.bytes[util.writeOffset] = 1 + } else { + util.bytes[util.writeOffset] = 0 + } + + util.WriteSeek(writeEndOffset) +} + +func (util *MarshalUtil) ReadBool() (bool, error) { + readEndOffset, err := util.checkReadCapacity(1) + if err != nil { + return false, err + } + + defer util.ReadSeek(readEndOffset) + + return util.bytes[util.readOffset] == 1, nil +} diff --git a/packages/binary/marshalutil/marshalutil.go b/packages/binary/marshalutil/marshalutil.go index f6e95e704af690b4f7cdc22fc0ec5a442e1ee722..87837b836e27401d660a2cd0db70364244d75a1b 100644 --- a/packages/binary/marshalutil/marshalutil.go +++ b/packages/binary/marshalutil/marshalutil.go @@ -71,7 +71,14 @@ func (util *MarshalUtil) ReadSeek(offset int) { } } -func (util *MarshalUtil) Bytes() []byte { +func (util *MarshalUtil) Bytes(clone ...bool) []byte { + if len(clone) >= 1 && clone[0] { + clone := make([]byte, util.size) + copy(clone, util.bytes) + + return clone + } + return util.bytes[:util.size] } diff --git a/packages/binary/marshalutil/marshalutil.time.go b/packages/binary/marshalutil/marshalutil.time.go new file mode 100644 index 0000000000000000000000000000000000000000..36633dd9d878dcf9d065dbe1b2a3272fe578a1d6 --- /dev/null +++ b/packages/binary/marshalutil/marshalutil.time.go @@ -0,0 +1,33 @@ +package marshalutil + +import ( + "time" +) + +// WriteTime marshals the given time into a sequence of bytes, that get appended to the internal buffer. +func (util *MarshalUtil) WriteTime(timeToWrite time.Time) { + nanoSeconds := timeToWrite.UnixNano() + + // the zero value of time translates to -6795364578871345152 + if nanoSeconds == -6795364578871345152 { + util.WriteInt64(0) + } else { + util.WriteInt64(timeToWrite.UnixNano()) + } +} + +// ReadTime unmarshals a time object from the internal read buffer. +func (util *MarshalUtil) ReadTime() (result time.Time, err error) { + nanoSeconds, err := util.ReadInt64() + if err != nil { + return + } + + if nanoSeconds == 0 { + result = time.Time{} + } else { + result = time.Unix(0, nanoSeconds) + } + + return +} diff --git a/packages/binary/marshalutil/marshalutil_test.go b/packages/binary/marshalutil/marshalutil_test.go index 4b38f69ceb12747fff314784bde35a9683f120e1..17605b2140af0de9c4673c264f9b7787f7c926ac 100644 --- a/packages/binary/marshalutil/marshalutil_test.go +++ b/packages/binary/marshalutil/marshalutil_test.go @@ -11,6 +11,7 @@ func Test(t *testing.T) { util.WriteBytes(make([]byte, UINT64_SIZE)) util.WriteInt64(-12) util.WriteUint64(38) + util.WriteUint64(38) fmt.Println(util.ReadBytes(UINT64_SIZE)) fmt.Println(util.ReadInt64()) diff --git a/packages/binary/signature/ed25119/private_key.go b/packages/binary/signature/ed25119/private_key.go index 89dc1a15ecc01f5b088a0aca871390dbbcbd101e..9885a64325cab2c1dccbb84ece58d1b7302856d2 100644 --- a/packages/binary/signature/ed25119/private_key.go +++ b/packages/binary/signature/ed25119/private_key.go @@ -1,11 +1,27 @@ package ed25119 import ( + "fmt" + "github.com/oasislabs/ed25519" ) type PrivateKey [PrivateKeySize]byte +func PrivateKeyFromBytes(bytes []byte) (result PrivateKey, err error, consumedBytes int) { + if len(bytes) < PrivateKeySize { + err = fmt.Errorf("bytes too short") + + return + } + + copy(result[:], bytes) + + consumedBytes = PrivateKeySize + + return +} + func (privateKey PrivateKey) Sign(data []byte) (result Signature) { copy(result[:], ed25519.Sign(privateKey[:], data)) diff --git a/packages/binary/signature/ed25119/public_key.go b/packages/binary/signature/ed25119/public_key.go index 9afe9766d147c05f17b1ce6f4c7f256fc18bbb05..f050f6ff274fc6bbb19f6a9dd1c105465fea551c 100644 --- a/packages/binary/signature/ed25119/public_key.go +++ b/packages/binary/signature/ed25119/public_key.go @@ -5,6 +5,8 @@ import ( "fmt" "github.com/oasislabs/ed25519" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" ) type PublicKey [PublicKeySize]byte @@ -23,10 +25,22 @@ func PublicKeyFromBytes(bytes []byte) (result PublicKey, err error, consumedByte return } +func ParsePublicKey(marshalUtil *marshalutil.MarshalUtil) (PublicKey, error) { + if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return PublicKeyFromBytes(data) }); err != nil { + return PublicKey{}, err + } else { + return id.(PublicKey), nil + } +} + func (publicKey PublicKey) VerifySignature(data []byte, signature Signature) bool { return ed25519.Verify(publicKey[:], data, signature[:]) } +func (publicKey PublicKey) Bytes() []byte { + return publicKey[:] +} + func (publicKey *PublicKey) UnmarshalBinary(bytes []byte) (err error) { if len(bytes) < PublicKeySize { return errors.New("not enough bytes") diff --git a/packages/binary/signature/ed25119/signature.go b/packages/binary/signature/ed25119/signature.go index d8a291eec642f9714b15160dd27ea3f8b40c5b0d..01a6750f7b62cb1c9b5653ef272bd9d4fee3c1b9 100644 --- a/packages/binary/signature/ed25119/signature.go +++ b/packages/binary/signature/ed25119/signature.go @@ -3,6 +3,8 @@ package ed25119 import ( "errors" "fmt" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" ) type Signature [SignatureSize]byte @@ -21,6 +23,18 @@ func SignatureFromBytes(bytes []byte) (result Signature, err error, consumedByte return } +func ParseSignature(marshalUtil *marshalutil.MarshalUtil) (Signature, error) { + if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return SignatureFromBytes(data) }); err != nil { + return Signature{}, err + } else { + return id.(Signature), nil + } +} + +func (signature Signature) Bytes() []byte { + return signature[:] +} + func (signature *Signature) UnmarshalBinary(bytes []byte) (err error) { if len(bytes) < SignatureSize { return errors.New("not enough bytes") diff --git a/packages/binary/spammer/spammer.go b/packages/binary/spammer/spammer.go index 945393339b7f04c57810cb224fa7d23660a81ee2..f41499e28aaae3c84f06b3249d7a0a1efe1e8fba 100644 --- a/packages/binary/spammer/spammer.go +++ b/packages/binary/spammer/spammer.go @@ -1,13 +1,12 @@ package spammer import ( - "fmt" "sync/atomic" "time" "github.com/iotaledger/hive.go/types" - "github.com/iotaledger/goshimmer/packages/binary/identity" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" "github.com/iotaledger/goshimmer/packages/binary/tangle/tipselector" @@ -43,7 +42,7 @@ func (spammer *Spammer) Shutdown() { } func (spammer *Spammer) run(tps int, processId int64) { - fmt.Println(processId) + spammingIdentity := ed25119.GenerateKeyPair() currentSentCounter := 0 start := time.Now() @@ -54,7 +53,7 @@ func (spammer *Spammer) run(tps int, processId int64) { trunkTransactionId, branchTransactionId := spammer.tipSelector.GetTips() spammer.transactionParser.Parse( - transaction.New(trunkTransactionId, branchTransactionId, identity.Generate(), data.New([]byte("SPAM"))).GetBytes(), + transaction.New(trunkTransactionId, branchTransactionId, spammingIdentity, data.New([]byte("SPAM"))).Bytes(), nil, ) @@ -74,7 +73,7 @@ func (spammer *Spammer) run(tps int, processId int64) { } func (spammer *Spammer) sendBurst(transactions int, processId int64) { - spammingIdentity := identity.Generate() + spammingIdentity := ed25119.GenerateKeyPair() previousTransactionId := transaction.EmptyId @@ -86,7 +85,7 @@ func (spammer *Spammer) sendBurst(transactions int, processId int64) { spamTransaction := transaction.New(previousTransactionId, previousTransactionId, spammingIdentity, data.New([]byte("SPAM"))) previousTransactionId = spamTransaction.GetId() - burstBuffer[i] = spamTransaction.GetBytes() + burstBuffer[i] = spamTransaction.Bytes() } for i := 0; i < transactions; i++ { diff --git a/packages/binary/storageprefix/storageprefix.go b/packages/binary/storageprefix/storageprefix.go index fc9a8a21990a5bfaf13c435f9949b73d5a90e6c4..d288fb2db1a15ff0d9245d8c2f8748d401534acc 100644 --- a/packages/binary/storageprefix/storageprefix.go +++ b/packages/binary/storageprefix/storageprefix.go @@ -8,12 +8,13 @@ var ( TangleApprovers = []byte{3} TangleMissingTransaction = []byte{4} - ValueTangleTransferMetadata = []byte{5} - ValueTangleConsumers = []byte{6} - ValueTangleMissingTransfers = []byte{7} + ValueTransferPayload = []byte{5} + ValueTransferPayloadMetadata = []byte{6} + ValueTransferApprover = []byte{7} + ValueTransferMissingPayload = []byte{8} - LedgerStateTransferOutput = []byte{8} - LedgerStateTransferOutputBooking = []byte{9} - LedgerStateReality = []byte{10} - LedgerStateConflictSet = []byte{11} + LedgerStateTransferOutput = []byte{9} + LedgerStateTransferOutputBooking = []byte{10} + LedgerStateReality = []byte{11} + LedgerStateConflictSet = []byte{12} ) diff --git a/packages/binary/tangle/model/transaction/id.go b/packages/binary/tangle/model/transaction/id.go index 03c17fa2b4a9a03ed11dbb23d6a203a479f40f96..c7a9319090879ecaa52812d2887c72a52dca71d7 100644 --- a/packages/binary/tangle/model/transaction/id.go +++ b/packages/binary/tangle/model/transaction/id.go @@ -4,6 +4,8 @@ import ( "fmt" "github.com/mr-tron/base58" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" ) type Id [IdLength]byte @@ -41,6 +43,15 @@ func IdFromBytes(bytes []byte) (result Id, err error, consumedBytes int) { return } +// ParseId is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func ParseId(marshalUtil *marshalutil.MarshalUtil) (Id, error) { + if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return IdFromBytes(data) }); err != nil { + return Id{}, err + } else { + return id.(Id), nil + } +} + func (id *Id) MarshalBinary() (result []byte, err error) { return id.Bytes(), nil } diff --git a/packages/binary/tangle/model/transaction/payload/data/data.go b/packages/binary/tangle/model/transaction/payload/data/data.go index 84bc43b7da9be36c6479f5381dbab6bec64ffc79..3c971c20c30459ef8d84d1ce2c3c012309e36409 100644 --- a/packages/binary/tangle/model/transaction/payload/data/data.go +++ b/packages/binary/tangle/model/transaction/payload/data/data.go @@ -36,7 +36,18 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Data) (result *Data, err e marshalUtil := marshalutil.New(bytes) // read data - result.data = marshalUtil.ReadRemainingBytes() + result.payloadType, err = marshalUtil.ReadUint32() + if err != nil { + return + } + payloadBytes, err := marshalUtil.ReadUint32() + if err != nil { + return + } + result.data, err = marshalUtil.ReadBytes(int(payloadBytes)) + if err != nil { + return + } // return the number of bytes we processed consumedBytes = marshalUtil.ReadOffset() @@ -57,7 +68,9 @@ func (dataPayload *Data) Bytes() []byte { // initialize helper marshalUtil := marshalutil.New() - // write the data as raw bytes + // marshal the payload specific information + marshalUtil.WriteUint32(dataPayload.GetType()) + marshalUtil.WriteUint32(uint32(len(dataPayload.data))) marshalUtil.WriteBytes(dataPayload.data[:]) // return result diff --git a/packages/binary/tangle/model/transaction/payload/payload.go b/packages/binary/tangle/model/transaction/payload/payload.go index 2d570a886866aa0cecc5972e420b1c76fb593c17..06d0d43912b9889493f0a8ba1d72cf7adaed5fec 100644 --- a/packages/binary/tangle/model/transaction/payload/payload.go +++ b/packages/binary/tangle/model/transaction/payload/payload.go @@ -2,6 +2,8 @@ package payload import ( "encoding" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" ) type Payload interface { @@ -12,3 +14,42 @@ type Payload interface { GetType() Type String() string } + +// FromBytes unmarshals a public identity from a sequence of bytes. +func FromBytes(bytes []byte) (result Payload, err error, consumedBytes int) { + // initialize helper + marshalUtil := marshalutil.New(bytes) + + // calculate result + payloadType, err := marshalUtil.ReadUint32() + if err != nil { + return + } + payloadSize, err := marshalUtil.ReadUint32() + if err != nil { + return + } + marshalUtil.ReadSeek(marshalUtil.ReadOffset() - marshalutil.UINT32_SIZE*2) + payloadBytes, err := marshalUtil.ReadBytes(int(payloadSize) + 8) + if err != nil { + return + } + result, err = GetUnmarshaler(payloadType)(payloadBytes) + if err != nil { + return + } + + // return the number of bytes we processed + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func Parse(marshalUtil *marshalutil.MarshalUtil) (Payload, error) { + if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { + return nil, err + } else { + return payload.(Payload), nil + } +} diff --git a/packages/binary/tangle/model/transaction/test/transaction_test.go b/packages/binary/tangle/model/transaction/test/transaction_test.go index fdac283ef304d95d19311ea4017a5e00aa49e999..0d88e5d6954c6b3de751016bcd89d8e927f8661c 100644 --- a/packages/binary/tangle/model/transaction/test/transaction_test.go +++ b/packages/binary/tangle/model/transaction/test/transaction_test.go @@ -9,7 +9,7 @@ import ( "github.com/panjf2000/ants/v2" - "github.com/iotaledger/goshimmer/packages/binary/identity" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" ) @@ -20,7 +20,7 @@ func BenchmarkVerifyDataTransactions(b *testing.B) { transactions := make([][]byte, b.N) for i := 0; i < b.N; i++ { - tx := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data"))) + tx := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), data.New([]byte("some data"))) if marshaledTransaction, err := tx.MarshalBinary(); err != nil { b.Error(err) @@ -50,8 +50,8 @@ func BenchmarkVerifySignature(b *testing.B) { transactions := make([]*transaction.Transaction, b.N) for i := 0; i < b.N; i++ { - transactions[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("test"))) - transactions[i].GetBytes() + transactions[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), data.New([]byte("test"))) + transactions[i].Bytes() } var wg sync.WaitGroup diff --git a/packages/binary/tangle/model/transaction/transaction.go b/packages/binary/tangle/model/transaction/transaction.go index 5e662b83c3aa2e8e6bf5a1a9e1d06a20fd94a43f..4abed904ff65a5cdea8e5bec1017ca1a69d2452a 100644 --- a/packages/binary/tangle/model/transaction/transaction.go +++ b/packages/binary/tangle/model/transaction/transaction.go @@ -5,8 +5,8 @@ import ( "github.com/iotaledger/hive.go/stringify" - "github.com/iotaledger/goshimmer/packages/binary/identity" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" "github.com/iotaledger/hive.go/objectstorage" @@ -23,11 +23,11 @@ type Transaction struct { // core properties (they are part of the transaction when being sent) trunkTransactionId Id branchTransactionId Id - issuer *identity.Identity + issuerPublicKey ed25119.PublicKey payload payload.Payload bytes []byte bytesMutex sync.RWMutex - signature [identity.SignatureSize]byte + signature ed25119.Signature signatureMutex sync.RWMutex // derived properties @@ -35,14 +35,18 @@ type Transaction struct { idMutex sync.RWMutex payloadId *payload.Id payloadIdMutex sync.RWMutex + + // only stored on the machine of the signer + issuerPrivateKey ed25119.PrivateKey } // Allows us to "issue" a transaction. -func New(trunkTransactionId Id, branchTransactionId Id, issuer *identity.Identity, payload payload.Payload) (result *Transaction) { +func New(trunkTransactionId Id, branchTransactionId Id, issuerKeyPair ed25119.KeyPair, payload payload.Payload) (result *Transaction) { return &Transaction{ trunkTransactionId: trunkTransactionId, branchTransactionId: branchTransactionId, - issuer: issuer, + issuerPublicKey: issuerKeyPair.PublicKey, + issuerPrivateKey: issuerKeyPair.PrivateKey, payload: payload, } } @@ -74,61 +78,38 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Transaction) (result *Tran // initialize helper marshalUtil := marshalutil.New(bytes) - // read trunk transaction id - trunkTransactionId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return IdFromBytes(data) }) - if err != nil { + // parse information + if result.trunkTransactionId, err = ParseId(marshalUtil); err != nil { return } - result.trunkTransactionId = trunkTransactionId.(Id) - - // read branch transaction id - branchTransactionId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return IdFromBytes(data) }) - if err != nil { + if result.branchTransactionId, err = ParseId(marshalUtil); err != nil { return } - result.branchTransactionId = branchTransactionId.(Id) - - // read issuer - publicKeyBytes, err := marshalUtil.ReadBytes(identity.PublicKeySize) - if err != nil { + if result.issuerPublicKey, err = ed25119.ParsePublicKey(marshalUtil); err != nil { return } - result.issuer = identity.New(publicKeyBytes) - - // read payload type - payloadType, err := marshalUtil.ReadUint32() - if err != nil { + if result.payload, err = payload.Parse(marshalUtil); err != nil { return } - - // read payload - payloadBytes, err := marshalUtil.ReadBytes(-identity.SignatureSize) - if err != nil { - return - } - result.payload, err = payload.GetUnmarshaler(payloadType)(payloadBytes) - if err != nil { + if result.signature, err = ed25119.ParseSignature(marshalUtil); err != nil { return } - // read signature - copy(result.signature[:], marshalUtil.ReadRemainingBytes()) + // return the number of bytes we processed + consumedBytes = marshalUtil.ReadOffset() // store marshaled version - result.bytes = make([]byte, len(bytes)) + result.bytes = make([]byte, consumedBytes) copy(result.bytes, bytes) - // return the number of bytes we processed - consumedBytes = marshalUtil.ReadOffset() - return } func (transaction *Transaction) VerifySignature() (result bool) { - transactionBytes := transaction.GetBytes() + transactionBytes := transaction.Bytes() transaction.signatureMutex.RLock() - result = transaction.issuer.VerifySignature(transactionBytes[:len(transactionBytes)-identity.SignatureSize], transaction.signature[:]) + result = transaction.issuerPublicKey.VerifySignature(transactionBytes[:len(transactionBytes)-ed25119.SignatureSize], transaction.signature) transaction.signatureMutex.RUnlock() return @@ -192,14 +173,6 @@ func (transaction *Transaction) GetPayloadId() (result payload.Id) { return } -func (transaction *Transaction) GetBytes() []byte { - if result, err := transaction.MarshalBinary(); err != nil { - panic(err) - } else { - return result - } -} - func (transaction *Transaction) calculateTransactionId() Id { payloadId := transaction.GetPayloadId() @@ -219,7 +192,7 @@ func (transaction *Transaction) calculateTransactionId() Id { } func (transaction *Transaction) calculatePayloadId() payload.Id { - bytes := transaction.GetBytes() + bytes := transaction.Bytes() return blake2b.Sum512(bytes[2*IdLength:]) } @@ -240,14 +213,13 @@ func (transaction *Transaction) Bytes() []byte { return transaction.bytes } + // marshal result marshalUtil := marshalutil.New() - marshalUtil.WriteBytes(transaction.trunkTransactionId.Bytes()) marshalUtil.WriteBytes(transaction.branchTransactionId.Bytes()) - marshalUtil.WriteBytes(transaction.issuer.PublicKey) - marshalUtil.WriteUint32(transaction.payload.GetType()) + marshalUtil.WriteBytes(transaction.issuerPublicKey.Bytes()) marshalUtil.WriteBytes(transaction.payload.Bytes()) - marshalUtil.WriteBytes(transaction.issuer.Sign(marshalUtil.Bytes())) + marshalUtil.WriteBytes(transaction.issuerPrivateKey.Sign(marshalUtil.Bytes()).Bytes()) return marshalUtil.Bytes() } diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go index 4b3653ca8c0a7402b7b1651932bf11e569136abc..0e86da66147ef245bef1599abf97c047a38a2fa9 100644 --- a/packages/binary/tangle/tangle.go +++ b/packages/binary/tangle/tangle.go @@ -134,7 +134,7 @@ func (tangle *Tangle) Prune() error { return nil } -// Worker that stores the transactions and calls the corresponding "Storage events" +// Worker that stores the transactions and calls the corresponding storage events" func (tangle *Tangle) storeTransactionWorker(tx *transaction.Transaction) { // store transaction var cachedTransaction *transaction.CachedTransaction diff --git a/packages/binary/tangle/tangle_test.go b/packages/binary/tangle/tangle_test.go index f0f8c60ef5a7660306818fc83d7d0bfdc821fd66..be15e7e3b701e1385ba71d15399c6e9659f8c5eb 100644 --- a/packages/binary/tangle/tangle_test.go +++ b/packages/binary/tangle/tangle_test.go @@ -7,11 +7,10 @@ import ( "testing" "time" - "github.com/dgraph-io/badger/v2" "github.com/iotaledger/hive.go/events" "github.com/stretchr/testify/require" - "github.com/iotaledger/goshimmer/packages/binary/identity" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata" @@ -19,10 +18,6 @@ import ( "github.com/iotaledger/goshimmer/plugins/config" ) -var testDatabase *badger.DB - -var _ = config.PLUGIN - func BenchmarkTangle_AttachTransaction(b *testing.B) { dir, err := ioutil.TempDir("", b.Name()) require.NoError(b, err) @@ -30,19 +25,19 @@ func BenchmarkTangle_AttachTransaction(b *testing.B) { // use the tempdir for the database config.Node.Set(database.CFG_DIRECTORY, dir) - tangle := New(testDatabase, []byte("TEST_BINARY_TANGLE")) + tangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE")) if err := tangle.Prune(); err != nil { b.Error(err) return } - testIdentity := identity.Generate() + testIdentity := ed25119.GenerateKeyPair() transactionBytes := make([]*transaction.Transaction, b.N) for i := 0; i < b.N; i++ { transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, testIdentity, data.New([]byte("some data"))) - transactionBytes[i].GetBytes() + transactionBytes[i].Bytes() } b.ResetTimer() @@ -96,8 +91,8 @@ func TestTangle_AttachTransaction(t *testing.T) { fmt.Println("REMOVED:", transactionId) })) - newTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data"))) - newTransaction2 := transaction.New(newTransaction1.GetId(), newTransaction1.GetId(), identity.Generate(), data.New([]byte("some other data"))) + newTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), data.New([]byte("some data"))) + newTransaction2 := transaction.New(newTransaction1.GetId(), newTransaction1.GetId(), ed25119.GenerateKeyPair(), data.New([]byte("some other data"))) tangle.AttachTransaction(newTransaction2) diff --git a/packages/binary/tangle/tipselector/tipselector_test.go b/packages/binary/tangle/tipselector/tipselector_test.go index 0bd3d385482c852445a5d92969e4dcc990b08c05..05329cc3e71770858f8606ca19554db4d8c653ae 100644 --- a/packages/binary/tangle/tipselector/tipselector_test.go +++ b/packages/binary/tangle/tipselector/tipselector_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/iotaledger/goshimmer/packages/binary/identity" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" ) @@ -20,7 +20,7 @@ func Test(t *testing.T) { assert.Equal(t, transaction.EmptyId, branch1) // create a transaction and attach it - transaction1 := transaction.New(trunk1, branch1, identity.Generate(), data.New([]byte("testtransaction"))) + transaction1 := transaction.New(trunk1, branch1, ed25119.GenerateKeyPair(), data.New([]byte("testtransaction"))) tipSelector.AddTip(transaction1) // check if the tip shows up in the tip count @@ -32,7 +32,7 @@ func Test(t *testing.T) { assert.Equal(t, transaction1.GetId(), branch2) // create a 2nd transaction and attach it - transaction2 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("testtransaction"))) + transaction2 := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), data.New([]byte("testtransaction"))) tipSelector.AddTip(transaction2) // check if the tip shows up in the tip count @@ -40,7 +40,7 @@ func Test(t *testing.T) { // attach a transaction to our two tips trunk3, branch3 := tipSelector.GetTips() - transaction3 := transaction.New(trunk3, branch3, identity.Generate(), data.New([]byte("testtransaction"))) + transaction3 := transaction.New(trunk3, branch3, ed25119.GenerateKeyPair(), data.New([]byte("testtransaction"))) tipSelector.AddTip(transaction3) // check if the tip shows replaces the current tips diff --git a/packages/binary/tangle/transactionparser/transactionparser_test.go b/packages/binary/tangle/transactionparser/transactionparser_test.go index 5741252932ba5a82eb889300aa32e031f4b6ce2b..8f31c0e9d101fd2fa03e3ef821ad84de5dc2da9e 100644 --- a/packages/binary/tangle/transactionparser/transactionparser_test.go +++ b/packages/binary/tangle/transactionparser/transactionparser_test.go @@ -7,13 +7,13 @@ import ( "github.com/iotaledger/hive.go/events" - "github.com/iotaledger/goshimmer/packages/binary/identity" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data" ) func BenchmarkTransactionParser_ParseBytesSame(b *testing.B) { - txBytes := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("Test"))).GetBytes() + txBytes := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), data.New([]byte("Test"))).Bytes() txParser := New() b.ResetTimer() @@ -28,7 +28,7 @@ func BenchmarkTransactionParser_ParseBytesSame(b *testing.B) { func BenchmarkTransactionParser_ParseBytesDifferent(b *testing.B) { transactionBytes := make([][]byte, b.N) for i := 0; i < b.N; i++ { - transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("Test"+strconv.Itoa(i)))).GetBytes() + transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), data.New([]byte("Test"+strconv.Itoa(i)))).Bytes() } txParser := New() @@ -43,10 +43,10 @@ func BenchmarkTransactionParser_ParseBytesDifferent(b *testing.B) { } func TestTransactionParser_ParseTransaction(t *testing.T) { - tx := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("Test"))) + tx := transaction.New(transaction.EmptyId, transaction.EmptyId, ed25119.GenerateKeyPair(), data.New([]byte("Test"))) txParser := New() - txParser.Parse(tx.GetBytes(), nil) + txParser.Parse(tx.Bytes(), nil) txParser.Events.TransactionParsed.Attach(events.NewClosure(func(tx *transaction.Transaction) { fmt.Println("PARSED!!!") diff --git a/packages/binary/valuetransfers/address/address.go b/packages/binary/valuetransfer/address/address.go similarity index 100% rename from packages/binary/valuetransfers/address/address.go rename to packages/binary/valuetransfer/address/address.go diff --git a/packages/binary/valuetransfers/coloredbalance/color/color.go b/packages/binary/valuetransfer/coloredbalance/color/color.go similarity index 100% rename from packages/binary/valuetransfers/coloredbalance/color/color.go rename to packages/binary/valuetransfer/coloredbalance/color/color.go diff --git a/packages/binary/valuetransfers/coloredbalance/coloredbalance.go b/packages/binary/valuetransfer/coloredbalance/coloredbalance.go similarity index 93% rename from packages/binary/valuetransfers/coloredbalance/coloredbalance.go rename to packages/binary/valuetransfer/coloredbalance/coloredbalance.go index 6d8f576bb570575d1e841549f828371c99370a32..b0f4d43a072a3130dfa3da1603b87a4e0240b080 100644 --- a/packages/binary/valuetransfers/coloredbalance/coloredbalance.go +++ b/packages/binary/valuetransfer/coloredbalance/coloredbalance.go @@ -4,7 +4,7 @@ import ( "strconv" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/coloredbalance/color" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance/color" ) type ColoredBalance struct { diff --git a/packages/binary/valuetransfer/payload/cached_object.go b/packages/binary/valuetransfer/payload/cached_object.go new file mode 100644 index 0000000000000000000000000000000000000000..5c1639b1685cf5627fe8164f14c12922bc34f89c --- /dev/null +++ b/packages/binary/valuetransfer/payload/cached_object.go @@ -0,0 +1,39 @@ +package payload + +import ( + "github.com/iotaledger/hive.go/objectstorage" +) + +// CachedObject is a wrapper for the object storage, that takes care of type casting the managed objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of CachedObjects, without having to manually type cast over and over again. +type CachedObject struct { + objectstorage.CachedObject +} + +// Retain wraps the underlying method to return a new "wrapped object". +func (cachedPayload *CachedObject) Retain() *CachedObject { + return &CachedObject{cachedPayload.CachedObject.Retain()} +} + +// Consume wraps the underlying method to return the correctly typed objects in the callback. +func (cachedPayload *CachedObject) Consume(consumer func(payload *Payload)) bool { + return cachedPayload.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*Payload)) + }) +} + +// Unwrap provides a way to "Get" a type casted version of the underlying object. +func (cachedPayload *CachedObject) Unwrap() *Payload { + if untypedTransaction := cachedPayload.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*Payload); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} diff --git a/packages/binary/valuetransfer/payload/id/id.go b/packages/binary/valuetransfer/payload/id/id.go new file mode 100644 index 0000000000000000000000000000000000000000..8a8f24f0425dff74cef572d337cbf443391fcd3b --- /dev/null +++ b/packages/binary/valuetransfer/payload/id/id.go @@ -0,0 +1,87 @@ +package id + +import ( + "fmt" + + "github.com/mr-tron/base58" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" +) + +// Id represents the hash of a payload that is used to identify the given payload. +type Id [Length]byte + +// New creates a payload id from a base58 encoded string. +func New(base58EncodedString string) (result Id, err error) { + bytes, err := base58.Decode(base58EncodedString) + if err != nil { + return + } + + if len(bytes) != Length { + err = fmt.Errorf("length of base58 formatted payload id is wrong") + + return + } + + copy(result[:], bytes) + + return +} + +// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func Parse(marshalUtil *marshalutil.MarshalUtil) (Id, error) { + if id, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { + return Id{}, err + } else { + return id.(Id), nil + } +} + +// FromBytes unmarshals a payload id from a sequence of bytes. +// It either creates a new payload id or fills the optionally provided object with the parsed information. +func FromBytes(bytes []byte, optionalTargetObject ...*Id) (result Id, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + var targetObject *Id + switch len(optionalTargetObject) { + case 0: + targetObject = &result + case 1: + targetObject = optionalTargetObject[0] + default: + panic("too many arguments in call to FromBytes") + } + + // initialize helper + marshalUtil := marshalutil.New(bytes) + + // read id from bytes + idBytes, err := marshalUtil.ReadBytes(Length) + if err != nil { + return + } + copy(targetObject[:], idBytes) + + // copy result if we have provided a target object + result = *targetObject + + // return the number of bytes we processed + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// String returns a base58 encoded version of the payload id. +func (id Id) String() string { + return base58.Encode(id[:]) +} + +func (id Id) Bytes() []byte { + return id[:] +} + +// Empty represents the id encoding the genesis. +var Genesis Id + +// Length defined the amount of bytes in a payload id (32 bytes hash value). +const Length = 32 diff --git a/packages/binary/valuetransfer/payload/id/id_test.go b/packages/binary/valuetransfer/payload/id/id_test.go new file mode 100644 index 0000000000000000000000000000000000000000..86fd25ab18cd9c0a41dc8d8c3120fdca8939b4e2 --- /dev/null +++ b/packages/binary/valuetransfer/payload/id/id_test.go @@ -0,0 +1,26 @@ +package id + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test(t *testing.T) { + // create variable for id + sourceId, err := New("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") + if err != nil { + panic(err) + } + + // read serialized id into both variables + var restoredIdPointer Id + restoredIdValue, err, _ := FromBytes(sourceId.Bytes(), &restoredIdPointer) + if err != nil { + panic(err) + } + + // check if both variables give the same result + assert.Equal(t, sourceId, restoredIdValue) + assert.Equal(t, sourceId, restoredIdPointer) +} diff --git a/packages/binary/valuetransfers/payload/payload.go b/packages/binary/valuetransfer/payload/payload.go similarity index 76% rename from packages/binary/valuetransfers/payload/payload.go rename to packages/binary/valuetransfer/payload/payload.go index 39430b2179a54e991c57a15d19883c112ff7f153..ee248f7dbb20167cc783f4cab6c8072bda963743 100644 --- a/packages/binary/valuetransfers/payload/payload.go +++ b/packages/binary/valuetransfer/payload/payload.go @@ -9,9 +9,9 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/marshalutil" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer" - transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/id" + payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer" + transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" ) type Payload struct { @@ -36,6 +36,17 @@ func New(trunkPayloadId, branchPayloadId payloadid.Id, valueTransfer *transfer.T } } +func FromStorage(key []byte) objectstorage.StorableObject { + id, err, _ := payloadid.FromBytes(key) + if err != nil { + panic(err) + } + + return &Payload{ + id: &id, + } +} + // FromBytes parses the marshaled version of a Payload into an object. // It either returns a new Payload or fills an optionally provided Payload with the parsed information. func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, err error, consumedBytes int) { @@ -52,19 +63,29 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, // initialize helper marshalUtil := marshalutil.New(bytes) + // read information that are required to identify the payload from the outside + _, err = marshalUtil.ReadUint32() + if err != nil { + return + } + _, err = marshalUtil.ReadUint32() + if err != nil { + return + } + // parse trunk payload id - parsedTrunkPayloadId, err := marshalUtil.ReadBytes(payloadid.Length) + parsedTrunkPayloadId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return payloadid.FromBytes(data) }) if err != nil { return } - result.trunkPayloadId = payloadid.New(parsedTrunkPayloadId) + result.trunkPayloadId = parsedTrunkPayloadId.(payloadid.Id) // parse branch payload id - parsedBranchPayloadId, err := marshalUtil.ReadBytes(payloadid.Length) + parsedBranchPayloadId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return payloadid.FromBytes(data) }) if err != nil { return } - result.branchPayloadId = payloadid.New(parsedBranchPayloadId) + result.branchPayloadId = parsedBranchPayloadId.(payloadid.Id) // parse transfer parsedTransfer, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return transfer.FromBytes(data) }) @@ -104,22 +125,22 @@ func (payload *Payload) GetId() payloadid.Id { } // otherwise calculate the id - transferId := payload.GetTransfer().GetId() marshalUtil := marshalutil.New(payloadid.Length + payloadid.Length + transferid.Length) - marshalUtil.WriteBytes(payload.trunkPayloadId[:]) - marshalUtil.WriteBytes(payload.branchPayloadId[:]) - marshalUtil.WriteBytes(transferId[:]) + marshalUtil.WriteBytes(payload.trunkPayloadId.Bytes()) + marshalUtil.WriteBytes(payload.branchPayloadId.Bytes()) + marshalUtil.WriteBytes(payload.GetTransfer().GetId().Bytes()) + var id payloadid.Id = blake2b.Sum256(marshalUtil.Bytes()) payload.id = &id return id } -func (payload *Payload) GetTrunkPayloadId() payloadid.Id { +func (payload *Payload) GetTrunkId() payloadid.Id { return payload.trunkPayloadId } -func (payload *Payload) GetBranchPayloadId() payloadid.Id { +func (payload *Payload) GetBranchId() payloadid.Id { return payload.branchPayloadId } @@ -155,9 +176,12 @@ func (payload *Payload) Bytes() (bytes []byte) { } // marshal fields - marshalUtil := marshalutil.New(payloadid.Length + payloadid.Length + transferid.Length) - marshalUtil.WriteBytes(payload.trunkPayloadId[:]) - marshalUtil.WriteBytes(payload.branchPayloadId[:]) + payloadLength := payloadid.Length + payloadid.Length + len(transferBytes) + marshalUtil := marshalutil.New(marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + payloadLength) + marshalUtil.WriteUint32(Type) + marshalUtil.WriteUint32(uint32(payloadLength)) + marshalUtil.WriteBytes(payload.trunkPayloadId.Bytes()) + marshalUtil.WriteBytes(payload.branchPayloadId.Bytes()) marshalUtil.WriteBytes(transferBytes) bytes = marshalUtil.Bytes() @@ -170,8 +194,8 @@ func (payload *Payload) Bytes() (bytes []byte) { func (payload *Payload) String() string { return stringify.Struct("Payload", stringify.StructField("id", payload.GetId()), - stringify.StructField("trunk", payload.GetTrunkPayloadId()), - stringify.StructField("branch", payload.GetBranchPayloadId()), + stringify.StructField("trunk", payload.GetTrunkId()), + stringify.StructField("branch", payload.GetBranchId()), stringify.StructField("transfer", payload.GetTransfer()), ) } diff --git a/packages/binary/valuetransfers/payload/id/id.go b/packages/binary/valuetransfer/payload/transfer/id/id.go similarity index 83% rename from packages/binary/valuetransfers/payload/id/id.go rename to packages/binary/valuetransfer/payload/transfer/id/id.go index 8f9847f54fd82e1d017095934152e26f6005478a..8036c466ac7ec863bcc680b59441934f9b3ab4ba 100644 --- a/packages/binary/valuetransfers/payload/id/id.go +++ b/packages/binary/valuetransfer/payload/transfer/id/id.go @@ -12,10 +12,12 @@ func New(idBytes []byte) (result Id) { return } +func (id Id) Bytes() []byte { + return id[:] +} + func (id Id) String() string { return base58.Encode(id[:]) } -var Empty Id - const Length = 32 diff --git a/packages/binary/valuetransfers/payload/transfer/inputs/inputs.go b/packages/binary/valuetransfer/payload/transfer/inputs/inputs.go similarity index 92% rename from packages/binary/valuetransfers/payload/transfer/inputs/inputs.go rename to packages/binary/valuetransfer/payload/transfer/inputs/inputs.go index bfb7e68840cfb082de4ac3d0269dcb2c5484223e..be2c3fa460e3fd2ceac979e31426aeaa5459bad5 100644 --- a/packages/binary/valuetransfers/payload/transfer/inputs/inputs.go +++ b/packages/binary/valuetransfer/payload/transfer/inputs/inputs.go @@ -3,10 +3,10 @@ package inputs import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/id" - transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/id" - transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/transferoutput/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" + transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" + transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transferoutput/id" ) type Inputs struct { diff --git a/packages/binary/valuetransfers/payload/transfer/outputs/outputs.go b/packages/binary/valuetransfer/payload/transfer/outputs/outputs.go similarity index 96% rename from packages/binary/valuetransfers/payload/transfer/outputs/outputs.go rename to packages/binary/valuetransfer/payload/transfer/outputs/outputs.go index 7a6d94febd64f14aa4178c2e832d296edfb1603b..f39268bc68a6fa284b2b2cd7ffdcac0bb36fc86e 100644 --- a/packages/binary/valuetransfers/payload/transfer/outputs/outputs.go +++ b/packages/binary/valuetransfer/payload/transfer/outputs/outputs.go @@ -3,8 +3,8 @@ package outputs import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/coloredbalance" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance" ) type Outputs struct { diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/ed25519.go b/packages/binary/valuetransfer/payload/transfer/signatures/ed25519.go similarity index 98% rename from packages/binary/valuetransfers/payload/transfer/signatures/ed25519.go rename to packages/binary/valuetransfer/payload/transfer/signatures/ed25519.go index 17cdc17d78cfa4f7d1ac016e5a11f231f57fe4b3..e7423f5512ee7f10ad5e889a19cccafde6246cf5 100644 --- a/packages/binary/valuetransfers/payload/transfer/signatures/ed25519.go +++ b/packages/binary/valuetransfer/payload/transfer/signatures/ed25519.go @@ -5,7 +5,7 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/marshalutil" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" ) // region PUBLIC API /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/interfaces.go b/packages/binary/valuetransfer/payload/transfer/signatures/interfaces.go similarity index 98% rename from packages/binary/valuetransfers/payload/transfer/signatures/interfaces.go rename to packages/binary/valuetransfer/payload/transfer/signatures/interfaces.go index 9b28078ff953206e6c3aedcb12ca36e7b59d66db..81fe7247e3355d5154eae174f1ba70a948e58350 100644 --- a/packages/binary/valuetransfers/payload/transfer/signatures/interfaces.go +++ b/packages/binary/valuetransfer/payload/transfer/signatures/interfaces.go @@ -1,6 +1,6 @@ package signatures -import "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" +import "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" // SignatureScheme defines an interface for different signature generation methods (i.e. ED25519, WOTS, and so on ...). type SignatureScheme interface { diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/signatures.go b/packages/binary/valuetransfer/payload/transfer/signatures/signatures.go similarity index 97% rename from packages/binary/valuetransfers/payload/transfer/signatures/signatures.go rename to packages/binary/valuetransfer/payload/transfer/signatures/signatures.go index f5cfee2cfe03550a9282eefabcaf2ea6617eacc2..d07d1a43bdf62f827d52133792199f4250c9733e 100644 --- a/packages/binary/valuetransfers/payload/transfer/signatures/signatures.go +++ b/packages/binary/valuetransfer/payload/transfer/signatures/signatures.go @@ -3,7 +3,7 @@ package signatures import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" ) // Signatures represents a container for the address signatures of a value transfer. diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/signatures_test.go b/packages/binary/valuetransfer/payload/transfer/signatures/signatures_test.go similarity index 93% rename from packages/binary/valuetransfers/payload/transfer/signatures/signatures_test.go rename to packages/binary/valuetransfer/payload/transfer/signatures/signatures_test.go index a4aca5092e78ebceb620719f23be35249aee5779..214092e8a9fd33b77df6cb491d7a16a08a618b38 100644 --- a/packages/binary/valuetransfers/payload/transfer/signatures/signatures_test.go +++ b/packages/binary/valuetransfer/payload/transfer/signatures/signatures_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" ) func TestSignatures(t *testing.T) { diff --git a/packages/binary/valuetransfers/payload/transfer/transfer.go b/packages/binary/valuetransfer/payload/transfer/transfer.go similarity index 94% rename from packages/binary/valuetransfers/payload/transfer/transfer.go rename to packages/binary/valuetransfer/payload/transfer/transfer.go index fd041ce5481d164b84964cc7efc5c073a7756803..0703fcba9f5987ce14dd917f228155e9c4b95ad9 100644 --- a/packages/binary/valuetransfers/payload/transfer/transfer.go +++ b/packages/binary/valuetransfer/payload/transfer/transfer.go @@ -10,11 +10,11 @@ import ( "golang.org/x/crypto/blake2b" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/inputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/outputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/signatures" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/inputs" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/outputs" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/signatures" ) // region IMPLEMENT Transfer /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/binary/valuetransfer/tangle/constants.go b/packages/binary/valuetransfer/tangle/constants.go new file mode 100644 index 0000000000000000000000000000000000000000..937b67282aaa2828313d58abb363c7844df4906b --- /dev/null +++ b/packages/binary/valuetransfer/tangle/constants.go @@ -0,0 +1,10 @@ +package tangle + +import ( + "time" +) + +const ( + MAX_MISSING_TIME_BEFORE_CLEANUP = 30 * time.Second + MISSING_CHECK_INTERVAL = 5 * time.Second +) diff --git a/packages/binary/valuetransfer/tangle/events.go b/packages/binary/valuetransfer/tangle/events.go new file mode 100644 index 0000000000000000000000000000000000000000..653ae8281c6189ab82f2346a05f1bfc6d2b124fb --- /dev/null +++ b/packages/binary/valuetransfer/tangle/events.go @@ -0,0 +1,41 @@ +package tangle + +import ( + "github.com/iotaledger/hive.go/events" + + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" + payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadmetadata" +) + +type Events struct { + // Get's called whenever a transaction + PayloadAttached *events.Event + PayloadSolid *events.Event + MissingPayloadReceived *events.Event + PayloadMissing *events.Event + PayloadUnsolidifiable *events.Event + TransactionRemoved *events.Event +} + +func newEvents() *Events { + return &Events{ + PayloadAttached: events.NewEvent(cachedPayloadEvent), + PayloadSolid: events.NewEvent(cachedPayloadEvent), + MissingPayloadReceived: events.NewEvent(cachedPayloadEvent), + PayloadMissing: events.NewEvent(payloadIdEvent), + PayloadUnsolidifiable: events.NewEvent(payloadIdEvent), + TransactionRemoved: events.NewEvent(payloadIdEvent), + } +} + +func payloadIdEvent(handler interface{}, params ...interface{}) { + handler.(func(payloadid.Id))(params[0].(payloadid.Id)) +} + +func cachedPayloadEvent(handler interface{}, params ...interface{}) { + handler.(func(*payload.CachedObject, *payloadmetadata.CachedObject))( + params[0].(*payload.CachedObject).Retain(), + params[1].(*payloadmetadata.CachedObject).Retain(), + ) +} diff --git a/packages/binary/valuetransfer/tangle/missingpayload/missingpayload.go b/packages/binary/valuetransfer/tangle/missingpayload/missingpayload.go new file mode 100644 index 0000000000000000000000000000000000000000..38afa8099f50a9c59aa62e56bed61e714911449d --- /dev/null +++ b/packages/binary/valuetransfer/tangle/missingpayload/missingpayload.go @@ -0,0 +1,103 @@ +package missingpayload + +import ( + "time" + + "github.com/iotaledger/hive.go/objectstorage" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" +) + +// MissingPayload represents a payload that was referenced through branch or trunk but that is missing in our object +// storage. +type MissingPayload struct { + objectstorage.StorableObjectFlags + + payloadId payloadid.Id + missingSince time.Time +} + +// New creates an entry for a missing value transfer payload. +func New(payloadId payloadid.Id) *MissingPayload { + return &MissingPayload{ + payloadId: payloadId, + missingSince: time.Now(), + } +} + +// FromBytes 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 FromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &MissingPayload{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to FromBytes") + } + + // parse the bytes + marshalUtil := marshalutil.New(bytes) + if result.payloadId, err = payloadid.Parse(marshalUtil); err != nil { + return + } + if result.missingSince, err = marshalUtil.ReadTime(); err != nil { + return + } + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// FromStorage 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.MarshalBinary interface. +func FromStorage([]byte) objectstorage.StorableObject { + return &MissingPayload{} +} + +// GetId returns the payload id, that is missing. +func (missingPayload *MissingPayload) GetId() payloadid.Id { + return missingPayload.payloadId +} + +// GetMissingSince returns the time.Time since the transaction was first reported as being missing. +func (missingPayload *MissingPayload) GetMissingSince() time.Time { + return missingPayload.missingSince +} + +// 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() +} + +// GetStorageKey returns the key that is used to store the object in the database. +// It is required to match StorableObject interface. +func (missingPayload *MissingPayload) GetStorageKey() []byte { + return missingPayload.payloadId.Bytes() +} + +// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. +// It is required to match StorableObject interface. +func (missingPayload *MissingPayload) Update(other objectstorage.StorableObject) { + panic("implement me") +} + +// MarshalBinary is required to match the encoding.BinaryMarshaler interface. +func (missingPayload *MissingPayload) MarshalBinary() (data []byte, err error) { + return missingPayload.Bytes(), nil +} + +// UnmarshalBinary is required to match the encoding.BinaryUnmarshaler interface. +func (missingPayload *MissingPayload) UnmarshalBinary(data []byte) (err error) { + _, err, _ = FromBytes(data, missingPayload) + + return +} diff --git a/packages/binary/valuetransfer/tangle/payloadapprover/cached_object.go b/packages/binary/valuetransfer/tangle/payloadapprover/cached_object.go new file mode 100644 index 0000000000000000000000000000000000000000..b90c704272f82869a9b3069f59d1409d92650b6f --- /dev/null +++ b/packages/binary/valuetransfer/tangle/payloadapprover/cached_object.go @@ -0,0 +1,49 @@ +package payloadapprover + +import ( + "github.com/iotaledger/hive.go/objectstorage" +) + +// CachedObject is a wrapper for the object storage, that takes care of type casting the managed objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of CachedObjects, without having to manually type cast over and over again. +type CachedObject struct { + objectstorage.CachedObject +} + +// Retain wraps the underlying method to return a new "wrapped object". +func (cachedApprover *CachedObject) Retain() *CachedObject { + return &CachedObject{cachedApprover.CachedObject.Retain()} +} + +// Consume wraps the underlying method to return the correctly typed objects in the callback. +func (cachedApprover *CachedObject) Consume(consumer func(payload *PayloadApprover)) bool { + return cachedApprover.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*PayloadApprover)) + }) +} + +// Unwrap provides a way to "Get" a type casted version of the underlying object. +func (cachedApprover *CachedObject) Unwrap() *PayloadApprover { + if untypedTransaction := cachedApprover.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*PayloadApprover); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} + +type CachedObjects []*CachedObject + +func (cachedApprovers CachedObjects) Consume(consumer func(approver *PayloadApprover)) (consumed bool) { + for _, cachedApprover := range cachedApprovers { + consumed = cachedApprover.Consume(consumer) || consumed + } + + return +} diff --git a/packages/binary/valuetransfer/tangle/payloadapprover/payloadapprover.go b/packages/binary/valuetransfer/tangle/payloadapprover/payloadapprover.go new file mode 100644 index 0000000000000000000000000000000000000000..7c92ae68b2b5bd01615f73532b5edb579aa5219b --- /dev/null +++ b/packages/binary/valuetransfer/tangle/payloadapprover/payloadapprover.go @@ -0,0 +1,85 @@ +package payloadapprover + +import ( + "github.com/iotaledger/hive.go/objectstorage" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" +) + +// PayloadApprover is a database entity, that allows us to keep track of the "tangle structure" by encoding which +// payload approves which other payload. It allows us to traverse the tangle in the opposite direction of the referenced +// trunk and branch payloads. +type PayloadApprover struct { + objectstorage.StorableObjectFlags + + storageKey []byte + referencedPayloadId payloadid.Id + approvingPayloadId payloadid.Id +} + +// New creates an approver object that encodes a single relation between an approved and an approving payload. +func New(referencedPayload payloadid.Id, approvingPayload payloadid.Id) *PayloadApprover { + marshalUtil := marshalutil.New(payloadid.Length + payloadid.Length) + marshalUtil.WriteBytes(referencedPayload.Bytes()) + marshalUtil.WriteBytes(approvingPayload.Bytes()) + + return &PayloadApprover{ + referencedPayloadId: referencedPayload, + approvingPayloadId: approvingPayload, + storageKey: marshalUtil.Bytes(), + } +} + +// FromStorage 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 UnmarshalBinary +// method. +func FromStorage(idBytes []byte) objectstorage.StorableObject { + marshalUtil := marshalutil.New(idBytes) + + referencedPayloadId, err := payloadid.Parse(marshalUtil) + if err != nil { + panic(err) + } + approvingPayloadId, err := payloadid.Parse(marshalUtil) + if err != nil { + panic(err) + } + + result := &PayloadApprover{ + referencedPayloadId: referencedPayloadId, + approvingPayloadId: approvingPayloadId, + storageKey: marshalUtil.Bytes(true), + } + + return result +} + +// GetApprovingPayloadId returns the id of the approving payload. +func (approver *PayloadApprover) GetApprovingPayloadId() payloadid.Id { + return approver.approvingPayloadId +} + +// GetStorageKey returns the key that is used to store the object in the database. +// It is required to match StorableObject interface. +func (approver *PayloadApprover) GetStorageKey() []byte { + return approver.storageKey +} + +// MarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything, +// since all of the information about an approver are stored in the "key". +func (approver *PayloadApprover) MarshalBinary() (data []byte, err error) { + return +} + +// UnmarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything, +// since all of the information about an approver are stored in the "key". +func (approver *PayloadApprover) UnmarshalBinary(data []byte) error { + return nil +} + +// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. +// It is required to match StorableObject interface. +func (approver *PayloadApprover) Update(other objectstorage.StorableObject) { + panic("implement me") +} diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata/cached_object.go b/packages/binary/valuetransfer/tangle/payloadmetadata/cached_object.go new file mode 100644 index 0000000000000000000000000000000000000000..bde06d7cc7f75d5508858a09bdd8c2b52d51c274 --- /dev/null +++ b/packages/binary/valuetransfer/tangle/payloadmetadata/cached_object.go @@ -0,0 +1,39 @@ +package payloadmetadata + +import ( + "github.com/iotaledger/hive.go/objectstorage" +) + +// CachedObject is a wrapper for the object storage, that takes care of type casting the managed objects. +// Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means +// that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of +// manually managing these type, we create a wrapper that does this for us. This way, we can consistently handle the +// specialized types of CachedObjects, without having to manually type cast over and over again. +type CachedObject struct { + objectstorage.CachedObject +} + +// Retain wraps the underlying method to return a new "wrapped object". +func (cachedPayload *CachedObject) Retain() *CachedObject { + return &CachedObject{cachedPayload.CachedObject.Retain()} +} + +// Consume wraps the underlying method to return the correctly typed objects in the callback. +func (cachedPayload *CachedObject) Consume(consumer func(payload *PayloadMetadata)) bool { + return cachedPayload.CachedObject.Consume(func(object objectstorage.StorableObject) { + consumer(object.(*PayloadMetadata)) + }) +} + +// Unwrap provides a way to "Get" a type casted version of the underlying object. +func (cachedPayload *CachedObject) Unwrap() *PayloadMetadata { + if untypedTransaction := cachedPayload.Get(); untypedTransaction == nil { + return nil + } else { + if typeCastedTransaction := untypedTransaction.(*PayloadMetadata); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } else { + return typeCastedTransaction + } + } +} diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata.go b/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata.go new file mode 100644 index 0000000000000000000000000000000000000000..b6eb53fbf71dc683f8c3b2479626b97c371e9b56 --- /dev/null +++ b/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata.go @@ -0,0 +1,178 @@ +package payloadmetadata + +import ( + "sync" + "time" + + "github.com/iotaledger/hive.go/objectstorage" + "github.com/iotaledger/hive.go/stringify" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" +) + +// PayloadMetadata is a container for the metadata of a value transfer payload. +// It is used to store the information in the database. +type PayloadMetadata struct { + objectstorage.StorableObjectFlags + + payloadId payloadid.Id + solid bool + solidificationTime time.Time + + solidMutex sync.RWMutex + solidificationTimeMutex sync.RWMutex +} + +// New creates an empty container for the metadata of a value transfer payload. +func New(payloadId payloadid.Id) *PayloadMetadata { + return &PayloadMetadata{ + payloadId: payloadId, + } +} + +// FromBytes 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 FromBytes(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 FromBytes") + } + + // parse the bytes + marshalUtil := marshalutil.New(bytes) + if result.payloadId, err = payloadid.Parse(marshalUtil); err != nil { + return + } + if result.solidificationTime, err = marshalUtil.ReadTime(); err != nil { + return + } + if result.solid, err = marshalUtil.ReadBool(); err != nil { + return + } + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// FromStorage 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.MarshalBinary interface. +func FromStorage(id []byte) objectstorage.StorableObject { + result := &PayloadMetadata{} + + var err error + if result.payloadId, err = payloadid.Parse(marshalutil.New(id)); err != nil { + panic(err) + } + + return result +} + +// Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func Parse(marshalUtil *marshalutil.MarshalUtil) (*PayloadMetadata, error) { + if payloadMetadata, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(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() payloadid.Id { + return payloadMetadata.payloadId +} + +// IsSolid returns true of the payload has been marked as solid. +func (payloadMetadata *PayloadMetadata) IsSolid() (result bool) { + payloadMetadata.solidMutex.RLock() + result = payloadMetadata.solid + payloadMetadata.solidMutex.RUnlock() + + return +} + +// SetSolid marks a payload as either solid or not solid. +// It returns true if the solid flag was changes and automatically updates the solidificationTime as well. +func (payloadMetadata *PayloadMetadata) SetSolid(solid bool) (modified bool) { + payloadMetadata.solidMutex.RLock() + if payloadMetadata.solid != solid { + payloadMetadata.solidMutex.RUnlock() + + payloadMetadata.solidMutex.Lock() + if payloadMetadata.solid != solid { + payloadMetadata.solid = solid + if solid { + payloadMetadata.solidificationTimeMutex.Lock() + payloadMetadata.solidificationTime = time.Now() + payloadMetadata.solidificationTimeMutex.Unlock() + } + + payloadMetadata.SetModified() + + modified = true + } + payloadMetadata.solidMutex.Unlock() + + } else { + payloadMetadata.solidMutex.RUnlock() + } + + return +} + +// GetSoldificationTime returns the time when the payload was marked to be solid. +func (payloadMetadata *PayloadMetadata) GetSoldificationTime() time.Time { + payloadMetadata.solidificationTimeMutex.RLock() + defer payloadMetadata.solidificationTimeMutex.RUnlock() + + return payloadMetadata.solidificationTime +} + +// 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() +} + +// String creates a human readable version of the metadata (for debug purposes). +func (payloadMetadata *PayloadMetadata) String() string { + return stringify.Struct("PayloadMetadata", + stringify.StructField("payloadId", payloadMetadata.GetPayloadId()), + stringify.StructField("solid", payloadMetadata.IsSolid()), + stringify.StructField("solidificationTime", payloadMetadata.GetSoldificationTime()), + ) +} + +// GetStorageKey returns the key that is used to store the object in the database. +// It is required to match StorableObject interface. +func (payloadMetadata *PayloadMetadata) GetStorageKey() []byte { + return payloadMetadata.payloadId.Bytes() +} + +// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. +// It is required to match StorableObject interface. +func (payloadMetadata *PayloadMetadata) Update(other objectstorage.StorableObject) { + panic("update forbidden") +} + +// MarshalBinary is required to match the encoding.BinaryMarshaler interface. +func (payloadMetadata *PayloadMetadata) MarshalBinary() ([]byte, error) { + return payloadMetadata.Bytes(), nil +} + +// UnmarshalBinary is required to match the encoding.BinaryUnmarshaler interface. +func (payloadMetadata *PayloadMetadata) UnmarshalBinary(data []byte) (err error) { + _, err, _ = FromBytes(data, payloadMetadata) + + return +} diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata_test.go b/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata_test.go new file mode 100644 index 0000000000000000000000000000000000000000..fd85c6f5307055506ea8dc258d4bc42e8c7552bb --- /dev/null +++ b/packages/binary/valuetransfer/tangle/payloadmetadata/payloadmetadata_test.go @@ -0,0 +1,46 @@ +package payloadmetadata + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" +) + +func TestMarshalUnmarshal(t *testing.T) { + originalMetadata := New(id.Genesis) + + clonedMetadata, err, _ := FromBytes(originalMetadata.Bytes()) + if err != nil { + panic(err) + } + + assert.Equal(t, originalMetadata.GetPayloadId(), clonedMetadata.GetPayloadId()) + assert.Equal(t, originalMetadata.IsSolid(), clonedMetadata.IsSolid()) + assert.Equal(t, originalMetadata.GetSoldificationTime().Round(time.Second), clonedMetadata.GetSoldificationTime().Round(time.Second)) + + originalMetadata.SetSolid(true) + + clonedMetadata, err, _ = FromBytes(originalMetadata.Bytes()) + if err != nil { + panic(err) + } + + assert.Equal(t, originalMetadata.GetPayloadId(), clonedMetadata.GetPayloadId()) + assert.Equal(t, originalMetadata.IsSolid(), clonedMetadata.IsSolid()) + assert.Equal(t, originalMetadata.GetSoldificationTime().Round(time.Second), clonedMetadata.GetSoldificationTime().Round(time.Second)) +} + +func TestPayloadMetadata_SetSolid(t *testing.T) { + originalMetadata := New(id.Genesis) + + assert.Equal(t, false, originalMetadata.IsSolid()) + assert.Equal(t, time.Time{}, originalMetadata.GetSoldificationTime()) + + originalMetadata.SetSolid(true) + + assert.Equal(t, true, originalMetadata.IsSolid()) + assert.Equal(t, time.Now().Round(time.Second), originalMetadata.GetSoldificationTime().Round(time.Second)) +} diff --git a/packages/binary/valuetransfer/tangle/tangle.go b/packages/binary/valuetransfer/tangle/tangle.go new file mode 100644 index 0000000000000000000000000000000000000000..39c97d7197cca9e091e3b386f319b965fb7ce280 --- /dev/null +++ b/packages/binary/valuetransfer/tangle/tangle.go @@ -0,0 +1,236 @@ +package tangle + +import ( + "container/list" + "time" + + "github.com/dgraph-io/badger/v2" + "github.com/iotaledger/hive.go/async" + "github.com/iotaledger/hive.go/objectstorage" + + "github.com/iotaledger/goshimmer/packages/binary/storageprefix" + valuepayload "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" + payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/missingpayload" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadapprover" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadmetadata" +) + +// 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 + missingPayloadStorage *objectstorage.ObjectStorage + + Events Events + + storePayloadWorkerPool async.WorkerPool + solidifierWorkerPool async.WorkerPool + cleanupWorkerPool async.WorkerPool +} + +func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) { + result = &Tangle{ + storageId: storageId, + + payloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayload...), valuepayload.FromStorage, objectstorage.CacheTime(time.Second)), + payloadMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayloadMetadata...), payloadmetadata.FromStorage, objectstorage.CacheTime(time.Second)), + approverStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferApprover...), payloadapprover.FromStorage, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payloadid.Length, payloadid.Length), objectstorage.KeysOnly(true)), + missingPayloadStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), missingpayload.FromStorage, objectstorage.CacheTime(time.Second)), + + Events: *newEvents(), + } + + return +} + +// AttachPayload adds a new payload to the value tangle. +func (tangle *Tangle) AttachPayload(payload *valuepayload.Payload) { + tangle.storePayloadWorkerPool.Submit(func() { tangle.storePayloadWorker(payload) }) +} + +// GetPayload retrieves a payload from the object storage. +func (tangle *Tangle) GetPayload(payloadId payloadid.Id) *valuepayload.CachedObject { + return &valuepayload.CachedObject{CachedObject: tangle.payloadStorage.Load(payloadId.Bytes())} +} + +// GetPayloadMetadata retrieves the metadata of a value payload from the object storage. +func (tangle *Tangle) GetPayloadMetadata(payloadId payloadid.Id) *payloadmetadata.CachedObject { + return &payloadmetadata.CachedObject{CachedObject: tangle.payloadMetadataStorage.Load(payloadId.Bytes())} +} + +// GetApprovers retrieves the approvers of a payload from the object storage. +func (tangle *Tangle) GetApprovers(transactionId payloadid.Id) payloadapprover.CachedObjects { + approvers := make(payloadapprover.CachedObjects, 0) + tangle.approverStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { + approvers = append(approvers, &payloadapprover.CachedObject{CachedObject: cachedObject}) + + return true + }, transactionId[:]) + + return approvers +} + +// Shutdown stops the worker pools and shuts down the object storage instances. +func (tangle *Tangle) Shutdown() *Tangle { + tangle.storePayloadWorkerPool.ShutdownGracefully() + tangle.solidifierWorkerPool.ShutdownGracefully() + tangle.cleanupWorkerPool.ShutdownGracefully() + + tangle.payloadStorage.Shutdown() + tangle.payloadMetadataStorage.Shutdown() + tangle.approverStorage.Shutdown() + tangle.missingPayloadStorage.Shutdown() + + return tangle +} + +// Prune resets the database and deletes all objects (for testing or "node resets"). +func (tangle *Tangle) Prune() error { + for _, storage := range []*objectstorage.ObjectStorage{ + tangle.payloadStorage, + tangle.payloadMetadataStorage, + tangle.approverStorage, + tangle.missingPayloadStorage, + } { + if err := storage.Prune(); err != nil { + return err + } + } + + return nil +} + +// storePayloadWorker is the worker function that stores the payload and calls the corresponding storage events. +func (tangle *Tangle) storePayloadWorker(payload *valuepayload.Payload) { + // store payload + var cachedPayload *valuepayload.CachedObject + if _tmp, transactionIsNew := tangle.payloadStorage.StoreIfAbsent(payload); !transactionIsNew { + return + } else { + cachedPayload = &valuepayload.CachedObject{CachedObject: _tmp} + } + + // store payload metadata + payloadId := payload.GetId() + cachedMetadata := &payloadmetadata.CachedObject{CachedObject: tangle.payloadMetadataStorage.Store(payloadmetadata.New(payloadId))} + + // store trunk approver + trunkId := payload.GetTrunkId() + tangle.approverStorage.Store(payloadapprover.New(trunkId, payloadId)).Release() + + // store branch approver + if branchId := payload.GetBranchId(); branchId != trunkId { + tangle.approverStorage.Store(payloadapprover.New(branchId, trunkId)).Release() + } + + // trigger events + if tangle.missingPayloadStorage.DeleteIfPresent(payloadId.Bytes()) { + tangle.Events.MissingPayloadReceived.Trigger(cachedPayload, cachedMetadata) + } + tangle.Events.PayloadAttached.Trigger(cachedPayload, cachedMetadata) + + // check solidity + tangle.solidifierWorkerPool.Submit(func() { + tangle.solidifyTransactionWorker(cachedPayload, cachedMetadata) + }) +} + +// solidifyTransactionWorker is the worker function that solidifies the payloads (recursively from past to present). +func (tangle *Tangle) solidifyTransactionWorker(cachedPayload *valuepayload.CachedObject, cachedMetadata *payloadmetadata.CachedObject) { + popElementsFromStack := func(stack *list.List) (*valuepayload.CachedObject, *payloadmetadata.CachedObject) { + currentSolidificationEntry := stack.Front() + currentCachedPayload := currentSolidificationEntry.Value.([2]interface{})[0] + currentCachedMetadata := currentSolidificationEntry.Value.([2]interface{})[1] + stack.Remove(currentSolidificationEntry) + + return currentCachedPayload.(*valuepayload.CachedObject), currentCachedMetadata.(*payloadmetadata.CachedObject) + } + + // initialize the stack + solidificationStack := list.New() + solidificationStack.PushBack([2]interface{}{cachedPayload, cachedMetadata}) + + // process payloads that are supposed to be checked for solidity recursively + for solidificationStack.Len() > 0 { + currentCachedPayload, currentCachedMetadata := popElementsFromStack(solidificationStack) + + currentPayload := currentCachedPayload.Unwrap() + currentMetadata := currentCachedMetadata.Unwrap() + if currentPayload == nil || currentMetadata == nil { + currentCachedPayload.Release() + currentCachedMetadata.Release() + + continue + } + + // if current transaction is solid and was not marked as solid before: mark as solid and propagate + if tangle.isPayloadSolid(currentPayload, currentMetadata) && currentMetadata.SetSolid(true) { + tangle.Events.PayloadSolid.Trigger(currentCachedPayload, currentCachedMetadata) + + tangle.GetApprovers(currentPayload.GetId()).Consume(func(approver *payloadapprover.PayloadApprover) { + approverTransactionId := approver.GetApprovingPayloadId() + + solidificationStack.PushBack([2]interface{}{ + tangle.GetPayload(approverTransactionId), + tangle.GetPayloadMetadata(approverTransactionId), + }) + }) + } + + // release cached results + currentCachedPayload.Release() + currentCachedMetadata.Release() + } +} + +// isPayloadSolid returns true if the given payload is solid. A payload is considered to be solid solid, if it is either +// already marked as solid or if its referenced payloads are marked as solid. +func (tangle *Tangle) isPayloadSolid(payload *valuepayload.Payload, metadata *payloadmetadata.PayloadMetadata) bool { + if payload == nil || payload.IsDeleted() { + return false + } + + if metadata == nil || metadata.IsDeleted() { + return false + } + + if metadata.IsSolid() { + return true + } + + return tangle.isPayloadMarkedAsSolid(payload.GetTrunkId()) && tangle.isPayloadMarkedAsSolid(payload.GetBranchId()) +} + +// isPayloadMarkedAsSolid returns true if the payload was marked as solid already (by setting the corresponding flags +// in its metadata. +func (tangle *Tangle) isPayloadMarkedAsSolid(payloadId payloadid.Id) bool { + if payloadId == payloadid.Genesis { + return true + } + + transactionMetadataCached := tangle.GetPayloadMetadata(payloadId) + if transactionMetadata := transactionMetadataCached.Unwrap(); transactionMetadata == nil { + transactionMetadataCached.Release() + + // if transaction is missing and was not reported as missing, yet + if cachedMissingPayload, missingPayloadStored := tangle.missingPayloadStorage.StoreIfAbsent(missingpayload.New(payloadId)); missingPayloadStored { + cachedMissingPayload.Consume(func(object objectstorage.StorableObject) { + tangle.Events.PayloadMissing.Trigger(object.(*missingpayload.MissingPayload).GetId()) + }) + } + + return false + } else if !transactionMetadata.IsSolid() { + transactionMetadataCached.Release() + + return false + } + transactionMetadataCached.Release() + + return true +} diff --git a/packages/binary/valuetransfer/tangle/tangle_test.go b/packages/binary/valuetransfer/tangle/tangle_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b271eaa336291fe77c3c2f527365f45af7d20f5d --- /dev/null +++ b/packages/binary/valuetransfer/tangle/tangle_test.go @@ -0,0 +1,66 @@ +package tangle + +import ( + "fmt" + "io/ioutil" + "os" + "testing" + + "github.com/iotaledger/hive.go/events" + "github.com/stretchr/testify/require" + + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance/color" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer" + transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/inputs" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/outputs" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/tangle/payloadmetadata" + transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transferoutput/id" + "github.com/iotaledger/goshimmer/packages/database" + "github.com/iotaledger/goshimmer/plugins/config" +) + +func TestTangle_AttachPayload(t *testing.T) { + dir, err := ioutil.TempDir("", t.Name()) + require.NoError(t, err) + defer os.Remove(dir) + + config.Node.Set(database.CFG_DIRECTORY, dir) + + tangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE")) + if err := tangle.Prune(); err != nil { + t.Error(err) + + return + } + + tangle.Events.PayloadSolid.Attach(events.NewClosure(func(payload *payload.CachedObject, metadata *payloadmetadata.CachedObject) { + fmt.Println(payload.Unwrap()) + + payload.Release() + metadata.Release() + })) + + addressKeyPair1 := ed25119.GenerateKeyPair() + addressKeyPair2 := ed25119.GenerateKeyPair() + + tangle.AttachPayload(payload.New(id.Genesis, id.Genesis, transfer.New( + inputs.New( + transferoutputid.New(address.FromED25519PubKey(addressKeyPair1.PublicKey), transferid.New([]byte("transfer1"))), + transferoutputid.New(address.FromED25519PubKey(addressKeyPair2.PublicKey), transferid.New([]byte("transfer2"))), + ), + + outputs.New(map[address.Address][]*coloredbalance.ColoredBalance{ + address.New([]byte("output_address")): { + coloredbalance.New(color.IOTA, 1337), + }, + }), + ))) + + tangle.Shutdown() +} diff --git a/packages/binary/valuetransfers/test/payload_test.go b/packages/binary/valuetransfer/test/payload_test.go similarity index 78% rename from packages/binary/valuetransfers/test/payload_test.go rename to packages/binary/valuetransfer/test/payload_test.go index 6a91a62837450552a8e74e7a80d48dcaabaf777e..11b8e1454c34d50be8a0037aca9a3a26947fbfcf 100644 --- a/packages/binary/valuetransfers/test/payload_test.go +++ b/packages/binary/valuetransfer/test/payload_test.go @@ -6,20 +6,19 @@ import ( "github.com/stretchr/testify/assert" - "github.com/iotaledger/goshimmer/packages/binary/identity" "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/coloredbalance" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/coloredbalance/color" - valuepayload "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload" - payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer" - transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/id" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/inputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/outputs" - "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/signatures" - transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/transferoutput/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/coloredbalance/color" + valuepayload "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload" + payloadid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer" + transferid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/inputs" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/outputs" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/signatures" + transferoutputid "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transferoutput/id" ) func ExamplePayload() { @@ -42,10 +41,10 @@ func ExamplePayload() { // 2. create value payload (the ontology creates this and wraps the user provided transfer accordingly) valuePayload := valuepayload.New( // trunk in "value transfer ontology" (filled by ontology tipSelector) - payloadid.Empty, + payloadid.Genesis, // branch in "value transfer ontology" (filled by ontology tipSelector) - payloadid.Empty, + payloadid.Genesis, // value transfer valueTransfer, @@ -60,7 +59,7 @@ func ExamplePayload() { transaction.EmptyId, // issuer of the transaction (signs automatically) - identity.Generate(), + ed25119.GenerateKeyPair(), // payload valuePayload, @@ -74,8 +73,8 @@ func TestPayload(t *testing.T) { addressKeyPair2 := ed25119.GenerateKeyPair() originalPayload := valuepayload.New( - payloadid.Empty, - payloadid.Empty, + payloadid.Genesis, + payloadid.Genesis, transfer.New( inputs.New( transferoutputid.New(address.FromED25519PubKey(addressKeyPair1.PublicKey), transferid.New([]byte("transfer1"))), diff --git a/packages/binary/valuetransfers/transferoutput/id/id.go b/packages/binary/valuetransfer/transferoutput/id/id.go similarity index 95% rename from packages/binary/valuetransfers/transferoutput/id/id.go rename to packages/binary/valuetransfer/transferoutput/id/id.go index 0d2c7e95c96aecb91d501886442760366d31ce69..b43b9491f95eb98c78a9e4748891d662e0f64889 100644 --- a/packages/binary/valuetransfers/transferoutput/id/id.go +++ b/packages/binary/valuetransfer/transferoutput/id/id.go @@ -3,8 +3,8 @@ package id import ( "github.com/mr-tron/base58" - address2 "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" - id2 "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/id" + address2 "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address" + id2 "github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload/transfer/id" ) type Id [Length]byte diff --git a/packages/binary/valuetransfers/payload/transfer/id/id.go b/packages/binary/valuetransfers/payload/transfer/id/id.go deleted file mode 100644 index 3f25a8790726f6240cadae26e566ddd68941b430..0000000000000000000000000000000000000000 --- a/packages/binary/valuetransfers/payload/transfer/id/id.go +++ /dev/null @@ -1,19 +0,0 @@ -package id - -import ( - "github.com/mr-tron/base58" -) - -type Id [Length]byte - -func New(idBytes []byte) (result Id) { - copy(result[:], idBytes) - - return -} - -func (id Id) String() string { - return base58.Encode(id[:]) -} - -const Length = 32 diff --git a/plugins/gossip/gossip.go b/plugins/gossip/gossip.go index 4995280f2ba1824f44b49d7f2817cbfd0f152b9a..7eaf015f846557a3d89f2a3c67e7e8a3c3163bf6 100644 --- a/plugins/gossip/gossip.go +++ b/plugins/gossip/gossip.go @@ -80,7 +80,7 @@ func getTransaction(transactionId transaction.Id) (bytes []byte, err error) { log.Debugw("get tx from db", "id", transactionId.String()) if !tangle.Instance.GetTransaction(transactionId).Consume(func(transaction *transaction.Transaction) { - bytes = transaction.GetBytes() + bytes = transaction.Bytes() }) { err = fmt.Errorf("transaction not found: hash=%s", transactionId) } diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go index dcf615e8af4f4220f6f58f3da88644e061a3c653..3d917c98bd06ff212ccdbc7eb72d1c8ca06bf0d0 100644 --- a/plugins/gossip/plugin.go +++ b/plugins/gossip/plugin.go @@ -81,7 +81,7 @@ func configureEvents() { transactionMetadata.Release() cachedTransaction.Consume(func(transaction *transaction.Transaction) { - mgr.SendTransaction(transaction.GetBytes()) + mgr.SendTransaction(transaction.Bytes()) }) }))