Skip to content
Snippets Groups Projects
Commit c006a58b authored by lunfardo314's avatar lunfardo314
Browse files

- added data payload to the essence of the value transaction

- wrote tests for value transactions
parent 654f63ca
Branches
Tags
No related merge requests found
...@@ -34,6 +34,12 @@ func Random() (address Address) { ...@@ -34,6 +34,12 @@ func Random() (address Address) {
return return
} }
func RandomOfType(versionByte byte) Address {
ret := Random()
ret[0] = versionByte
return ret
}
// FromBase58 creates an address from a base58 encoded string. // FromBase58 creates an address from a base58 encoded string.
func FromBase58(base58String string) (address Address, err error) { func FromBase58(base58String string) (address Address, err error) {
// decode string // decode string
......
...@@ -70,7 +70,7 @@ func (tangle *Tangle) AttachPayload(payload *payload.Payload) { ...@@ -70,7 +70,7 @@ func (tangle *Tangle) AttachPayload(payload *payload.Payload) {
tangle.storePayloadWorkerPool.Submit(func() { tangle.storePayloadWorker(payload) }) tangle.storePayloadWorkerPool.Submit(func() { tangle.storePayloadWorker(payload) })
} }
// GetPayload retrieves a payload from the object storage. // GetDataPayload retrieves a payload from the object storage.
func (tangle *Tangle) GetPayload(payloadId payload.Id) *payload.CachedPayload { func (tangle *Tangle) GetPayload(payloadId payload.Id) *payload.CachedPayload {
return &payload.CachedPayload{CachedObject: tangle.payloadStorage.Load(payloadId.Bytes())} return &payload.CachedPayload{CachedObject: tangle.payloadStorage.Load(payloadId.Bytes())}
} }
......
...@@ -32,6 +32,10 @@ type Transaction struct { ...@@ -32,6 +32,10 @@ type Transaction struct {
signatureBytes []byte signatureBytes []byte
signatureBytesMutex sync.RWMutex signatureBytesMutex sync.RWMutex
dataPayloadType uint32
dataPayload []byte
dataPayloadMutex sync.RWMutex
bytes []byte bytes []byte
bytesMutex sync.RWMutex bytesMutex sync.RWMutex
} }
...@@ -182,6 +186,15 @@ func (transaction *Transaction) EssenceBytes() []byte { ...@@ -182,6 +186,15 @@ func (transaction *Transaction) EssenceBytes() []byte {
// marshal outputs // marshal outputs
marshalUtil.WriteBytes(transaction.outputs.Bytes()) marshalUtil.WriteBytes(transaction.outputs.Bytes())
// marshal dataPayload type
marshalUtil.WriteUint32(transaction.dataPayloadType)
// marshal dataPayload size
marshalUtil.WriteUint32(transaction.DataPayloadSize())
// marshal dataPayload data
marshalUtil.WriteBytes(transaction.dataPayload)
// store marshaled result // store marshaled result
transaction.essenceBytes = marshalUtil.Bytes() transaction.essenceBytes = marshalUtil.Bytes()
...@@ -260,9 +273,43 @@ func (transaction *Transaction) String() string { ...@@ -260,9 +273,43 @@ func (transaction *Transaction) String() string {
stringify.StructField("inputs", transaction.inputs), stringify.StructField("inputs", transaction.inputs),
stringify.StructField("outputs", transaction.outputs), stringify.StructField("outputs", transaction.outputs),
stringify.StructField("signatures", transaction.signatures), stringify.StructField("signatures", transaction.signatures),
stringify.StructField("dataPayloadSize", transaction.DataPayloadSize()),
) )
} }
// max dataPayload size limit
const MAX_DATA_PAYLOAD_SIZE = 64 * 1024
// sets yhe dataPayload and its type
func (transaction *Transaction) SetDataPayload(data []byte, payloadType uint32) error {
transaction.dataPayloadMutex.Lock()
defer transaction.dataPayloadMutex.Unlock()
if len(data) > MAX_DATA_PAYLOAD_SIZE {
return fmt.Errorf("maximum dataPayload size of %d bytes exceeded", MAX_DATA_PAYLOAD_SIZE)
}
transaction.dataPayload = data
transaction.dataPayloadType = payloadType
return nil
}
// gets the dataPayload and its type
func (transaction *Transaction) GetDataPayload() ([]byte, uint32) {
transaction.dataPayloadMutex.RLock()
defer transaction.dataPayloadMutex.RUnlock()
return transaction.dataPayload, transaction.dataPayloadType
}
// return size of the dataPayload as uint32
// nil payload as size 0
func (transaction *Transaction) DataPayloadSize() uint32 {
transaction.dataPayloadMutex.RLock()
defer transaction.dataPayloadMutex.RUnlock()
return uint32(len(transaction.dataPayload))
}
// endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// region IMPLEMENT StorableObject interface /////////////////////////////////////////////////////////////////////////// // region IMPLEMENT StorableObject interface ///////////////////////////////////////////////////////////////////////////
...@@ -301,6 +348,30 @@ func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (err e ...@@ -301,6 +348,30 @@ func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (err e
} }
transaction.outputs = parsedOutputs.(*Outputs) transaction.outputs = parsedOutputs.(*Outputs)
// unmarshal data payload type
transaction.dataPayloadType, err = marshalUtil.ReadUint32()
if err != nil {
return
}
// unmarshal data payload size
var dataPayloadSize uint32
dataPayloadSize, err = marshalUtil.ReadUint32()
if err != nil {
return
}
if dataPayloadSize > MAX_DATA_PAYLOAD_SIZE {
err = fmt.Errorf("data payload size of %d bytes exceeds maximum limit of %d bytes",
dataPayloadSize, MAX_DATA_PAYLOAD_SIZE)
return
}
// unmarshal data payload
transaction.dataPayload, err = marshalUtil.ReadBytes(int(dataPayloadSize))
if err != nil {
return
}
// store essence bytes // store essence bytes
essenceBytesCount := marshalUtil.ReadOffset() essenceBytesCount := marshalUtil.ReadOffset()
transaction.essenceBytes = make([]byte, essenceBytesCount) transaction.essenceBytes = make([]byte, essenceBytesCount)
......
package transaction
import (
"bytes"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme"
"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance"
"github.com/iotaledger/hive.go/crypto/ed25519"
"github.com/stretchr/testify/assert"
"strings"
"testing"
)
func TestEmptyDataPayload(t *testing.T) {
sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair())
addr := sigScheme.Address()
o1 := NewOutputId(addr, RandomId())
inputs := NewInputs(o1)
bal := balance.New(balance.COLOR_IOTA, 1)
outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
tx := New(inputs, outputs)
tx.Sign(sigScheme)
check := tx.SignaturesValid()
assert.Equal(t, true, check)
}
func TestShortDataPayload(t *testing.T) {
sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair())
addr := sigScheme.Address()
o1 := NewOutputId(addr, RandomId())
inputs := NewInputs(o1)
bal := balance.New(balance.COLOR_IOTA, 1)
outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
tx := New(inputs, outputs)
dataPayload := []byte("data payload test")
dataPayloadType := uint32(42)
err := tx.SetDataPayload(dataPayload, dataPayloadType)
assert.Equal(t, nil, err)
dpBack, dptBack := tx.GetDataPayload()
assert.Equal(t, true, bytes.Compare(dpBack, dataPayload) == 0)
assert.Equal(t, true, dptBack == dataPayloadType)
tx.Sign(sigScheme)
check := tx.SignaturesValid()
assert.Equal(t, true, check)
// corrupt data payload bytes
// reset essence to force recalculation
tx.essenceBytes = nil
dataPayload[2] = '?'
err = tx.SetDataPayload(dataPayload, dataPayloadType)
assert.Equal(t, nil, err)
// expect signature is not valid
check = tx.SignaturesValid()
assert.Equal(t, false, check)
}
func TestTooLongDataPayload(t *testing.T) {
sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair())
addr := sigScheme.Address()
o1 := NewOutputId(addr, RandomId())
inputs := NewInputs(o1)
bal := balance.New(balance.COLOR_IOTA, 1)
outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
tx := New(inputs, outputs)
dataPayload := []byte(strings.Repeat("1", MAX_DATA_PAYLOAD_SIZE+1))
dataPayloadType := uint32(42)
err := tx.SetDataPayload(dataPayload, dataPayloadType)
assert.Equal(t, true, err != nil)
}
func TestMarshalingEmptyDataPayload(t *testing.T) {
sigScheme := signaturescheme.RandBLS()
addr := sigScheme.Address()
o1 := NewOutputId(addr, RandomId())
inputs := NewInputs(o1)
bal := balance.New(balance.COLOR_IOTA, 1)
outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
tx := New(inputs, outputs)
tx.Sign(sigScheme)
check := tx.SignaturesValid()
assert.Equal(t, true, check)
v := tx.ObjectStorageValue()
tx1 := Transaction{}
err, _ := tx1.UnmarshalObjectStorageValue(v)
if err != nil {
assert.Error(t, err)
}
assert.Equal(t, true, tx1.SignaturesValid())
assert.Equal(t, true, bytes.Compare(tx1.Id().Bytes(), tx.Id().Bytes()) == 0)
}
func TestMarshalingDataPayload(t *testing.T) {
sigScheme := signaturescheme.RandBLS()
addr := sigScheme.Address()
o1 := NewOutputId(addr, RandomId())
inputs := NewInputs(o1)
bal := balance.New(balance.COLOR_IOTA, 1)
outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
tx := New(inputs, outputs)
dataPayload := []byte("data payload test")
dataPayloadType := uint32(42)
err := tx.SetDataPayload(dataPayload, dataPayloadType)
assert.Equal(t, nil, err)
tx.Sign(sigScheme)
check := tx.SignaturesValid()
assert.Equal(t, true, check)
v := tx.ObjectStorageValue()
tx1 := Transaction{}
err, _ = tx1.UnmarshalObjectStorageValue(v)
assert.Equal(t, nil, err)
assert.Equal(t, true, tx1.SignaturesValid())
assert.Equal(t, true, bytes.Compare(tx1.Id().Bytes(), tx.Id().Bytes()) == 0)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment