diff --git a/packages/binary/datastructure/orderedmap/orderedmap.go b/packages/binary/datastructure/orderedmap/orderedmap.go index d92c1e8c3b67f1292d87e2e50f4d09d86c984f92..fe0555421f1a5146b3f63e863c93d68192a033e5 100644 --- a/packages/binary/datastructure/orderedmap/orderedmap.go +++ b/packages/binary/datastructure/orderedmap/orderedmap.go @@ -67,14 +67,18 @@ func (orderedMap *OrderedMap) Set(key interface{}, newValue interface{}) bool { } func (orderedMap *OrderedMap) ForEach(consumer func(key, value interface{}) bool) { + orderedMap.mutex.RLock() currentEntry := orderedMap.head + orderedMap.mutex.RUnlock() for currentEntry != nil { if !consumer(currentEntry.key, currentEntry.value) { return } + orderedMap.mutex.RLock() currentEntry = currentEntry.next + orderedMap.mutex.RUnlock() } } diff --git a/packages/binary/marshalutil/marshalutil.byte.go b/packages/binary/marshalutil/marshalutil.byte.go new file mode 100644 index 0000000000000000000000000000000000000000..37e15bf71d31107e46f59e2e0c52fed7566d14e5 --- /dev/null +++ b/packages/binary/marshalutil/marshalutil.byte.go @@ -0,0 +1,20 @@ +package marshalutil + +func (util *MarshalUtil) WriteByte(byte byte) { + writeEndOffset := util.expandWriteCapacity(1) + + util.bytes[util.writeOffset] = byte + + util.WriteSeek(writeEndOffset) +} + +func (util *MarshalUtil) ReadByte() (byte, error) { + readEndOffset, err := util.checkReadCapacity(1) + if err != nil { + return 0, err + } + + defer util.ReadSeek(readEndOffset) + + return util.bytes[util.readOffset], nil +} diff --git a/packages/binary/marshalutil/marshalutil.bytes.go b/packages/binary/marshalutil/marshalutil.bytes.go index 5f2c298fce9440247db38a98e8d1326b8e56a921..22d2580acf9eb3185368cd33d893e1f0d690ade6 100644 --- a/packages/binary/marshalutil/marshalutil.bytes.go +++ b/packages/binary/marshalutil/marshalutil.bytes.go @@ -9,6 +9,10 @@ func (util *MarshalUtil) WriteBytes(bytes []byte) { } func (util *MarshalUtil) ReadBytes(length int) ([]byte, error) { + if length < 0 { + length = len(util.bytes) - util.readOffset + length + } + readEndOffset, err := util.checkReadCapacity(length) if err != nil { return nil, err diff --git a/packages/binary/marshalutil/marshalutil.go b/packages/binary/marshalutil/marshalutil.go index 733ee12f038b32b54413e2071b676375d1dbd064..f6e95e704af690b4f7cdc22fc0ec5a442e1ee722 100644 --- a/packages/binary/marshalutil/marshalutil.go +++ b/packages/binary/marshalutil/marshalutil.go @@ -56,11 +56,19 @@ func (util *MarshalUtil) WriteOffset() int { } func (util *MarshalUtil) WriteSeek(offset int) { - util.writeOffset = offset + if offset < 0 { + util.writeOffset += offset + } else { + util.writeOffset = offset + } } func (util *MarshalUtil) ReadSeek(offset int) { - util.readOffset = offset + if offset < 0 { + util.readOffset += offset + } else { + util.readOffset = offset + } } func (util *MarshalUtil) Bytes() []byte { diff --git a/packages/binary/signature/ed25119/public_key.go b/packages/binary/signature/ed25119/public_key.go index c9d58e254413349234283406c817f8c68c7d30e5..9afe9766d147c05f17b1ce6f4c7f256fc18bbb05 100644 --- a/packages/binary/signature/ed25119/public_key.go +++ b/packages/binary/signature/ed25119/public_key.go @@ -2,12 +2,27 @@ package ed25119 import ( "errors" + "fmt" "github.com/oasislabs/ed25519" ) type PublicKey [PublicKeySize]byte +func PublicKeyFromBytes(bytes []byte) (result PublicKey, err error, consumedBytes int) { + if len(bytes) < PublicKeySize { + err = fmt.Errorf("bytes too short") + + return + } + + copy(result[:], bytes) + + consumedBytes = PublicKeySize + + return +} + func (publicKey PublicKey) VerifySignature(data []byte, signature Signature) bool { return ed25519.Verify(publicKey[:], data, signature[:]) } diff --git a/packages/binary/signature/ed25119/signature.go b/packages/binary/signature/ed25119/signature.go index bd33e1138e42da2809b0dac22afa1a140d5b8c3b..d8a291eec642f9714b15160dd27ea3f8b40c5b0d 100644 --- a/packages/binary/signature/ed25119/signature.go +++ b/packages/binary/signature/ed25119/signature.go @@ -2,10 +2,25 @@ package ed25119 import ( "errors" + "fmt" ) type Signature [SignatureSize]byte +func SignatureFromBytes(bytes []byte) (result Signature, err error, consumedBytes int) { + if len(bytes) < SignatureSize { + err = fmt.Errorf("bytes too short") + + return + } + + copy(result[:SignatureSize], bytes) + + consumedBytes = SignatureSize + + return +} + func (signature *Signature) UnmarshalBinary(bytes []byte) (err error) { if len(bytes) < SignatureSize { return errors.New("not enough bytes") diff --git a/packages/binary/tangle/model/transaction/id.go b/packages/binary/tangle/model/transaction/id.go index dd5ca1544b311f85740893dd416a04358cb74267..03c17fa2b4a9a03ed11dbb23d6a203a479f40f96 100644 --- a/packages/binary/tangle/model/transaction/id.go +++ b/packages/binary/tangle/model/transaction/id.go @@ -1,30 +1,60 @@ package transaction import ( + "fmt" + "github.com/mr-tron/base58" ) type Id [IdLength]byte -func NewId(id []byte) (result Id) { - copy(result[:], id) +func NewId(base58EncodedString string) (result Id, err error) { + bytes, err := base58.Decode(base58EncodedString) + if err != nil { + return + } + + if len(bytes) != IdLength { + err = fmt.Errorf("length of base58 formatted transaction id is wrong") + + return + } + + copy(result[:], bytes) return } -func (id *Id) MarshalBinary() (result []byte, err error) { - result = make([]byte, IdLength) - copy(result, id[:]) +// IdFromBytes unmarshals a transaction id from a sequence of bytes. +func IdFromBytes(bytes []byte) (result Id, err error, consumedBytes int) { + // check arguments + if len(bytes) < IdLength { + err = fmt.Errorf("bytes not long enough to encode a valid transaction id") + } + + // calculate result + copy(result[:], bytes) + + // return the number of bytes we processed + consumedBytes = IdLength return } +func (id *Id) MarshalBinary() (result []byte, err error) { + return id.Bytes(), nil +} + func (id *Id) UnmarshalBinary(data []byte) (err error) { copy(id[:], data) return } +func (id Id) Bytes() []byte { + return id[:] +} + func (id Id) String() string { return base58.Encode(id[:]) } diff --git a/packages/binary/tangle/model/transaction/payload/data/data.go b/packages/binary/tangle/model/transaction/payload/data/data.go index 8b41b99ce062ee65fee8cbd25b5561bc50b7a538..84bc43b7da9be36c6479f5381dbab6bec64ffc79 100644 --- a/packages/binary/tangle/model/transaction/payload/data/data.go +++ b/packages/binary/tangle/model/transaction/payload/data/data.go @@ -1,6 +1,9 @@ package data import ( + "github.com/iotaledger/hive.go/stringify" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload" ) @@ -18,6 +21,29 @@ func New(data []byte) *Data { } } +func FromBytes(bytes []byte, optionalTargetObject ...*Data) (result *Data, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &Data{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to FromBytes") + } + + // initialize helper + marshalUtil := marshalutil.New(bytes) + + // read data + result.data = marshalUtil.ReadRemainingBytes() + + // return the number of bytes we processed + consumedBytes = marshalUtil.ReadOffset() + + return +} + func (dataPayload *Data) GetType() payload.Type { return dataPayload.payloadType } @@ -26,20 +52,34 @@ func (dataPayload *Data) GetData() []byte { return dataPayload.data } -func (dataPayload *Data) UnmarshalBinary(data []byte) error { - dataPayload.data = make([]byte, len(data)) - copy(dataPayload.data, data) +// Bytes marshals the data payload into a sequence of bytes. +func (dataPayload *Data) Bytes() []byte { + // initialize helper + marshalUtil := marshalutil.New() + + // write the data as raw bytes + marshalUtil.WriteBytes(dataPayload.data[:]) - return nil + // return result + return marshalUtil.Bytes() } -func (dataPayload *Data) MarshalBinary() (data []byte, err error) { - data = make([]byte, len(dataPayload.data)) - copy(data, dataPayload.data) +func (dataPayload *Data) UnmarshalBinary(data []byte) (err error) { + _, err, _ = FromBytes(data, dataPayload) return } +func (dataPayload *Data) MarshalBinary() (data []byte, err error) { + return dataPayload.Bytes(), nil +} + +func (dataPayload *Data) String() string { + return stringify.Struct("Data", + stringify.StructField("data", string(dataPayload.GetData())), + ) +} + func GenericPayloadUnmarshalerFactory(payloadType payload.Type) payload.Unmarshaler { return func(data []byte) (payload payload.Payload, err error) { payload = &Data{ diff --git a/packages/binary/tangle/model/transaction/payload/payload.go b/packages/binary/tangle/model/transaction/payload/payload.go index 23ff09be788c7dc242b3fd640813e43641a72f76..2d570a886866aa0cecc5972e420b1c76fb593c17 100644 --- a/packages/binary/tangle/model/transaction/payload/payload.go +++ b/packages/binary/tangle/model/transaction/payload/payload.go @@ -8,5 +8,7 @@ type Payload interface { encoding.BinaryMarshaler encoding.BinaryUnmarshaler + Bytes() []byte GetType() Type + String() string } diff --git a/packages/binary/tangle/model/transaction/test/transaction_test.go b/packages/binary/tangle/model/transaction/test/transaction_test.go index 1ca51d61b5d7b49fcf31df68a5da4a9b1b6b8708..fdac283ef304d95d19311ea4017a5e00aa49e999 100644 --- a/packages/binary/tangle/model/transaction/test/transaction_test.go +++ b/packages/binary/tangle/model/transaction/test/transaction_test.go @@ -34,7 +34,7 @@ func BenchmarkVerifyDataTransactions(b *testing.B) { for i := 0; i < b.N; i++ { currentIndex := i pool.Submit(func() { - if tx, err := transaction.FromBytes(transactions[currentIndex]); err != nil { + if tx, err, _ := transaction.FromBytes(transactions[currentIndex]); err != nil { b.Error(err) } else { tx.VerifySignature() diff --git a/packages/binary/tangle/model/transaction/transaction.go b/packages/binary/tangle/model/transaction/transaction.go index 227b30954db9086f9f640dcf954bdaa7c44c9ffe..5e662b83c3aa2e8e6bf5a1a9e1d06a20fd94a43f 100644 --- a/packages/binary/tangle/model/transaction/transaction.go +++ b/packages/binary/tangle/model/transaction/transaction.go @@ -1,12 +1,12 @@ package transaction import ( - "encoding/binary" "sync" "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/tangle/model/transaction/payload" "github.com/iotaledger/hive.go/objectstorage" @@ -60,9 +60,66 @@ func FromStorage(id []byte) (result objectstorage.StorableObject) { return } -func FromBytes(bytes []byte) (result *Transaction, err error) { - result = &Transaction{} - err = result.UnmarshalBinary(bytes) +func FromBytes(bytes []byte, optionalTargetObject ...*Transaction) (result *Transaction, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &Transaction{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to FromBytes") + } + + // 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 { + 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 { + return + } + result.branchTransactionId = branchTransactionId.(Id) + + // read issuer + publicKeyBytes, err := marshalUtil.ReadBytes(identity.PublicKeySize) + if err != nil { + return + } + result.issuer = identity.New(publicKeyBytes) + + // read payload type + payloadType, err := marshalUtil.ReadUint32() + if 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 { + return + } + + // read signature + copy(result.signature[:], marshalUtil.ReadRemainingBytes()) + + // store marshaled version + result.bytes = make([]byte, len(bytes)) + copy(result.bytes, bytes) + + // return the number of bytes we processed + consumedBytes = marshalUtil.ReadOffset() return } @@ -167,91 +224,41 @@ func (transaction *Transaction) calculatePayloadId() payload.Id { return blake2b.Sum512(bytes[2*IdLength:]) } -// Since transactions are immutable and do not get changed after being created, we cache the result of the marshaling. -func (transaction *Transaction) MarshalBinary() (result []byte, err error) { +func (transaction *Transaction) Bytes() []byte { transaction.bytesMutex.RLock() - if transaction.bytes == nil { - transaction.bytesMutex.RUnlock() - - transaction.bytesMutex.Lock() - if transaction.bytes == nil { - var serializedPayload []byte - if transaction.payload != nil { - if serializedPayload, err = transaction.payload.MarshalBinary(); err != nil { - return - } - } - serializedPayloadLength := len(serializedPayload) - - result = make([]byte, IdLength+IdLength+identity.PublicKeySize+4+serializedPayloadLength+identity.SignatureSize) - offset := 0 - - copy(result[offset:], transaction.trunkTransactionId[:]) - offset += IdLength - - copy(result[offset:], transaction.branchTransactionId[:]) - offset += IdLength - - if transaction.issuer != nil { - copy(result[offset:], transaction.issuer.PublicKey) - } - offset += identity.PublicKeySize - - binary.LittleEndian.PutUint32(result[offset:], transaction.payload.GetType()) - offset += 4 - - if serializedPayloadLength != 0 { - copy(result[offset:], serializedPayload) - offset += serializedPayloadLength - } - - if transaction.issuer != nil { - transaction.signatureMutex.Lock() - copy(transaction.signature[:], transaction.issuer.Sign(result[:offset])) - transaction.signatureMutex.Unlock() - copy(result[offset:], transaction.signature[:]) - } - // offset += identity.SignatureSize - - transaction.bytes = result - } else { - result = transaction.bytes - } - transaction.bytesMutex.Unlock() - } else { - result = transaction.bytes + if transaction.bytes != nil { + defer transaction.bytesMutex.RUnlock() - transaction.bytesMutex.RUnlock() + return transaction.bytes } - return -} - -func (transaction *Transaction) UnmarshalBinary(data []byte) (err error) { - offset := 0 - - copy(transaction.trunkTransactionId[:], data[offset:]) - offset += IdLength + transaction.bytesMutex.RUnlock() + transaction.bytesMutex.RLock() + defer transaction.bytesMutex.RUnlock() - copy(transaction.branchTransactionId[:], data[offset:]) - offset += IdLength + if transaction.bytes != nil { + return transaction.bytes + } - transaction.issuer = identity.New(data[offset : offset+identity.PublicKeySize]) - offset += identity.PublicKeySize + marshalUtil := marshalutil.New() - payloadType := binary.LittleEndian.Uint32(data[offset:]) - offset += 4 + marshalUtil.WriteBytes(transaction.trunkTransactionId.Bytes()) + marshalUtil.WriteBytes(transaction.branchTransactionId.Bytes()) + marshalUtil.WriteBytes(transaction.issuer.PublicKey) + marshalUtil.WriteUint32(transaction.payload.GetType()) + marshalUtil.WriteBytes(transaction.payload.Bytes()) + marshalUtil.WriteBytes(transaction.issuer.Sign(marshalUtil.Bytes())) - if transaction.payload, err = payload.GetUnmarshaler(payloadType)(data[offset : len(data)-identity.SignatureSize]); err != nil { - return - } - offset += len(data) - identity.SignatureSize - offset + return marshalUtil.Bytes() +} - copy(transaction.signature[:], data[offset:]) - // offset += identity.SignatureSize +// Since transactions are immutable and do not get changed after being created, we cache the result of the marshaling. +func (transaction *Transaction) MarshalBinary() (result []byte, err error) { + return transaction.Bytes(), nil +} - transaction.bytes = make([]byte, len(data)) - copy(transaction.bytes, data) +func (transaction *Transaction) UnmarshalBinary(data []byte) (err error) { + _, err, _ = FromBytes(data, transaction) return } diff --git a/packages/binary/tangle/transactionparser/transactionparser.go b/packages/binary/tangle/transactionparser/transactionparser.go index f1568d49796a6b1dd9fc16917b3fdac6daeade91..8aa1c56d36ea23243587b33fdd33b69480e96885 100644 --- a/packages/binary/tangle/transactionparser/transactionparser.go +++ b/packages/binary/tangle/transactionparser/transactionparser.go @@ -136,7 +136,7 @@ func (transactionParser *TransactionParser) setupTransactionsFilterDataFlow() { } func (transactionParser *TransactionParser) parseTransaction(bytes []byte, peer *peer.Peer) { - if parsedTransaction, err := transaction.FromBytes(bytes); err != nil { + if parsedTransaction, err, _ := transaction.FromBytes(bytes); err != nil { transactionParser.Events.BytesRejected.Trigger(bytes, err, peer) } else { transactionParser.transactionFilters[0].Filter(parsedTransaction, peer) diff --git a/packages/binary/valuetransfers/address/address.go b/packages/binary/valuetransfers/address/address.go index 22947afa4936af755cd8e9a0f1b204dd2cd4cb5e..17cfddba141ff76a67a3b25fa992474746ff660d 100644 --- a/packages/binary/valuetransfers/address/address.go +++ b/packages/binary/valuetransfers/address/address.go @@ -2,6 +2,9 @@ package address import ( "github.com/mr-tron/base58" + "golang.org/x/crypto/blake2b" + + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" ) type AddressVersion = byte @@ -16,6 +19,15 @@ func New(bytes []byte) (address Address) { return } +func FromED25519PubKey(key ed25119.PublicKey) (address Address) { + digest := blake2b.Sum256(key[:]) + + address[0] = 0 + copy(address[1:], digest[:]) + + return +} + func (address *Address) GetVersion() AddressVersion { return address[0] } diff --git a/packages/binary/valuetransfers/coloredbalance/coloredbalance.go b/packages/binary/valuetransfers/coloredbalance/coloredbalance.go index 26b0a485207480e384c52f644299daf5c55649a3..6d8f576bb570575d1e841549f828371c99370a32 100644 --- a/packages/binary/valuetransfers/coloredbalance/coloredbalance.go +++ b/packages/binary/valuetransfers/coloredbalance/coloredbalance.go @@ -44,7 +44,7 @@ func FromBytes(bytes []byte) (result *ColoredBalance, err error, consumedBytes i return } -func (balance *ColoredBalance) ToBytes() []byte { +func (balance *ColoredBalance) Bytes() []byte { marshalUtil := marshalutil.New(color.Length + marshalutil.UINT32_SIZE) marshalUtil.WriteBytes(balance.color.Bytes()) diff --git a/packages/binary/valuetransfers/payload/transfer/inputs/inputs.go b/packages/binary/valuetransfers/payload/transfer/inputs/inputs.go index d36935b03eb1a87859a4733605b841b488c88dce..bfb7e68840cfb082de4ac3d0269dcb2c5484223e 100644 --- a/packages/binary/valuetransfers/payload/transfer/inputs/inputs.go +++ b/packages/binary/valuetransfers/payload/transfer/inputs/inputs.go @@ -78,7 +78,7 @@ func (inputs *Inputs) Add(input transferoutputid.Id) *Inputs { return inputs } -func (inputs *Inputs) ToBytes() (bytes []byte) { +func (inputs *Inputs) Bytes() (bytes []byte) { marshalUtil := marshalutil.New() marshalUtil.WriteSeek(4) @@ -106,11 +106,9 @@ func (inputs *Inputs) ForEach(consumer func(transferOutputId transferoutputid.Id }) } -func (inputs *Inputs) ForEachAddress(consumer func(currentAddress address.Address)) { +func (inputs *Inputs) ForEachAddress(consumer func(currentAddress address.Address) bool) { inputs.OrderedMap.ForEach(func(key, value interface{}) bool { - consumer(key.(address.Address)) - - return true + return consumer(key.(address.Address)) }) } diff --git a/packages/binary/valuetransfers/payload/transfer/outputs/outputs.go b/packages/binary/valuetransfers/payload/transfer/outputs/outputs.go index 4c66d7ef0a0d2dceeb3d61000691b5bde1d9cb49..7a6d94febd64f14aa4178c2e832d296edfb1603b 100644 --- a/packages/binary/valuetransfers/payload/transfer/outputs/outputs.go +++ b/packages/binary/valuetransfers/payload/transfer/outputs/outputs.go @@ -3,15 +3,15 @@ package outputs import ( "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/marshalutil" - address2 "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" - coloredbalance2 "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/coloredbalance" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/coloredbalance" ) type Outputs struct { *orderedmap.OrderedMap } -func New(outputs map[address2.Address][]*coloredbalance2.ColoredBalance) (result *Outputs) { +func New(outputs map[address.Address][]*coloredbalance.ColoredBalance) (result *Outputs) { result = &Outputs{orderedmap.New()} for address, balances := range outputs { result.Add(address, balances) @@ -37,23 +37,21 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, marshalUtil := marshalutil.New(bytes) // read number of addresses in the outputs - addressCount, addressCountErr := marshalUtil.ReadUint32() - if addressCountErr != nil { - err = addressCountErr - + addressCount, err := marshalUtil.ReadUint32() + if err != nil { return } // iterate the corresponding times and collect addresses + their details for i := uint32(0); i < addressCount; i++ { // read address - addressBytes, addressErr := marshalUtil.ReadBytes(address2.Length) + addressBytes, addressErr := marshalUtil.ReadBytes(address.Length) if addressErr != nil { err = addressErr return } - address := address2.New(addressBytes) + address := address.New(addressBytes) // read number of balances in the outputs balanceCount, balanceCountErr := marshalUtil.ReadUint32() @@ -64,16 +62,16 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, } // iterate the corresponding times and collect balances - coloredBalances := make([]*coloredbalance2.ColoredBalance, balanceCount) + coloredBalances := make([]*coloredbalance.ColoredBalance, balanceCount) for j := uint32(0); j < balanceCount; j++ { - coloredBalance, coloredBalanceErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return coloredbalance2.FromBytes(data) }) + coloredBalance, coloredBalanceErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return coloredbalance.FromBytes(data) }) if coloredBalanceErr != nil { err = coloredBalanceErr return } - coloredBalances[j] = coloredBalance.(*coloredbalance2.ColoredBalance) + coloredBalances[j] = coloredBalance.(*coloredbalance.ColoredBalance) } // add the gathered information as an output @@ -86,15 +84,15 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, return } -func (outputs *Outputs) Add(address address2.Address, balances []*coloredbalance2.ColoredBalance) *Outputs { +func (outputs *Outputs) Add(address address.Address, balances []*coloredbalance.ColoredBalance) *Outputs { outputs.Set(address, balances) return outputs } -func (outputs *Outputs) ForEach(consumer func(address address2.Address, balances []*coloredbalance2.ColoredBalance)) { +func (outputs *Outputs) ForEach(consumer func(address address.Address, balances []*coloredbalance.ColoredBalance)) { outputs.OrderedMap.ForEach(func(key, value interface{}) bool { - consumer(key.(address2.Address), value.([]*coloredbalance2.ColoredBalance)) + consumer(key.(address.Address), value.([]*coloredbalance.ColoredBalance)) return true }) @@ -110,12 +108,12 @@ func (outputs *Outputs) Bytes() []byte { } marshalUtil.WriteUint32(uint32(outputs.Size())) - outputs.ForEach(func(address address2.Address, balances []*coloredbalance2.ColoredBalance) { + outputs.ForEach(func(address address.Address, balances []*coloredbalance.ColoredBalance) { marshalUtil.WriteBytes(address.ToBytes()) marshalUtil.WriteUint32(uint32(len(balances))) for _, balance := range balances { - marshalUtil.WriteBytes(balance.ToBytes()) + marshalUtil.WriteBytes(balance.Bytes()) } }) @@ -129,7 +127,7 @@ func (outputs *Outputs) String() string { result := "[\n" empty := true - outputs.ForEach(func(address address2.Address, balances []*coloredbalance2.ColoredBalance) { + outputs.ForEach(func(address address.Address, balances []*coloredbalance.ColoredBalance) { empty = false result += " " + address.String() + ": [\n" diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/ed25519.go b/packages/binary/valuetransfers/payload/transfer/signatures/ed25519.go new file mode 100644 index 0000000000000000000000000000000000000000..17cdc17d78cfa4f7d1ac016e5a11f231f57fe4b3 --- /dev/null +++ b/packages/binary/valuetransfers/payload/transfer/signatures/ed25519.go @@ -0,0 +1,134 @@ +package signatures + +import ( + "fmt" + + "github.com/iotaledger/goshimmer/packages/binary/marshalutil" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" +) + +// region PUBLIC API /////////////////////////////////////////////////////////////////////////////////////////////////// + +const ( + // every signature scheme has a version byte associated to it. + VERSION_ED25519 = byte(1) +) + +// ED25519 creates an instance of a signature scheme, that is used to sign the corresponding address. +func ED25519(keyPair ed25119.KeyPair) SignatureScheme { + return &ed25519SignatureScheme{ + keyPair: keyPair, + } +} + +// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// region signature scheme implementation ////////////////////////////////////////////////////////////////////////////// + +// ed25519SignatureScheme defines an interface for ED25519 elliptic curve signatures. +type ed25519SignatureScheme struct { + keyPair ed25119.KeyPair +} + +// Version returns the version byte that is associated to this signature scheme. +func (signatureScheme *ed25519SignatureScheme) Version() byte { + return VERSION_ED25519 +} + +// Address returns the address that this signature scheme instance is securing. +func (signatureScheme *ed25519SignatureScheme) Address() address.Address { + return address.FromED25519PubKey(signatureScheme.keyPair.PublicKey) +} + +// Sign creates a valid signature for the given data according to the signature scheme implementation. +func (signatureScheme *ed25519SignatureScheme) Sign(data []byte) Signature { + return &ed25519Signature{ + publicKey: signatureScheme.keyPair.PublicKey, + signature: signatureScheme.keyPair.PrivateKey.Sign(data), + } +} + +// interface contract (allow the compiler to check if the implementation has all of the required methods). +var _ SignatureScheme = &ed25519SignatureScheme{} + +// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// region signature implementation ///////////////////////////////////////////////////////////////////////////////////// + +// ed25519Signature represents a signature for an addresses that uses elliptic curve cryptography. +type ed25519Signature struct { + publicKey ed25119.PublicKey + signature ed25119.Signature +} + +// ed25519SignatureFromBytes unmarshals an ed25519 signatures from a sequence of bytes. +// It either creates a new signature or fills the optionally provided object with the parsed information. +func ed25519SignatureFromBytes(bytes []byte, optionalTargetObject ...*ed25519Signature) (result *ed25519Signature, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &ed25519Signature{} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to ed25519SignatureFromBytes") + } + + // initialize helper + marshalUtil := marshalutil.New(bytes) + + // read version + versionByte, err := marshalUtil.ReadByte() + if err != nil { + return + } else if versionByte != VERSION_ED25519 { + err = fmt.Errorf("invalid version byte when parsing ed25519 signature") + + return + } + + // read public key + publicKey, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return ed25119.PublicKeyFromBytes(data) }) + if err != nil { + return + } + result.publicKey = publicKey.(ed25119.PublicKey) + + // read signature + signature, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return ed25119.SignatureFromBytes(data) }) + if err != nil { + return + } + result.signature = signature.(ed25119.Signature) + + // return the number of bytes we processed + consumedBytes = marshalUtil.ReadOffset() + + return +} + +// IsValid returns true if the signature is valid for the given data. +func (signature *ed25519Signature) IsValid(signedData []byte) bool { + return signature.publicKey.VerifySignature(signedData, signature.signature) +} + +// Bytes returns a marshaled version of the signature. +func (signature *ed25519Signature) Bytes() []byte { + marshalUtil := marshalutil.New(1 + ed25119.PublicKeySize + ed25119.SignatureSize) + marshalUtil.WriteByte(VERSION_ED25519) + marshalUtil.WriteBytes(signature.publicKey[:]) + marshalUtil.WriteBytes(signature.signature[:]) + + return marshalUtil.Bytes() +} + +// Address returns the address, that this signature signs. +func (signature *ed25519Signature) Address() address.Address { + return address.FromED25519PubKey(signature.publicKey) +} + +// interface contract (allow the compiler to check if the implementation has all of the required methods). +var _ Signature = &ed25519Signature{} + +// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/interfaces.go b/packages/binary/valuetransfers/payload/transfer/signatures/interfaces.go new file mode 100644 index 0000000000000000000000000000000000000000..9b28078ff953206e6c3aedcb12ca36e7b59d66db --- /dev/null +++ b/packages/binary/valuetransfers/payload/transfer/signatures/interfaces.go @@ -0,0 +1,27 @@ +package signatures + +import "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" + +// SignatureScheme defines an interface for different signature generation methods (i.e. ED25519, WOTS, and so on ...). +type SignatureScheme interface { + // Version returns the version byte that is associated to this signature scheme. + Version() byte + + // Address returns the address that this signature scheme instance is securing. + Address() address.Address + + // Sign creates a valid signature for the given data according to the signature scheme implementation. + Sign(data []byte) Signature +} + +// Signature defines an interface for an address signature generated by the corresponding signature scheme. +type Signature interface { + // IsValid returns true if the signature is valid for the given data. + IsValid(signedData []byte) bool + + // Bytes returns a marshaled version of the signature. + Bytes() []byte + + // Address returns the address, that this signature signs. + Address() address.Address +} diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/signatures.go b/packages/binary/valuetransfers/payload/transfer/signatures/signatures.go index 87f18aacd027ce65b3eafd1b9e772e489e324e93..f5cfee2cfe03550a9282eefabcaf2ea6617eacc2 100644 --- a/packages/binary/valuetransfers/payload/transfer/signatures/signatures.go +++ b/packages/binary/valuetransfers/payload/transfer/signatures/signatures.go @@ -1,4 +1,117 @@ 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" +) + +// Signatures represents a container for the address signatures of a value transfer. +// It internally manages the list of signatures as an ordered map, so that the serialization order is deterministic and +// produces the same sequence of bytes during marshaling and unmarshaling. type Signatures struct { + orderedMap *orderedmap.OrderedMap +} + +// New creates an empty container for the address signatures of a value transfer. +func New() *Signatures { + return &Signatures{ + orderedMap: orderedmap.New(), + } +} + +// FromBytes unmarshals a container with signatures 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 ...*Signatures) (result *Signatures, err error, consumedBytes int) { + // determine the target object that will hold the unmarshaled information + switch len(optionalTargetObject) { + case 0: + result = &Signatures{orderedMap: orderedmap.New()} + case 1: + result = optionalTargetObject[0] + default: + panic("too many arguments in call to FromBytes") + } + + // initialize helper + marshalUtil := marshalutil.New(bytes) + + // read version + versionByte, err := marshalUtil.ReadByte() + if err != nil { + return + } + + // 0 byte encodes the end of the signatures + for versionByte != 0 { + // perform signature scheme specific decoding + switch versionByte { + case VERSION_ED25519: + marshalUtil.ReadSeek(-1) + signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return ed25519SignatureFromBytes(data) }) + if signatureErr != nil { + err = signatureErr + + return + } + typeCastedSignature := signature.(Signature) + + result.orderedMap.Set(typeCastedSignature.Address(), typeCastedSignature) + } + + // read version of next signature + if versionByte, err = marshalUtil.ReadByte(); err != nil { + return + } + } + + // return the number of bytes we processed + consumedBytes = marshalUtil.ReadOffset() + + return +} + +func (signatures *Signatures) Add(address address.Address, signature Signature) { + signatures.orderedMap.Set(address, signature) +} + +func (signatures *Signatures) Get(address address.Address) (Signature, bool) { + signature, exists := signatures.orderedMap.Get(address) + if !exists { + return nil, false + } + + return signature.(Signature), exists +} + +// Size returns the amount of signatures in this container. +func (signatures *Signatures) Size() int { + return signatures.orderedMap.Size() +} + +// ForEach iterates through all signatures, calling the consumer for every found entry. +// The iteration can be aborted by the consumer returning false +func (signatures *Signatures) ForEach(consumer func(address address.Address, signature Signature) bool) { + signatures.orderedMap.ForEach(func(key, value interface{}) bool { + return consumer(key.(address.Address), value.(Signature)) + }) +} + +// Bytes marshals the signatures into a sequence of bytes. +func (signatures *Signatures) Bytes() []byte { + // initialize helper + marshalUtil := marshalutil.New() + + // iterate through signatures and dump them + signatures.ForEach(func(address address.Address, signature Signature) bool { + marshalUtil.WriteBytes(signature.Bytes()) + + return true + }) + + // trailing 0 to indicate the end of signatures + marshalUtil.WriteByte(0) + + // return result + return marshalUtil.Bytes() } diff --git a/packages/binary/valuetransfers/payload/transfer/signatures/signatures_test.go b/packages/binary/valuetransfers/payload/transfer/signatures/signatures_test.go new file mode 100644 index 0000000000000000000000000000000000000000..a4aca5092e78ebceb620719f23be35249aee5779 --- /dev/null +++ b/packages/binary/valuetransfers/payload/transfer/signatures/signatures_test.go @@ -0,0 +1,48 @@ +package signatures + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" + "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/address" +) + +func TestSignatures(t *testing.T) { + dataToSign := []byte("test") + + address1SigScheme := ED25519(ed25119.GenerateKeyPair()) + address2SigScheme := ED25519(ed25119.GenerateKeyPair()) + + signatures := New() + signatures.Add(address1SigScheme.Address(), address1SigScheme.Sign(dataToSign)) + signatures.Add(address2SigScheme.Address(), address2SigScheme.Sign(dataToSign)) + + assert.Equal(t, 2, signatures.Size()) + + signatures.Add(address1SigScheme.Address(), address1SigScheme.Sign(dataToSign)) + + assert.Equal(t, 2, signatures.Size()) + + signatures.ForEach(func(address address.Address, signature Signature) bool { + assert.Equal(t, true, signature.IsValid(dataToSign)) + + return true + }) + + clonedSignatures, err, _ := FromBytes(signatures.Bytes()) + if err != nil { + t.Error(err) + + return + } + + assert.Equal(t, 2, clonedSignatures.Size()) + + clonedSignatures.ForEach(func(address address.Address, signature Signature) bool { + assert.Equal(t, true, signature.IsValid(dataToSign)) + + return true + }) +} diff --git a/packages/binary/valuetransfers/payload/transfer/transfer.go b/packages/binary/valuetransfers/payload/transfer/transfer.go index ab9f3bfafc6002412e26c95729c49a8cf970b398..fd041ce5481d164b84964cc7efc5c073a7756803 100644 --- a/packages/binary/valuetransfers/payload/transfer/transfer.go +++ b/packages/binary/valuetransfers/payload/transfer/transfer.go @@ -10,7 +10,7 @@ import ( "golang.org/x/crypto/blake2b" "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/valuetransfers/payload/transfer/id" "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/inputs" "github.com/iotaledger/goshimmer/packages/binary/valuetransfers/payload/transfer/outputs" @@ -41,8 +41,9 @@ type Transfer struct { func New(inputs *inputs.Inputs, outputs *outputs.Outputs) *Transfer { return &Transfer{ - inputs: inputs, - outputs: outputs, + inputs: inputs, + outputs: outputs, + signatures: signatures.New(), } } @@ -74,8 +75,25 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Transfer) (result *Transfe } result.outputs = parsedOutputs.(*outputs.Outputs) + // store essence bytes + essenceBytesCount := marshalUtil.ReadOffset() + result.essenceBytes = make([]byte, essenceBytesCount) + copy(result.essenceBytes, bytes[:essenceBytesCount]) + + // unmarshal outputs + parsedSignatures, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return signatures.FromBytes(data) }) + if err != nil { + return + } + result.signatures = parsedSignatures.(*signatures.Signatures) + + // store signature bytes + signatureBytesCount := marshalUtil.ReadOffset() - essenceBytesCount + result.signatureBytes = make([]byte, signatureBytesCount) + copy(result.signatureBytes, bytes[essenceBytesCount:essenceBytesCount+signatureBytesCount]) + // return the number of bytes we processed - consumedBytes = marshalUtil.ReadOffset() + consumedBytes = essenceBytesCount + signatureBytesCount // store bytes, so we don't have to marshal manually result.bytes = bytes[:consumedBytes] @@ -84,10 +102,10 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Transfer) (result *Transfe } func FromStorage(key []byte) *Transfer { - id := id.New(key) + transferId := id.New(key) return &Transfer{ - id: &id, + id: &transferId, } } @@ -122,8 +140,81 @@ func (transfer *Transfer) GetId() id.Id { return transferId } +func (transfer *Transfer) SignaturesValid() bool { + signaturesValid := true + transfer.inputs.ForEachAddress(func(address address.Address) bool { + if signature, exists := transfer.signatures.Get(address); !exists || !signature.IsValid(transfer.EssenceBytes()) { + signaturesValid = false + + return false + } + + return true + }) + + return signaturesValid +} + +func (transfer *Transfer) EssenceBytes() []byte { + // acquire read lock on essenceBytes + transfer.essenceBytesMutex.RLock() + + // return essenceBytes if the object has been marshaled already + if transfer.essenceBytes != nil { + defer transfer.essenceBytesMutex.RUnlock() + + return transfer.essenceBytes + } + + // switch to write lock + transfer.essenceBytesMutex.RUnlock() + transfer.essenceBytesMutex.Lock() + defer transfer.essenceBytesMutex.Unlock() + + // return essenceBytes if the object has been marshaled in the mean time + if essenceBytes := transfer.essenceBytes; essenceBytes != nil { + return essenceBytes + } + + // create marshal helper + marshalUtil := marshalutil.New() + + // marshal inputs + marshalUtil.WriteBytes(transfer.inputs.Bytes()) + + // marshal outputs + marshalUtil.WriteBytes(transfer.outputs.Bytes()) + + // store marshaled result + transfer.essenceBytes = marshalUtil.Bytes() + + return transfer.essenceBytes +} + +func (transfer *Transfer) SignatureBytes() []byte { + transfer.signatureBytesMutex.RLock() + if transfer.signatureBytes != nil { + defer transfer.signatureBytesMutex.RUnlock() + + return transfer.signatureBytes + } + + transfer.signatureBytesMutex.RUnlock() + transfer.signatureBytesMutex.Lock() + defer transfer.signatureBytesMutex.Unlock() + + if transfer.signatureBytes != nil { + return transfer.signatureBytes + } + + // generate signatures + transfer.signatureBytes = transfer.signatures.Bytes() + + return transfer.signatureBytes +} + func (transfer *Transfer) Bytes() []byte { - // acquired read lock on bytes + // acquire read lock on bytes transfer.bytesMutex.RLock() // return bytes if the object has been marshaled already @@ -146,11 +237,11 @@ func (transfer *Transfer) Bytes() []byte { // create marshal helper marshalUtil := marshalutil.New() - // marshal inputs - marshalUtil.WriteBytes(transfer.inputs.ToBytes()) + // marshal essence bytes + marshalUtil.WriteBytes(transfer.EssenceBytes()) - // marshal outputs - marshalUtil.WriteBytes(transfer.outputs.Bytes()) + // marshal signature bytes + marshalUtil.WriteBytes(transfer.SignatureBytes()) // store marshaled result transfer.bytes = marshalUtil.Bytes() @@ -158,8 +249,10 @@ func (transfer *Transfer) Bytes() []byte { return transfer.bytes } -func (transfer *Transfer) Sign(pair ed25119.KeyPair) { - //transfer.signatures[pair.PublicKey] = pair.PrivateKey.Sign(transfer.Bytes()) +func (transfer *Transfer) Sign(signature signatures.SignatureScheme) *Transfer { + transfer.signatures.Add(signature.Address(), signature.Sign(transfer.EssenceBytes())) + + return transfer } func (transfer *Transfer) String() string { diff --git a/packages/binary/valuetransfers/test/payload_test.go b/packages/binary/valuetransfers/test/payload_test.go index ae7cc819511c3d4d7a9ea140afdca86508d679ae..6a91a62837450552a8e74e7a80d48dcaabaf777e 100644 --- a/packages/binary/valuetransfers/test/payload_test.go +++ b/packages/binary/valuetransfers/test/payload_test.go @@ -4,7 +4,10 @@ import ( "fmt" "testing" + "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" @@ -15,6 +18,7 @@ import ( 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" ) @@ -66,14 +70,16 @@ func ExamplePayload() { } func TestPayload(t *testing.T) { + addressKeyPair1 := ed25119.GenerateKeyPair() + addressKeyPair2 := ed25119.GenerateKeyPair() originalPayload := valuepayload.New( payloadid.Empty, payloadid.Empty, transfer.New( inputs.New( - transferoutputid.New(address.New([]byte("input_address1")), transferid.New([]byte("transfer1"))), - transferoutputid.New(address.New([]byte("input_address2")), transferid.New([]byte("transfer2"))), + 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{ @@ -81,17 +87,32 @@ func TestPayload(t *testing.T) { coloredbalance.New(color.IOTA, 1337), }, }), + ).Sign( + signatures.ED25519(addressKeyPair1), ), ) - clonedPayload, err, _ := valuepayload.FromBytes(originalPayload.Bytes()) + assert.Equal(t, false, originalPayload.GetTransfer().SignaturesValid()) + + originalPayload.GetTransfer().Sign( + signatures.ED25519(addressKeyPair2), + ) + + assert.Equal(t, true, originalPayload.GetTransfer().SignaturesValid()) + + clonedPayload1, err, _ := valuepayload.FromBytes(originalPayload.Bytes()) if err != nil { panic(err) } - fmt.Println(originalPayload) - fmt.Println(clonedPayload) + assert.Equal(t, originalPayload.GetId(), clonedPayload1.GetId()) + assert.Equal(t, true, clonedPayload1.GetTransfer().SignaturesValid()) + + clonedPayload2, err, _ := valuepayload.FromBytes(clonedPayload1.Bytes()) + if err != nil { + panic(err) + } - fmt.Println(originalPayload.GetId()) - fmt.Println(clonedPayload.GetId()) + assert.Equal(t, originalPayload.GetId(), clonedPayload2.GetId()) + assert.Equal(t, true, clonedPayload2.GetTransfer().SignaturesValid()) } diff --git a/packages/gossip/manager.go b/packages/gossip/manager.go index e28c81afda3211d546a8f865ec6783a70348523c..24b72a251b8c507e86297dcf0bfa3e866d82489f 100644 --- a/packages/gossip/manager.go +++ b/packages/gossip/manager.go @@ -256,7 +256,11 @@ func (m *Manager) handlePacket(data []byte, p *peer.Peer) error { } m.log.Debugw("received message", "type", "TRANSACTION_REQUEST", "id", p.ID()) // do something - tx, err := m.getTransaction(transaction.NewId(msg.GetHash())) + txId, err, _ := transaction.IdFromBytes(msg.GetHash()) + if err != nil { + m.log.Debugw("error getting transaction", "hash", msg.GetHash(), "err", err) + } + tx, err := m.getTransaction(txId) if err != nil { m.log.Debugw("error getting transaction", "hash", msg.GetHash(), "err", err) } else { diff --git a/plugins/spa/explorer_routes.go b/plugins/spa/explorer_routes.go index c3de4085e28c7838617d4ed587daf2fab5e858bc..e98cccbbd4e4c9c6672c17b6faabe8d97ac146be 100644 --- a/plugins/spa/explorer_routes.go +++ b/plugins/spa/explorer_routes.go @@ -4,8 +4,6 @@ import ( "net/http" "sync" - "github.com/mr-tron/base58" - "github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction" "github.com/iotaledger/goshimmer/plugins/tangle" @@ -57,22 +55,9 @@ type SearchResult struct { Milestone *ExplorerTx `json:"milestone"` } -func transactionIdFromString(transactionId string) (transaction.Id, error) { - // TODO: CHECK LENGTH - - transactionIdBytes, err := base58.Decode(transactionId) - if err != nil { - return transaction.EmptyId, err - } - - // TODO: REMOVE CHECKSUM FROM STRING - - return transaction.NewId(transactionIdBytes), nil -} - func setupExplorerRoutes(routeGroup *echo.Group) { routeGroup.GET("/tx/:hash", func(c echo.Context) (err error) { - transactionId, err := transactionIdFromString(c.Param("hash")) + transactionId, err := transaction.NewId(c.Param("hash")) if err != nil { return } @@ -106,7 +91,7 @@ func setupExplorerRoutes(routeGroup *echo.Group) { go func() { defer wg.Done() - transactionId, err := transactionIdFromString(search) + transactionId, err := transaction.NewId(search) if err != nil { return }