diff --git a/packages/binary/address/address.go b/packages/binary/address/address.go index 41a03b74541434f3db9ae4b0b6374125f4a277dc..356a8e929522a23394dbd7cf4234bad4c9d8c9f9 100644 --- a/packages/binary/address/address.go +++ b/packages/binary/address/address.go @@ -3,6 +3,10 @@ package address import ( "crypto/rand" + "golang.org/x/crypto/blake2b" + + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" + "github.com/mr-tron/base58" ) @@ -24,6 +28,14 @@ func FromBase58EncodedString(base58EncodedString string) (result Address) { return } +func FromPublicKey(publicKey ed25119.PublicKey) (result Address) { + hashedPublicKey := blake2b.Sum256(publicKey[:]) + + copy(result[:], hashedPublicKey[:]) + + return +} + func Random() (result Address) { addressBytes := make([]byte, Length) if _, err := rand.Read(addressBytes); err != nil { diff --git a/packages/binary/signature/ed25119/ed25119.go b/packages/binary/signature/ed25119/ed25119.go new file mode 100644 index 0000000000000000000000000000000000000000..d4b65997bf4657ceeaa43427a8f0b43a58fc2dfe --- /dev/null +++ b/packages/binary/signature/ed25119/ed25119.go @@ -0,0 +1,18 @@ +package ed25119 + +import ( + "crypto/rand" + + "github.com/oasislabs/ed25519" +) + +func GenerateKeyPair() (keyPair KeyPair) { + if public, private, err := ed25519.GenerateKey(rand.Reader); err != nil { + panic(err) + } else { + copy(keyPair.PrivateKey[:], private) + copy(keyPair.PublicKey[:], public) + + return + } +} diff --git a/packages/binary/signature/ed25119/key_pair.go b/packages/binary/signature/ed25119/key_pair.go new file mode 100644 index 0000000000000000000000000000000000000000..ad0c31bbe6ef5e06df08138dd66282e843322af4 --- /dev/null +++ b/packages/binary/signature/ed25119/key_pair.go @@ -0,0 +1,6 @@ +package ed25119 + +type KeyPair struct { + PrivateKey PrivateKey + PublicKey PublicKey +} diff --git a/packages/binary/signature/ed25119/private_key.go b/packages/binary/signature/ed25119/private_key.go new file mode 100644 index 0000000000000000000000000000000000000000..89dc1a15ecc01f5b088a0aca871390dbbcbd101e --- /dev/null +++ b/packages/binary/signature/ed25119/private_key.go @@ -0,0 +1,15 @@ +package ed25119 + +import ( + "github.com/oasislabs/ed25519" +) + +type PrivateKey [PrivateKeySize]byte + +func (privateKey PrivateKey) Sign(data []byte) (result Signature) { + copy(result[:], ed25519.Sign(privateKey[:], data)) + + return +} + +const PrivateKeySize = 64 diff --git a/packages/binary/signature/ed25119/public_key.go b/packages/binary/signature/ed25119/public_key.go new file mode 100644 index 0000000000000000000000000000000000000000..c9d58e254413349234283406c817f8c68c7d30e5 --- /dev/null +++ b/packages/binary/signature/ed25119/public_key.go @@ -0,0 +1,25 @@ +package ed25119 + +import ( + "errors" + + "github.com/oasislabs/ed25519" +) + +type PublicKey [PublicKeySize]byte + +func (publicKey PublicKey) VerifySignature(data []byte, signature Signature) bool { + return ed25519.Verify(publicKey[:], data, signature[:]) +} + +func (publicKey *PublicKey) UnmarshalBinary(bytes []byte) (err error) { + if len(bytes) < PublicKeySize { + return errors.New("not enough bytes") + } + + copy(publicKey[:], bytes[:]) + + return +} + +const PublicKeySize = 32 diff --git a/packages/binary/signature/ed25119/signature.go b/packages/binary/signature/ed25119/signature.go new file mode 100644 index 0000000000000000000000000000000000000000..bd33e1138e42da2809b0dac22afa1a140d5b8c3b --- /dev/null +++ b/packages/binary/signature/ed25119/signature.go @@ -0,0 +1,19 @@ +package ed25119 + +import ( + "errors" +) + +type Signature [SignatureSize]byte + +func (signature *Signature) UnmarshalBinary(bytes []byte) (err error) { + if len(bytes) < SignatureSize { + return errors.New("not enough bytes") + } + + copy(signature[:], bytes[:]) + + return +} + +const SignatureSize = 64 diff --git a/packages/binary/transaction/payload/valuetransfer/value.go b/packages/binary/transaction/payload/valuetransfer/value.go deleted file mode 100644 index e433d9dfdf685b012760ea3b396659c616c80289..0000000000000000000000000000000000000000 --- a/packages/binary/transaction/payload/valuetransfer/value.go +++ /dev/null @@ -1,42 +0,0 @@ -package valuetransfer - -import ( - "sync" - - "github.com/iotaledger/goshimmer/packages/binary/address" - "github.com/iotaledger/goshimmer/packages/binary/transaction/payload" - "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" -) - -type ValueTransfer struct { - inputs []*transfer.OutputReference - inputsMutex sync.RWMutex -} - -var Type = payload.Type(1) - -func New() *ValueTransfer { - return &ValueTransfer{ - inputs: make([]*transfer.OutputReference, 0), - } -} - -func (valueTransfer *ValueTransfer) AddInput(transferHash transfer.Hash, address address.Address) *ValueTransfer { - valueTransfer.inputsMutex.Lock() - valueTransfer.inputs = append(valueTransfer.inputs, transfer.NewOutputReference(transferHash, address)) - valueTransfer.inputsMutex.Unlock() - - return valueTransfer -} - -func (valueTransfer *ValueTransfer) GetType() payload.Type { - return Type -} - -func (valueTransfer *ValueTransfer) MarshalBinary() (bytes []byte, err error) { - return -} - -func (valueTransfer *ValueTransfer) UnmarshalBinary(bytes []byte) (err error) { - return -} diff --git a/packages/binary/transaction/payload/valuetransfer/valuetransfer.go b/packages/binary/transaction/payload/valuetransfer/valuetransfer.go new file mode 100644 index 0000000000000000000000000000000000000000..6f369dc8883edb5259d6078de9192f5801c822a0 --- /dev/null +++ b/packages/binary/transaction/payload/valuetransfer/valuetransfer.go @@ -0,0 +1,362 @@ +package valuetransfer + +import ( + "encoding/binary" + "sync" + + "github.com/iotaledger/goshimmer/packages/binary/types" + + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" + + "github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins" + + "github.com/iotaledger/goshimmer/packages/binary/address" + "github.com/iotaledger/goshimmer/packages/binary/transaction/payload" + "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" +) + +type ValueTransfer struct { + inputs []*transfer.OutputReference + outputs map[address.Address][]*coloredcoins.ColoredBalance + signatures map[ed25119.PublicKey]ed25119.Signature + payloadBytes []byte + signatureBytes []byte + + inputsMutex sync.RWMutex + outputsMutex sync.RWMutex + signaturesMutex sync.RWMutex + payloadBytesMutex sync.RWMutex + signatureBytesMutex sync.RWMutex +} + +var Type = payload.Type(1) + +func New() *ValueTransfer { + return &ValueTransfer{ + inputs: make([]*transfer.OutputReference, 0), + outputs: make(map[address.Address][]*coloredcoins.ColoredBalance), + signatures: make(map[ed25119.PublicKey]ed25119.Signature), + } +} + +func (valueTransfer *ValueTransfer) GetType() payload.Type { + return Type +} + +func (valueTransfer *ValueTransfer) AddInput(transferHash transfer.Hash, address address.Address) *ValueTransfer { + if valueTransfer.isFinalized() { + panic("you can not add inputs after you have started finalizing (sign / marshal) the ValueTransfer") + } + + valueTransfer.inputsMutex.Lock() + valueTransfer.inputs = append(valueTransfer.inputs, transfer.NewOutputReference(transferHash, address)) + valueTransfer.inputsMutex.Unlock() + + return valueTransfer +} + +func (valueTransfer *ValueTransfer) AddOutput(address address.Address, balance *coloredcoins.ColoredBalance) *ValueTransfer { + if valueTransfer.isFinalized() { + panic("you can not add outputs after you have started finalizing (sign / marshal) the ValueTransfer") + } + + valueTransfer.outputsMutex.Lock() + if _, addressExists := valueTransfer.outputs[address]; !addressExists { + valueTransfer.outputs[address] = make([]*coloredcoins.ColoredBalance, 0) + } + + valueTransfer.outputs[address] = append(valueTransfer.outputs[address], balance) + valueTransfer.outputsMutex.Unlock() + + return valueTransfer +} + +func (valueTransfer *ValueTransfer) Sign(keyPair ed25119.KeyPair) *ValueTransfer { + payloadBytes := valueTransfer.marshalPayloadBytes() + + valueTransfer.signaturesMutex.RLock() + if _, signatureExists := valueTransfer.signatures[keyPair.PublicKey]; !signatureExists { + valueTransfer.signaturesMutex.RUnlock() + + valueTransfer.signaturesMutex.Lock() + if _, signatureExists := valueTransfer.signatures[keyPair.PublicKey]; !signatureExists { + valueTransfer.signatures[keyPair.PublicKey] = keyPair.PrivateKey.Sign(payloadBytes) + } + valueTransfer.signaturesMutex.Unlock() + } else { + valueTransfer.signaturesMutex.RUnlock() + } + + return valueTransfer +} + +func (valueTransfer *ValueTransfer) VerifySignatures() bool { + _, _ = valueTransfer.MarshalBinary() + payloadBytes := valueTransfer.marshalPayloadBytes() + + addressesToSign := make(map[address.Address]types.Empty) + for _, input := range valueTransfer.inputs { + addressesToSign[input.GetAddress()] = types.Void + } + + for publicKey, signature := range valueTransfer.signatures { + if publicKey.VerifySignature(payloadBytes, signature) { + delete(addressesToSign, address.FromPublicKey(publicKey)) + } else { + panic("INVALID SIGNATURE") + } + } + + return len(addressesToSign) == 0 +} + +func (valueTransfer *ValueTransfer) MarshalBinary() (result []byte, err error) { + payloadBytes := valueTransfer.marshalPayloadBytes() + signatureBytes := valueTransfer.marshalSignatureBytes(payloadBytes) + + result = append(payloadBytes, signatureBytes...) + + return +} + +func (valueTransfer *ValueTransfer) UnmarshalBinary(bytes []byte) (err error) { + offset := 0 + + payloadBytesOffset := offset + if err = valueTransfer.unmarshalInputs(bytes, &offset); err != nil { + return + } + + if err = valueTransfer.unmarshalOutputs(bytes, &offset); err != nil { + return + } + + payloadBytesLength := offset - payloadBytesOffset + valueTransfer.payloadBytes = make([]byte, payloadBytesLength) + copy(valueTransfer.payloadBytes, bytes[payloadBytesOffset:payloadBytesOffset+payloadBytesLength]) + + signatureBytesOffset := offset + if err = valueTransfer.unmarshalSignatures(bytes, &offset); err != nil { + return + } + + signatureBytesLength := offset - signatureBytesOffset + valueTransfer.signatureBytes = make([]byte, signatureBytesLength) + copy(valueTransfer.signatureBytes, bytes[signatureBytesOffset:signatureBytesOffset+signatureBytesLength]) + + return +} + +func (valueTransfer *ValueTransfer) isFinalized() (result bool) { + valueTransfer.payloadBytesMutex.RLock() + result = valueTransfer.payloadBytes != nil + valueTransfer.payloadBytesMutex.RUnlock() + + return +} + +func (valueTransfer *ValueTransfer) marshalPayloadBytes() (result []byte) { + valueTransfer.payloadBytesMutex.RLock() + if valueTransfer.payloadBytes == nil { + valueTransfer.payloadBytesMutex.RUnlock() + + valueTransfer.payloadBytesMutex.Lock() + if valueTransfer.payloadBytes == nil { + result = append(valueTransfer.marshalInputs(), valueTransfer.marshalOutputs()...) + + valueTransfer.payloadBytes = result + } else { + result = valueTransfer.payloadBytes + } + valueTransfer.payloadBytesMutex.Unlock() + } else { + result = valueTransfer.payloadBytes + + valueTransfer.payloadBytesMutex.RUnlock() + } + + return +} + +func (valueTransfer *ValueTransfer) marshalInputs() (result []byte) { + inputCount := len(valueTransfer.inputs) + marshaledTransferOutputReferenceLength := transfer.HashLength + address.Length + + result = make([]byte, 4+inputCount*marshaledTransferOutputReferenceLength) + offset := 0 + + binary.LittleEndian.PutUint32(result[offset:], uint32(inputCount)) + offset += 4 + + for _, transferOutputReference := range valueTransfer.inputs { + if marshaledTransferOutputReference, err := transferOutputReference.MarshalBinary(); err != nil { + panic(err) + } else { + copy(result[offset:], marshaledTransferOutputReference) + offset += marshaledTransferOutputReferenceLength + } + } + + return +} + +func (valueTransfer *ValueTransfer) marshalOutputs() (result []byte) { + totalLength := 4 + for _, outputs := range valueTransfer.outputs { + totalLength += address.Length + + totalLength += 4 + + for range outputs { + totalLength += coloredcoins.ColorLength + 8 + } + } + + result = make([]byte, totalLength) + offset := 0 + + binary.LittleEndian.PutUint32(result[offset:], uint32(len(valueTransfer.outputs))) + offset += 4 + + for outputAddress, outputs := range valueTransfer.outputs { + copy(result[offset:], outputAddress[:]) + offset += address.Length + + binary.LittleEndian.PutUint32(result[offset:], uint32(len(outputs))) + offset += 4 + + for _, coloredBalance := range outputs { + if marshaledColoredBalance, marshalErr := coloredBalance.MarshalBinary(); marshalErr != nil { + panic(marshalErr) + } else { + copy(result[offset:], marshaledColoredBalance) + offset += coloredcoins.ColorLength + 8 + } + } + } + + return +} + +func (valueTransfer *ValueTransfer) marshalSignatureBytes(payloadBytes []byte) (result []byte) { + valueTransfer.signatureBytesMutex.RLock() + if valueTransfer.signatureBytes == nil { + valueTransfer.signatureBytesMutex.RUnlock() + + valueTransfer.signatureBytesMutex.Lock() + if valueTransfer.signatureBytes == nil { + signatureCount := len(valueTransfer.signatures) + result = make([]byte, 4+signatureCount*(ed25119.PublicKeySize+ed25119.SignatureSize)) + offset := 0 + + binary.LittleEndian.PutUint32(result[offset:], uint32(signatureCount)) + offset += 4 + + valueTransfer.signaturesMutex.RLock() + for publicKey, signature := range valueTransfer.signatures { + copy(result[offset:], publicKey[:]) + offset += ed25119.PublicKeySize + + copy(result[offset:], signature[:]) + offset += ed25119.SignatureSize + } + valueTransfer.signaturesMutex.RUnlock() + + valueTransfer.signatureBytes = result + } else { + result = valueTransfer.signatureBytes + } + valueTransfer.signatureBytesMutex.Unlock() + } else { + result = valueTransfer.signatureBytes + + valueTransfer.signatureBytesMutex.RUnlock() + } + + return +} + +func (valueTransfer *ValueTransfer) unmarshalInputs(bytes []byte, offset *int) (err error) { + inputCount := int(binary.LittleEndian.Uint32(bytes[*offset:])) + *offset += 4 + + valueTransfer.inputs = make([]*transfer.OutputReference, inputCount) + marshaledTransferOutputReferenceLength := transfer.HashLength + address.Length + for i := 0; i < inputCount; i++ { + var transferOutputReference transfer.OutputReference + if err = transferOutputReference.UnmarshalBinary(bytes[*offset:]); err != nil { + return + } + *offset += marshaledTransferOutputReferenceLength + + valueTransfer.inputs[i] = &transferOutputReference + } + + return +} + +func (valueTransfer *ValueTransfer) unmarshalOutputs(bytes []byte, offset *int) (err error) { + outputCount := int(binary.LittleEndian.Uint32(bytes[*offset:])) + *offset += 4 + + valueTransfer.outputs = make(map[address.Address][]*coloredcoins.ColoredBalance) + + for i := 0; i < outputCount; i++ { + var outputAddress address.Address + if err = outputAddress.UnmarshalBinary(bytes[*offset:]); err != nil { + return + } + *offset += address.Length + + outputsCount := int(binary.LittleEndian.Uint32(bytes[*offset:])) + *offset += 4 + + valueTransfer.outputs[outputAddress] = make([]*coloredcoins.ColoredBalance, outputsCount) + + for j := 0; j < outputsCount; j++ { + var coloredBalance coloredcoins.ColoredBalance + if err = coloredBalance.UnmarshalBinary(bytes[*offset:]); err != nil { + return + } + *offset += coloredcoins.BalanceLength + + valueTransfer.outputs[outputAddress][j] = &coloredBalance + } + } + + return +} + +func (valueTransfer *ValueTransfer) unmarshalSignatures(bytes []byte, offset *int) (err error) { + signatureCount := int(binary.LittleEndian.Uint32(bytes[*offset:])) + *offset += 4 + + valueTransfer.signatures = make(map[ed25119.PublicKey]ed25119.Signature) + + for i := 0; i < signatureCount; i++ { + var publicKey ed25119.PublicKey + if err = publicKey.UnmarshalBinary(bytes[*offset:]); err != nil { + return + } + *offset += ed25119.PublicKeySize + + var signature ed25119.Signature + if err = signature.UnmarshalBinary(bytes[*offset:]); err != nil { + return + } + *offset += ed25119.SignatureSize + + valueTransfer.signatures[publicKey] = signature + } + + return +} + +func init() { + payload.RegisterType(Type, func(data []byte) (payload payload.Payload, err error) { + payload = &ValueTransfer{} + err = payload.UnmarshalBinary(data) + + return + }) +} diff --git a/packages/binary/transaction/test/transaction_test.go b/packages/binary/transaction/test/transaction_test.go index 06e790d6761a21e71438630069256e3eb7a43202..a5443cd193d706f4229a8ca59ca8909a8987f966 100644 --- a/packages/binary/transaction/test/transaction_test.go +++ b/packages/binary/transaction/test/transaction_test.go @@ -5,6 +5,10 @@ import ( "sync" "testing" + "github.com/iotaledger/goshimmer/packages/binary/signature/ed25119" + + "github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins" + "github.com/panjf2000/ants/v2" "github.com/iotaledger/goshimmer/packages/ledgerstate/transfer" @@ -49,16 +53,26 @@ func TestNew(t *testing.T) { newTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("test"))) assert.Equal(t, newTransaction1.VerifySignature(), true) - valueTransfer := valuetransfer.New().AddInput(transfer.NewHash("test"), address.Random()) + keyPairOfSourceAddress := ed25119.GenerateKeyPair() + keyPairOfTargetAddress := ed25119.GenerateKeyPair() - newValueTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), valueTransfer) + newValueTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), + valuetransfer.New(). + AddInput(transfer.NewHash("test"), address.FromPublicKey(keyPairOfSourceAddress.PublicKey)). + AddOutput(address.FromPublicKey(keyPairOfTargetAddress.PublicKey), coloredcoins.NewColoredBalance(coloredcoins.NewColor("IOTA"), 12)). + Sign(keyPairOfSourceAddress), + ) assert.Equal(t, newValueTransaction1.VerifySignature(), true) newValueTransaction2, _ := transaction.FromBytes(newValueTransaction1.GetBytes()) assert.Equal(t, newValueTransaction2.VerifySignature(), true) - if newValueTransaction1.GetPayload().GetType() == valuetransfer.Type { - fmt.Println("VALUE TRANSFER TRANSACTION") + fmt.Println(newValueTransaction1.GetPayload().(*valuetransfer.ValueTransfer).MarshalBinary()) + fmt.Println(newValueTransaction2.GetPayload().(*valuetransfer.ValueTransfer).MarshalBinary()) + + if newValueTransaction2.GetPayload().GetType() == valuetransfer.Type { + fmt.Println(newValueTransaction1.GetPayload().(*valuetransfer.ValueTransfer).VerifySignatures()) + fmt.Println(newValueTransaction2.GetPayload().(*valuetransfer.ValueTransfer).VerifySignatures()) } newTransaction2 := transaction.New(newTransaction1.GetId(), transaction.EmptyId, identity.Generate(), data.New([]byte("test1"))) diff --git a/packages/ledgerstate/coloredcoins/color.go b/packages/ledgerstate/coloredcoins/color.go index 9ff9559400132de925c58fcb0ccf7b40bc0b2d37..e5cc8321421d7efc70edf1a16f8b6a1e9d5a3924 100644 --- a/packages/ledgerstate/coloredcoins/color.go +++ b/packages/ledgerstate/coloredcoins/color.go @@ -14,6 +14,13 @@ func NewColor(color string) (result Color) { return } +func (color *Color) MarshalBinary() (result []byte, err error) { + result = make([]byte, ColorLength) + copy(result, color[:]) + + return +} + func (color *Color) UnmarshalBinary(data []byte) error { copy(color[:], data[:ColorLength]) diff --git a/packages/ledgerstate/coloredcoins/colored_balance.go b/packages/ledgerstate/coloredcoins/colored_balance.go index 898a0d9a58840220b64c0a0513925173796f0160..845b39c7783f87ac4d6543e577eb0e850a9aa03b 100644 --- a/packages/ledgerstate/coloredcoins/colored_balance.go +++ b/packages/ledgerstate/coloredcoins/colored_balance.go @@ -17,21 +17,37 @@ func NewColoredBalance(color Color, balance uint64) *ColoredBalance { } } -func (balance *ColoredBalance) GetColor() Color { - return balance.color +func (coloredBalance *ColoredBalance) GetColor() Color { + return coloredBalance.color } -func (balance *ColoredBalance) GetBalance() uint64 { - return balance.balance +func (coloredBalance *ColoredBalance) GetBalance() uint64 { + return coloredBalance.balance } -func (balance *ColoredBalance) UnmarshalBinary(data []byte) error { - balance.color = Color{} - if err := balance.color.UnmarshalBinary(data); err != nil { +func (coloredBalance *ColoredBalance) MarshalBinary() (result []byte, err error) { + result = make([]byte, ColorLength+8) + + if marshaledColor, marshalErr := coloredBalance.color.MarshalBinary(); marshalErr != nil { + err = marshalErr + + return + } else { + copy(result, marshaledColor) + } + + binary.LittleEndian.PutUint64(result[ColorLength:], coloredBalance.balance) + + return +} + +func (coloredBalance *ColoredBalance) UnmarshalBinary(data []byte) error { + coloredBalance.color = Color{} + if err := coloredBalance.color.UnmarshalBinary(data); err != nil { return err } - balance.balance = binary.LittleEndian.Uint64(data[ColorLength:]) + coloredBalance.balance = binary.LittleEndian.Uint64(data[ColorLength:]) return nil } diff --git a/packages/ledgerstate/outputs.png b/packages/ledgerstate/outputs.png index 348a7350b16b3d38a6d4731c7c51f2740fe6110c..fbc282cfbfb8ee744230710f46f058f8ff961ccd 100644 Binary files a/packages/ledgerstate/outputs.png and b/packages/ledgerstate/outputs.png differ diff --git a/packages/ledgerstate/outputs1.png b/packages/ledgerstate/outputs1.png index b695948cae29c186c1eb156ee1b0a736ab1045f6..639f9f9d70d5ff3d49ec4cfb86fd919dc28fe008 100644 Binary files a/packages/ledgerstate/outputs1.png and b/packages/ledgerstate/outputs1.png differ diff --git a/packages/ledgerstate/outputs2.png b/packages/ledgerstate/outputs2.png index 1628d4989b63e5a01f961b83453c40dd02db4996..b3de946340e39640db58e60567793234cea900ef 100644 Binary files a/packages/ledgerstate/outputs2.png and b/packages/ledgerstate/outputs2.png differ diff --git a/packages/ledgerstate/transfer/output_reference.go b/packages/ledgerstate/transfer/output_reference.go index bbdcef2f5555d6717b564e700294c6ad4f00317e..b061af8fb30545da6772b0be535943be65d9a33c 100644 --- a/packages/ledgerstate/transfer/output_reference.go +++ b/packages/ledgerstate/transfer/output_reference.go @@ -19,6 +19,33 @@ func NewOutputReference(transferHash Hash, addressHash address.Address) *OutputR } } +func (reference *OutputReference) GetAddress() address.Address { + return reference.addressHash +} + +func (reference *OutputReference) MarshalBinary() (result []byte, err error) { + result = make([]byte, HashLength+address.Length) + offset := 0 + + copy(result[offset:], reference.transferHash[:]) + offset += HashLength + + copy(result[offset:], reference.addressHash[:]) + + return +} + +func (reference *OutputReference) UnmarshalBinary(bytes []byte) (err error) { + offset := 0 + + copy(reference.transferHash[:], bytes[offset:]) + offset += HashLength + + copy(reference.addressHash[:], bytes[offset:]) + + return +} + func (reference *OutputReference) GetStorageKey() []byte { return reference.storageKey }