diff --git a/dapps/valuetransfers/dapp.go b/dapps/valuetransfers/dapp.go index bc5e7dd0284f74ab2cea3d5c0eb2a7c5c4699d4f..54085ddb1a43817d5ce9730039c71d751924b27d 100644 --- a/dapps/valuetransfers/dapp.go +++ b/dapps/valuetransfers/dapp.go @@ -24,12 +24,14 @@ import ( const ( // PluginName contains the human readable name of the plugin. - PluginName = "ValueTransfers" + PluginName = "ValueTransfers" + + // AverageNetworkDelay contains the average time it takes for a network to propagate through gossip. AverageNetworkDelay = 6 * time.Second ) var ( - // Plugin is the plugin instance of the message layer plugin. + // App is the "plugin" instance of the value-transfers application. App = node.NewPlugin(PluginName, node.Enabled, configure, run) // Tangle represents the value tangle that is used to express votes on value transactions. @@ -66,7 +68,7 @@ func configure(_ *node.Plugin) { // TODO: DECIDE WHAT WE SHOULD DO IF FPC FAILS // voter.Events().Failed.Attach(events.NewClosure(panic)) voter.Events().Finalized.Attach(events.NewClosure(func(id string, opinion vote.Opinion) { - branchId, err := branchmanager.BranchIdFromBase58(id) + branchID, err := branchmanager.BranchIDFromBase58(id) if err != nil { log.Error(err) @@ -75,9 +77,9 @@ func configure(_ *node.Plugin) { switch opinion { case vote.Like: - UTXODAG.BranchManager().SetBranchPreferred(branchId, true) + UTXODAG.BranchManager().SetBranchPreferred(branchID, true) case vote.Dislike: - UTXODAG.BranchManager().SetBranchPreferred(branchId, false) + UTXODAG.BranchManager().SetBranchPreferred(branchID, false) } })) } @@ -120,7 +122,7 @@ func onReceiveMessageFromMessageLayer(cachedMessage *message.CachedMessage, cach Tangle.AttachPayload(valuePayload) } -func onTransactionBooked(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *utxodag.CachedTransactionMetadata, cachedBranch *branchmanager.CachedBranch, conflictingInputs []transaction.OutputId, previousConsumersForked bool) { +func onTransactionBooked(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *utxodag.CachedTransactionMetadata, cachedBranch *branchmanager.CachedBranch, conflictingInputs []transaction.OutputID, previousConsumersForked bool) { defer cachedTransaction.Release() defer cachedTransactionMetadata.Release() defer cachedBranch.Release() @@ -138,7 +140,7 @@ func onTransactionBooked(cachedTransaction *transaction.CachedTransaction, cache return } - err := voter.Vote(branch.Id().String(), vote.Dislike) + err := voter.Vote(branch.ID().String(), vote.Dislike) if err != nil { log.Error(err) } @@ -157,7 +159,7 @@ func onTransactionBooked(cachedTransaction *transaction.CachedTransaction, cache return } - if transactionMetadata.BranchId() != branchmanager.NewBranchId(transactionMetadata.Id()) { + if transactionMetadata.BranchID() != branchmanager.NewBranchID(transactionMetadata.ID()) { return } @@ -165,7 +167,7 @@ func onTransactionBooked(cachedTransaction *transaction.CachedTransaction, cache }) } -func onFork(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *utxodag.CachedTransactionMetadata, cachedBranch *branchmanager.CachedBranch, conflictingInputs []transaction.OutputId) { +func onFork(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *utxodag.CachedTransactionMetadata, cachedBranch *branchmanager.CachedBranch, conflictingInputs []transaction.OutputID) { defer cachedTransaction.Release() defer cachedTransactionMetadata.Release() defer cachedBranch.Release() @@ -184,7 +186,7 @@ func onFork(cachedTransaction *transaction.CachedTransaction, cachedTransactionM return } - if _, err := UTXODAG.BranchManager().SetBranchPreferred(branch.Id(), true); err != nil { + if _, err := UTXODAG.BranchManager().SetBranchPreferred(branch.ID(), true); err != nil { log.Error(err) } } diff --git a/dapps/valuetransfers/fpc.go b/dapps/valuetransfers/fpc.go index 977bf6c78c16773cdeea52149f4cad66fe7e6ca1..0bd2f1c4db4c25aa3426a830c2ab9cab43b695cc 100644 --- a/dapps/valuetransfers/fpc.go +++ b/dapps/valuetransfers/fpc.go @@ -29,9 +29,14 @@ import ( ) const ( + // CfgFPCQuerySampleSize defines how many nodes will be queried each round. CfgFPCQuerySampleSize = "fpc.querySampleSize" - CfgFPCRoundInterval = "fpc.roundInterval" - CfgFPCBindAddress = "fpc.bindAddress" + + // CfgFPCRoundInterval defines how long a round lasts (in seconds) + CfgFPCRoundInterval = "fpc.roundInterval" + + // CfgFPCBindAddress defines on which address the FPC service should listen. + CfgFPCBindAddress = "fpc.bindAddress" ) func init() { @@ -96,14 +101,14 @@ func configureFPC() { func runFPC() { daemon.BackgroundWorker("FPCVoterServer", func(shutdownSignal <-chan struct{}) { voterServer = votenet.New(Voter(), func(id string) vote.Opinion { - branchId, err := branchmanager.BranchIdFromBase58(id) + branchID, err := branchmanager.BranchIDFromBase58(id) if err != nil { log.Errorf("received invalid vote request for branch '%s'", id) return vote.Unknown } - cachedBranch := UTXODAG.BranchManager().GetBranch(branchId) + cachedBranch := UTXODAG.BranchManager().Branch(branchID) defer cachedBranch.Release() branch := cachedBranch.Unwrap() @@ -154,6 +159,7 @@ type PeerOpinionGiver struct { p *peer.Peer } +// Query queries another node for its opinion. func (pog *PeerOpinionGiver) Query(ctx context.Context, ids []string) (vote.Opinions, error) { fpcServicePort := pog.p.Services().Get(service.FPCKey).Port() fpcAddr := net.JoinHostPort(pog.p.IP().String(), strconv.Itoa(fpcServicePort)) @@ -183,6 +189,7 @@ func (pog *PeerOpinionGiver) Query(ctx context.Context, ids []string) (vote.Opin return opinions, nil } +// ID returns a string representation of the identifier of the underlying Peer. func (pog *PeerOpinionGiver) ID() string { return pog.p.ID().String() } diff --git a/dapps/valuetransfers/packages/address/address.go b/dapps/valuetransfers/packages/address/address.go index 38fd22c166ddc8488766906c11fd7c93f029e869..16068a88d3e00c40cfe4eacfba4c98c851c28a36 100644 --- a/dapps/valuetransfers/packages/address/address.go +++ b/dapps/valuetransfers/packages/address/address.go @@ -11,21 +11,27 @@ import ( "github.com/iotaledger/hive.go/marshalutil" ) +// Version represents the version of the address. Different versions are associated to different signature schemes. type Version = byte +// Digest represents a hashed version of the consumed public key of the address. Hashing the public key allows us to +// maintain quantum-robustness for addresses, that have never been spent from, and it allows us to have fixed size +// addresses. type Digest = []byte +// Address represents an address in the IOTA ledger. type Address [Length]byte const ( - // every signature scheme has a version byte associated to it. - VERSION_ED25519 = byte(1) - VERSION_BLS = byte(2) + // VersionED25519 represents the address version that uses ED25519 signatures. + VersionED25519 = byte(1) + + // VersionBLS represents the address version that uses BLS signatures. + VersionBLS = byte(2) ) // Random creates a random address, which can for example be used in unit tests. // first byte (version) is also random - func Random() (address Address) { // generate a random sequence of bytes if _, err := rand.Read(address[:]); err != nil { @@ -34,7 +40,8 @@ func Random() (address Address) { return } -func RandomOfType(versionByte byte) Address { +// RandomOfType creates a random address with the given Version. +func RandomOfType(versionByte Version) Address { ret := Random() ret[0] = versionByte return ret @@ -65,7 +72,7 @@ func FromBase58(base58String string) (address Address, err error) { func FromED25519PubKey(key ed25519.PublicKey) (address Address) { digest := blake2b.Sum256(key[:]) - address[0] = VERSION_ED25519 + address[0] = VersionED25519 copy(address[1:], digest[:]) return @@ -73,18 +80,17 @@ func FromED25519PubKey(key ed25519.PublicKey) (address Address) { // FromBLSPubKey creates an address from marshaled BLS public key // unmarshaled BLS public key conforms to interface kyber.Point - func FromBLSPubKey(pubKey []byte) (address Address) { digest := blake2b.Sum256(pubKey) - address[0] = VERSION_BLS + address[0] = VersionBLS copy(address[1:], digest[:]) return } // FromBytes unmarshals an address from a sequence of bytes. -func FromBytes(bytes []byte) (result Address, err error, consumedBytes int) { +func FromBytes(bytes []byte) (result Address, consumedBytes int, err error) { // parse the bytes marshalUtil := marshalutil.New(bytes) addressBytes, err := marshalUtil.ReadBytes(Length) @@ -99,11 +105,12 @@ func FromBytes(bytes []byte) (result Address, err error, consumedBytes int) { // Parse is a wrapper for simplified unmarshaling of a byte stream using the marshalUtil package. func Parse(marshalUtil *marshalutil.MarshalUtil) (Address, error) { - if address, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { + address, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return FromBytes(data) }) + if err != nil { return Address{}, err - } else { - return address.(Address), nil } + + return address.(Address), nil } // Version returns the version of the address, which corresponds to the signature scheme that is used. diff --git a/dapps/valuetransfers/packages/address/signaturescheme/bls.go b/dapps/valuetransfers/packages/address/signaturescheme/bls.go index 5b17d8b654bd3437185848c6f176edc789909bc1..700eb9e4e05d7e4ae3b8f99b5ad2db0acc7f4645 100644 --- a/dapps/valuetransfers/packages/address/signaturescheme/bls.go +++ b/dapps/valuetransfers/packages/address/signaturescheme/bls.go @@ -24,10 +24,17 @@ import ( var suite = bn256.NewSuite() const ( - BLS_SIGNATURE_SIZE = 64 - BLS_PUBLIC_KEY_SIZE = 128 - BLS_PRIVATE_KEY_SIZE = 32 - BLS_FULL_SIGNATURE_SIZE = 1 + BLS_PUBLIC_KEY_SIZE + BLS_SIGNATURE_SIZE + // BLSSignatureSize represents the length in bytes of a BLS signature. + BLSSignatureSize = 64 + + // BLSPublicKeySize represents the length in bytes of a BLS public key. + BLSPublicKeySize = 128 + + // BLSPrivateKeySize represents the length in bytes of a BLS private key. + BLSPrivateKeySize = 32 + + // BLSFullSignatureSize represents the length in bytes of a full BLS signature. + BLSFullSignatureSize = 1 + BLSPublicKeySize + BLSSignatureSize ) // ---------------- implements SignatureScheme interface @@ -48,10 +55,10 @@ func RandBLS() SignatureScheme { return ret } -// BLS(,) creates an instance of BLS signature scheme +// BLS creates an instance of BLS signature scheme // from given private and public keys in marshaled binary form func BLS(priKey, pubKey []byte) (SignatureScheme, error) { - if len(priKey) != BLS_PRIVATE_KEY_SIZE || len(pubKey) != BLS_PUBLIC_KEY_SIZE { + if len(priKey) != BLSPrivateKeySize || len(pubKey) != BLSPublicKeySize { return nil, fmt.Errorf("wrong key size") } ret := &blsSignatureScheme{ @@ -68,7 +75,7 @@ func BLS(priKey, pubKey []byte) (SignatureScheme, error) { } func (sigscheme *blsSignatureScheme) Version() byte { - return address.VERSION_BLS + return address.VersionBLS } func (sigscheme *blsSignatureScheme) Address() address.Address { @@ -108,43 +115,46 @@ var _ SignatureScheme = &blsSignatureScheme{} // ---------------- implements Signature interface -type blsSignature [BLS_FULL_SIGNATURE_SIZE]byte +// BLSSignature represents a signature created with the BLS signature scheme. +type BLSSignature [BLSFullSignatureSize]byte -func BLSSignatureFromBytes(data []byte) (result *blsSignature, err error, consumedBytes int) { +// BLSSignatureFromBytes unmarshals a BLS signature from a sequence of bytes. +func BLSSignatureFromBytes(data []byte) (result *BLSSignature, consumedBytes int, err error) { consumedBytes = 0 err = nil - if len(data) < BLS_FULL_SIGNATURE_SIZE { - err = fmt.Errorf("marshaled BLS signature size must be %d", BLS_FULL_SIGNATURE_SIZE) + if len(data) < BLSFullSignatureSize { + err = fmt.Errorf("marshaled BLS signature size must be %d", BLSFullSignatureSize) return } - if data[0] != address.VERSION_BLS { - err = fmt.Errorf("wrong version byte, expected %d", address.VERSION_BLS) + if data[0] != address.VersionBLS { + err = fmt.Errorf("wrong version byte, expected %d", address.VersionBLS) return } - result = &blsSignature{} - copy(result[:BLS_FULL_SIGNATURE_SIZE], data) - consumedBytes = BLS_FULL_SIGNATURE_SIZE + result = &BLSSignature{} + copy(result[:BLSFullSignatureSize], data) + consumedBytes = BLSFullSignatureSize return } -func newBLSSignature(pubKey, signature []byte) *blsSignature { - var ret blsSignature - ret[0] = address.VERSION_BLS +func newBLSSignature(pubKey, signature []byte) *BLSSignature { + var ret BLSSignature + ret[0] = address.VersionBLS copy(ret.pubKey(), pubKey) copy(ret.signature(), signature) return &ret } -func (sig *blsSignature) pubKey() []byte { - return sig[1 : BLS_PUBLIC_KEY_SIZE+1] +func (sig *BLSSignature) pubKey() []byte { + return sig[1 : BLSPublicKeySize+1] } -func (sig *blsSignature) signature() []byte { - return sig[1+BLS_PUBLIC_KEY_SIZE:] +func (sig *BLSSignature) signature() []byte { + return sig[1+BLSPublicKeySize:] } -func (sig *blsSignature) IsValid(signedData []byte) bool { - if sig[0] != address.VERSION_BLS { +// IsValid returns true if the signature correctly signs the given data. +func (sig *BLSSignature) IsValid(signedData []byte) bool { + if sig[0] != address.VersionBLS { return false } // unmarshal public key @@ -155,18 +165,21 @@ func (sig *blsSignature) IsValid(signedData []byte) bool { return bdn.Verify(suite, pubKey, signedData, sig.signature()) == nil } -func (sig *blsSignature) Bytes() []byte { +// Bytes marshals the signature into a sequence of bytes. +func (sig *BLSSignature) Bytes() []byte { return sig[:] } -func (sig *blsSignature) Address() address.Address { +// Address returns the address that this signature signs. +func (sig *BLSSignature) Address() address.Address { return address.FromBLSPubKey(sig.pubKey()) } -func (sig *blsSignature) String() string { +func (sig *BLSSignature) String() string { return base58.Encode(sig[:]) } +// AggregateBLSSignatures combined multiple Signatures into a single one. func AggregateBLSSignatures(sigs ...Signature) (Signature, error) { if len(sigs) == 0 { return nil, fmt.Errorf("must be at least one signature to aggregate") @@ -180,7 +193,7 @@ func AggregateBLSSignatures(sigs ...Signature) (Signature, error) { var err error for i, sig := range sigs { - sigBls, ok := sig.(*blsSignature) + sigBls, ok := sig.(*BLSSignature) if !ok { return nil, fmt.Errorf("not a BLS signature") } @@ -214,4 +227,4 @@ func AggregateBLSSignatures(sigs ...Signature) (Signature, error) { } // interface contract (allow the compiler to check if the implementation has all of the required methods). -var _ Signature = &blsSignature{} +var _ Signature = &BLSSignature{} diff --git a/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go b/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go index 09597718b9121d99ea4c06077bbd9a00999b8745..846d92de594628c9cea3c00d2057abb456cc6495 100644 --- a/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go +++ b/dapps/valuetransfers/packages/address/signaturescheme/ed25519.go @@ -29,7 +29,7 @@ type ed25519SignatureScheme struct { // Version returns the version byte that is associated to this signature scheme. func (signatureScheme *ed25519SignatureScheme) Version() byte { - return address.VERSION_ED25519 + return address.VersionED25519 } // Address returns the address that this signature scheme instance is securing. @@ -39,7 +39,7 @@ func (signatureScheme *ed25519SignatureScheme) Address() address.Address { // Sign creates a valid signature for the given data according to the signature scheme implementation. func (signatureScheme *ed25519SignatureScheme) Sign(data []byte) Signature { - return &ed25519Signature{ + return &ED25519Signature{ publicKey: signatureScheme.keyPair.PublicKey, signature: signatureScheme.keyPair.PrivateKey.Sign(data), } @@ -52,19 +52,19 @@ var _ SignatureScheme = &ed25519SignatureScheme{} // region signature implementation ///////////////////////////////////////////////////////////////////////////////////// -// ed25519Signature represents a signature for an addresses that uses elliptic curve cryptography. -type ed25519Signature struct { +// ED25519Signature represents a signature for an addresses that uses elliptic curve cryptography. +type ED25519Signature struct { publicKey ed25519.PublicKey signature ed25519.Signature } -// ed25519SignatureFromBytes unmarshals an ed25519 signatures from a sequence of bytes. +// 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) { +func Ed25519SignatureFromBytes(bytes []byte, optionalTargetObject ...*ED25519Signature) (result *ED25519Signature, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: - result = &ed25519Signature{} + result = &ED25519Signature{} case 1: result = optionalTargetObject[0] default: @@ -78,21 +78,21 @@ func Ed25519SignatureFromBytes(bytes []byte, optionalTargetObject ...*ed25519Sig versionByte, err := marshalUtil.ReadByte() if err != nil { return - } else if versionByte != address.VERSION_ED25519 { + } else if versionByte != address.VersionED25519 { 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 ed25519.PublicKeyFromBytes(data) }) + publicKey, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ed25519.PublicKeyFromBytes(data) }) if err != nil { return } result.publicKey = publicKey.(ed25519.PublicKey) // read signature - signature, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return ed25519.SignatureFromBytes(data) }) + signature, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ed25519.SignatureFromBytes(data) }) if err != nil { return } @@ -105,14 +105,14 @@ func Ed25519SignatureFromBytes(bytes []byte, optionalTargetObject ...*ed25519Sig } // IsValid returns true if the signature is valid for the given data. -func (signature *ed25519Signature) IsValid(signedData []byte) bool { +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 { +func (signature *ED25519Signature) Bytes() []byte { marshalUtil := marshalutil.New(1 + ed25519.PublicKeySize + ed25519.SignatureSize) - marshalUtil.WriteByte(address.VERSION_ED25519) + marshalUtil.WriteByte(address.VersionED25519) marshalUtil.WriteBytes(signature.publicKey[:]) marshalUtil.WriteBytes(signature.signature[:]) @@ -120,7 +120,7 @@ func (signature *ed25519Signature) Bytes() []byte { } // Address returns the address, that this signature signs. -func (signature *ed25519Signature) Address() address.Address { +func (signature *ED25519Signature) Address() address.Address { return address.FromED25519PubKey(signature.publicKey) } diff --git a/dapps/valuetransfers/packages/address/signaturescheme/signature.go b/dapps/valuetransfers/packages/address/signaturescheme/signature.go index 006d19c626797629440e2838beb28bdcabc9aab2..eb7d6e47dff9cc57f78b307189d5f690814726e1 100644 --- a/dapps/valuetransfers/packages/address/signaturescheme/signature.go +++ b/dapps/valuetransfers/packages/address/signaturescheme/signature.go @@ -10,6 +10,6 @@ type Signature interface { // Bytes returns a marshaled version of the signature. Bytes() []byte - // Address returns the address, that this signature signs. + // Address returns the address that this signature signs. Address() address.Address } diff --git a/dapps/valuetransfers/packages/balance/balance.go b/dapps/valuetransfers/packages/balance/balance.go index d969817c1ef7f4317d9f7fe2e1710c1fc24c8fc4..142b95f595219b08f45b2171dc2932d4076caf57 100644 --- a/dapps/valuetransfers/packages/balance/balance.go +++ b/dapps/valuetransfers/packages/balance/balance.go @@ -6,11 +6,13 @@ import ( "github.com/iotaledger/hive.go/marshalutil" ) +// Balance represents a balance in the IOTA ledger. It consists out of a numeric value and a color. type Balance struct { value int64 color Color } +// New creates a new Balance with the given details. func New(color Color, balance int64) (result *Balance) { result = &Balance{ color: color, @@ -20,7 +22,8 @@ func New(color Color, balance int64) (result *Balance) { return } -func FromBytes(bytes []byte) (result *Balance, err error, consumedBytes int) { +// FromBytes unmarshals a Balance from a sequence of bytes. +func FromBytes(bytes []byte) (result *Balance, consumedBytes int, err error) { result = &Balance{} marshalUtil := marshalutil.New(bytes) @@ -30,14 +33,14 @@ func FromBytes(bytes []byte) (result *Balance, err error, consumedBytes int) { return } - if coinColor, colorErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + coinColor, colorErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ColorFromBytes(data) - }); colorErr != nil { - return nil, colorErr, marshalUtil.ReadOffset() - } else { - result.color = coinColor.(Color) + }) + if colorErr != nil { + return nil, marshalUtil.ReadOffset(), colorErr } + result.color = coinColor.(Color) consumedBytes = marshalUtil.ReadOffset() return @@ -45,11 +48,12 @@ func FromBytes(bytes []byte) (result *Balance, err error, consumedBytes int) { // Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. func Parse(marshalUtil *marshalutil.MarshalUtil) (*Balance, error) { - if address, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { + address, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return FromBytes(data) }) + if err != nil { return nil, err - } else { - return address.(*Balance), nil } + + return address.(*Balance), nil } // Value returns the numeric value of the balance. @@ -62,6 +66,7 @@ func (balance *Balance) Color() Color { return balance.color } +// Bytes marshals the Balance into a sequence of bytes. func (balance *Balance) Bytes() []byte { marshalUtil := marshalutil.New(Length) @@ -71,6 +76,7 @@ func (balance *Balance) Bytes() []byte { return marshalUtil.Bytes() } +// String creates a human readable string of the Balance. func (balance *Balance) String() string { return strconv.FormatInt(balance.value, 10) + " " + balance.color.String() } diff --git a/dapps/valuetransfers/packages/balance/balance_test.go b/dapps/valuetransfers/packages/balance/balance_test.go index d807eab771dd7465f8b32b473f85f3c226004a68..5dd98567cf634ec3ad3bd8ede4a42ed6d0ab4932 100644 --- a/dapps/valuetransfers/packages/balance/balance_test.go +++ b/dapps/valuetransfers/packages/balance/balance_test.go @@ -14,7 +14,7 @@ func TestMarshalUnmarshal(t *testing.T) { marshaledBalance := balance.Bytes() assert.Equal(t, Length, len(marshaledBalance)) - restoredBalance, err, consumedBytes := FromBytes(marshaledBalance) + restoredBalance, consumedBytes, err := FromBytes(marshaledBalance) if err != nil { panic(err) } diff --git a/dapps/valuetransfers/packages/balance/color.go b/dapps/valuetransfers/packages/balance/color.go index 33cd961e9bca4335cc4ee244d56fb8a489bf55bd..4fba5d26bb8f402fabb54a25ba08a3cae33070ad 100644 --- a/dapps/valuetransfers/packages/balance/color.go +++ b/dapps/valuetransfers/packages/balance/color.go @@ -5,9 +5,12 @@ import ( "github.com/mr-tron/base58" ) +// Color represents a marker that is associated to a token balance and that gives it a certain "meaning". The zero value +// represents "vanilla" IOTA tokens but it is also possible to define tokens that represent i.e. real world assets. type Color [ColorLength]byte -func ColorFromBytes(bytes []byte) (result Color, err error, consumedBytes int) { +// ColorFromBytes unmarshals a Color from a sequence of bytes. +func ColorFromBytes(bytes []byte) (result Color, consumedBytes int, err error) { colorBytes, err := marshalutil.New(bytes).ReadBytes(ColorLength) if err != nil { return @@ -19,12 +22,12 @@ func ColorFromBytes(bytes []byte) (result Color, err error, consumedBytes int) { return } -const ColorLength = 32 - +// Bytes marshals the Color into a sequence of bytes. func (color Color) Bytes() []byte { return color[:] } +// String creates a human readable string of the Color. func (color Color) String() string { if color == ColorIOTA { return "IOTA" @@ -33,6 +36,12 @@ func (color Color) String() string { return base58.Encode(color[:]) } +// ColorLength represents the length of a Color (amount of bytes). +const ColorLength = 32 + +// ColorIOTA is the zero value of the Color and represents vanilla IOTA tokens. var ColorIOTA Color = [32]byte{} +// ColorNew represents a placeholder Color that will be replaced with the transaction ID that created the funds. It is +// used to indicate that tokens should be "colored" in their Output (minting new colored coins). var ColorNew = [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} diff --git a/dapps/valuetransfers/packages/branchmanager/branch.go b/dapps/valuetransfers/packages/branchmanager/branch.go index d513e1baac0c0b8823bba457461d4fd172e34979..c48f009025279dc722d98a2b325f5c568bf6e2ad 100644 --- a/dapps/valuetransfers/packages/branchmanager/branch.go +++ b/dapps/valuetransfers/packages/branchmanager/branch.go @@ -11,12 +11,15 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" ) +// Branch represents a part of the tangle, that shares the same perception of the ledger state. Every conflicting +// transaction formw a Branch, that contains all transactions that are spending Outputs of the conflicting transactions. +// Branches can also be created by merging two other Branches, which creates an aggregated Branch. type Branch struct { objectstorage.StorableObjectFlags - id BranchId - parentBranches []BranchId - conflicts map[ConflictId]types.Empty + id BranchID + parentBranches []BranchID + conflicts map[ConflictID]types.Empty preferred bool liked bool @@ -25,8 +28,9 @@ type Branch struct { likedMutex sync.RWMutex } -func NewBranch(id BranchId, parentBranches []BranchId, conflictingInputs []transaction.OutputId) *Branch { - conflictingInputsMap := make(map[ConflictId]types.Empty) +// NewBranch is the constructor of a Branch and creates a new Branch object from the given details. +func NewBranch(id BranchID, parentBranches []BranchID, conflictingInputs []transaction.OutputID) *Branch { + conflictingInputsMap := make(map[ConflictID]types.Empty) for _, conflictingInput := range conflictingInputs { conflictingInputsMap[conflictingInput] = types.Void } @@ -38,7 +42,9 @@ func NewBranch(id BranchId, parentBranches []BranchId, conflictingInputs []trans } } -func BranchFromStorageKey(key []byte, optionalTargetObject ...*Branch) (result *Branch, err error, consumedBytes int) { +// BranchFromStorageKey is a factory method that creates a new Branch instance from a storage key of the objectstorage. +// It is used by the objectstorage, to create new instances of this entity. +func BranchFromStorageKey(key []byte, optionalTargetObject ...*Branch) (result *Branch, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -51,7 +57,7 @@ func BranchFromStorageKey(key []byte, optionalTargetObject ...*Branch) (result * // parse information marshalUtil := marshalutil.New(key) - result.id, err = ParseBranchId(marshalUtil) + result.id, err = ParseBranchID(marshalUtil) if err != nil { return } @@ -60,7 +66,8 @@ func BranchFromStorageKey(key []byte, optionalTargetObject ...*Branch) (result * return } -func BranchFromBytes(bytes []byte, optionalTargetObject ...*Branch) (result *Branch, err error, consumedBytes int) { +// BranchFromBytes unmarshals a Branch from a sequence of bytes. +func BranchFromBytes(bytes []byte, optionalTargetObject ...*Branch) (result *Branch, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseBranch(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -68,19 +75,18 @@ func BranchFromBytes(bytes []byte, optionalTargetObject ...*Branch) (result *Bra return } +// ParseBranch unmarshals a Branch using the given marshalUtil (for easier marshaling/unmarshaling). func ParseBranch(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Branch) (result *Branch, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return BranchFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { - err = parseErr - + }) + if err != nil { return - } else { - result = parsedObject.(*Branch) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*Branch) + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -90,23 +96,28 @@ func ParseBranch(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...* return } -func (branch *Branch) Id() BranchId { +// ID returns the identifier of the Branch (usually the transaction.ID that created the branch - unless its an +// aggregated Branch). +func (branch *Branch) ID() BranchID { return branch.id } -func (branch *Branch) ParentBranches() []BranchId { +// ParentBranches returns the identifiers of the parents of this Branch. +func (branch *Branch) ParentBranches() []BranchID { return branch.parentBranches } +// IsAggregated returns true if the branch is not a conflict-branch, but was created by merging multiple other branches. func (branch *Branch) IsAggregated() bool { return len(branch.parentBranches) > 1 } -func (branch *Branch) Conflicts() (conflicts map[ConflictId]types.Empty) { +// Conflicts retrieves the Conflicts that a Branch is part of. +func (branch *Branch) Conflicts() (conflicts map[ConflictID]types.Empty) { branch.conflictsMutex.RLock() defer branch.conflictsMutex.RUnlock() - conflicts = make(map[ConflictId]types.Empty, len(branch.conflicts)) + conflicts = make(map[ConflictID]types.Empty, len(branch.conflicts)) for conflict := range branch.conflicts { conflicts[conflict] = types.Void } @@ -114,7 +125,8 @@ func (branch *Branch) Conflicts() (conflicts map[ConflictId]types.Empty) { return } -func (branch *Branch) AddConflict(conflict ConflictId) (added bool) { +// AddConflict registers the membership of this Branch in a given +func (branch *Branch) AddConflict(conflict ConflictID) (added bool) { branch.conflictsMutex.RLock() if _, exists := branch.conflicts[conflict]; exists { branch.conflictsMutex.RUnlock() @@ -136,6 +148,7 @@ func (branch *Branch) AddConflict(conflict ConflictId) (added bool) { return } +// Preferred returns true, if the branch is the favored one among the branches in the same conflict sets. func (branch *Branch) Preferred() bool { branch.preferredMutex.RLock() defer branch.preferredMutex.RUnlock() @@ -143,6 +156,8 @@ func (branch *Branch) Preferred() bool { return branch.preferred } +// SetPreferred is the setter for the preferred flag. It returns true if the value of the flag has been updated. +// A branch is preferred if it represents the "liked" part of the tangle in it corresponding Branch. func (branch *Branch) SetPreferred(preferred bool) (modified bool) { branch.preferredMutex.RLock() if branch.preferred == preferred { @@ -165,6 +180,7 @@ func (branch *Branch) SetPreferred(preferred bool) (modified bool) { return branch.preferred } +// Liked returns if the branch is liked (it is preferred and all of its parents are liked). func (branch *Branch) Liked() bool { branch.likedMutex.RLock() defer branch.likedMutex.RUnlock() @@ -172,6 +188,7 @@ func (branch *Branch) Liked() bool { return branch.liked } +// SetLiked modifies the liked flag of this branch. It returns true, if the current value has been modified. func (branch *Branch) SetLiked(liked bool) (modified bool) { branch.likedMutex.RLock() if branch.liked == liked { @@ -194,6 +211,7 @@ func (branch *Branch) SetLiked(liked bool) (modified bool) { return branch.liked } +// Bytes returns a marshaled version of this Branch. func (branch *Branch) Bytes() []byte { return marshalutil.New(). WriteBytes(branch.ObjectStorageKey()). @@ -201,20 +219,25 @@ func (branch *Branch) Bytes() []byte { Bytes() } +// String returns a human readable version of this Branch (for debug purposes). func (branch *Branch) String() string { return stringify.Struct("Branch", - stringify.StructField("id", branch.Id()), + stringify.StructField("id", branch.ID()), ) } +// Update is disabled but needs to be implemented to be compatible with the objectstorage. func (branch *Branch) Update(other objectstorage.StorableObject) { panic("updates are disabled - please use the setters") } +// ObjectStorageKey returns the bytes that are used as a key when storing the Branch in an objectstorage. func (branch *Branch) ObjectStorageKey() []byte { return branch.id.Bytes() } +// ObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a marshaled +// Branch. func (branch *Branch) ObjectStorageValue() []byte { branch.preferredMutex.RLock() branch.likedMutex.RLock() @@ -224,18 +247,19 @@ func (branch *Branch) ObjectStorageValue() []byte { parentBranches := branch.ParentBranches() parentBranchCount := len(parentBranches) - marshalUtil := marshalutil.New(2*marshalutil.BOOL_SIZE + marshalutil.UINT32_SIZE + parentBranchCount*BranchIdLength) + marshalUtil := marshalutil.New(2*marshalutil.BOOL_SIZE + marshalutil.UINT32_SIZE + parentBranchCount*BranchIDLength) marshalUtil.WriteBool(branch.preferred) marshalUtil.WriteBool(branch.liked) marshalUtil.WriteUint32(uint32(parentBranchCount)) - for _, branchId := range parentBranches { - marshalUtil.WriteBytes(branchId.Bytes()) + for _, branchID := range parentBranches { + marshalUtil.WriteBytes(branchID.Bytes()) } return marshalUtil.Bytes() } -func (branch *Branch) UnmarshalObjectStorageValue(valueBytes []byte) (err error, consumedBytes int) { +// UnmarshalObjectStorageValue unmarshals the bytes that are stored in the value of the objectstorage. +func (branch *Branch) UnmarshalObjectStorageValue(valueBytes []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(valueBytes) branch.preferred, err = marshalUtil.ReadBool() if err != nil { @@ -249,9 +273,9 @@ func (branch *Branch) UnmarshalObjectStorageValue(valueBytes []byte) (err error, if err != nil { return } - branch.parentBranches = make([]BranchId, parentBranchCount) + branch.parentBranches = make([]BranchID, parentBranchCount) for i := uint32(0); i < parentBranchCount; i++ { - branch.parentBranches[i], err = ParseBranchId(marshalUtil) + branch.parentBranches[i], err = ParseBranchID(marshalUtil) if err != nil { return } @@ -261,34 +285,46 @@ func (branch *Branch) UnmarshalObjectStorageValue(valueBytes []byte) (err error, return } +// CachedBranch is a wrapper for the generic CachedObject returned by the objectstorage, that overrides the accessor +// methods, with a type-casted one. type CachedBranch struct { objectstorage.CachedObject } -func (cachedBranches *CachedBranch) Retain() *CachedBranch { - return &CachedBranch{cachedBranches.CachedObject.Retain()} +// Retain marks this CachedObject to still be in use by the program. +func (cachedBranch *CachedBranch) Retain() *CachedBranch { + return &CachedBranch{cachedBranch.CachedObject.Retain()} } -func (cachedBranches *CachedBranch) Unwrap() *Branch { - if untypedObject := cachedBranches.Get(); untypedObject == nil { +// Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. +func (cachedBranch *CachedBranch) Unwrap() *Branch { + untypedObject := cachedBranch.Get() + if untypedObject == nil { return nil - } else { - if typedObject := untypedObject.(*Branch); typedObject == nil || typedObject.IsDeleted() { - return nil - } else { - return typedObject - } } + + typedObject := untypedObject.(*Branch) + if typedObject == nil || typedObject.IsDeleted() { + return nil + } + + return typedObject } -func (cachedBranches *CachedBranch) Consume(consumer func(branch *Branch), forceRelease ...bool) (consumed bool) { - return cachedBranches.CachedObject.Consume(func(object objectstorage.StorableObject) { +// Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it +// exists). It automatically releases the object when the consumer finishes. +func (cachedBranch *CachedBranch) Consume(consumer func(branch *Branch), forceRelease ...bool) (consumed bool) { + return cachedBranch.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*Branch)) }, forceRelease...) } -type CachedBranches map[BranchId]*CachedBranch +// CachedBranches represents a collection of CachedBranches. +type CachedBranches map[BranchID]*CachedBranch +// Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object +// is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at +// least one object was consumed. func (cachedBranches CachedBranches) Consume(consumer func(branch *Branch)) (consumed bool) { for _, cachedBranch := range cachedBranches { consumed = cachedBranch.Consume(func(output *Branch) { @@ -299,6 +335,7 @@ func (cachedBranches CachedBranches) Consume(consumer func(branch *Branch)) (con return } +// Release is a utility function that allows us to release all CachedObjects in the collection. func (cachedBranches CachedBranches) Release(force ...bool) { for _, cachedBranch := range cachedBranches { cachedBranch.Release(force...) diff --git a/dapps/valuetransfers/packages/branchmanager/branchid.go b/dapps/valuetransfers/packages/branchmanager/branchid.go index 1840c57ab5a041a14119912f51a385bae913e33d..70e8aa532e4155c1b8f80108c58b0ad6906717e3 100644 --- a/dapps/valuetransfers/packages/branchmanager/branchid.go +++ b/dapps/valuetransfers/packages/branchmanager/branchid.go @@ -10,36 +10,42 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" ) -type BranchId [BranchIdLength]byte +// BranchID represents an identifier of a Branch. +type BranchID [BranchIDLength]byte var ( - UndefinedBranchId = BranchId{} - MasterBranchId = BranchId{1} + // UndefinedBranchID is the zero value of a BranchID and represents a branch that has not been set. + UndefinedBranchID = BranchID{} + + // MasterBranchID is the identifier of the MasterBranch (root of the Branch DAG). + MasterBranchID = BranchID{1} ) -// NewBranchId creates a new BranchId from a transaction Id. -func NewBranchId(transactionId transaction.Id) (branchId BranchId) { - copy(branchId[:], transactionId.Bytes()) +// NewBranchID creates a new BranchID from a transaction ID. +func NewBranchID(transactionID transaction.ID) (branchID BranchID) { + copy(branchID[:], transactionID.Bytes()) return } -func BranchIdFromBytes(bytes []byte) (result BranchId, err error, consumedBytes int) { +// BranchIDFromBytes unmarshals a BranchID from a sequence of bytes. +func BranchIDFromBytes(bytes []byte) (result BranchID, consumedBytes int, err error) { // parse the bytes marshalUtil := marshalutil.New(bytes) - branchIdBytes, idErr := marshalUtil.ReadBytes(BranchIdLength) + branchIDBytes, idErr := marshalUtil.ReadBytes(BranchIDLength) if idErr != nil { err = idErr return } - copy(result[:], branchIdBytes) + copy(result[:], branchIDBytes) consumedBytes = marshalUtil.ReadOffset() return } -func BranchIdFromBase58(base58String string) (branchId BranchId, err error) { +// BranchIDFromBase58 creates a new BranchID from a base58 encoded string. +func BranchIDFromBase58(base58String string) (branchID BranchID, err error) { // decode string bytes, err := base58.Decode(base58String) if err != nil { @@ -47,50 +53,53 @@ func BranchIdFromBase58(base58String string) (branchId BranchId, err error) { } // sanitize input - if len(bytes) != BranchIdLength { - err = fmt.Errorf("base58 encoded string does not match the length of a BranchId") + if len(bytes) != BranchIDLength { + err = fmt.Errorf("base58 encoded string does not match the length of a BranchID") return } // copy bytes to result - copy(branchId[:], bytes) + copy(branchID[:], bytes) return } -func ParseBranchId(marshalUtil *marshalutil.MarshalUtil) (result BranchId, err error) { - var branchIdBytes []byte - if branchIdBytes, err = marshalUtil.ReadBytes(BranchIdLength); err != nil { +// ParseBranchID unmarshals a BranchID using the given marshalUtil (for easier marshaling/unmarshaling). +func ParseBranchID(marshalUtil *marshalutil.MarshalUtil) (result BranchID, err error) { + var branchIDBytes []byte + if branchIDBytes, err = marshalUtil.ReadBytes(BranchIDLength); err != nil { return } - copy(result[:], branchIdBytes) + copy(result[:], branchIDBytes) return } -// Bytes marshals the BranchId into a sequence of bytes. -func (branchId BranchId) Bytes() []byte { +// Bytes marshals the BranchID into a sequence of bytes. +func (branchId BranchID) Bytes() []byte { return branchId[:] } -// String creates a base58 encoded version of the BranchId. -func (branchId BranchId) String() string { +// String creates a base58 encoded version of the BranchID. +func (branchId BranchID) String() string { return base58.Encode(branchId[:]) } -// BranchIdLength encodes the length of a branch identifier - since branches get created by transactions, it has the -// same length as a transaction Id. -const BranchIdLength = transaction.IdLength +// BranchIDLength encodes the length of a branch identifier - since branches get created by transactions, it has the +// same length as a transaction ID. +const BranchIDLength = transaction.IDLength -type BranchIds map[BranchId]types.Empty +// BranchIds represents a collection of BranchIds. +type BranchIds map[BranchID]types.Empty -func (branchIds BranchIds) ToList() (result []BranchId) { - result = make([]BranchId, len(branchIds)) +// ToList create a slice of BranchIDs from the collection. +func (branchIDs BranchIds) ToList() (result []BranchID) { + result = make([]BranchID, len(branchIDs)) i := 0 - for branchId := range branchIds { - result[i] = branchId + for branchID := range branchIDs { + result[i] = branchID i++ } diff --git a/dapps/valuetransfers/packages/branchmanager/branchmanager.go b/dapps/valuetransfers/packages/branchmanager/branchmanager.go index 799568cc3b15fd35cf45315e25787f1d5b93113b..43f38c976a2dbc0af8a1ff53ca0840b92ed6f0f9 100644 --- a/dapps/valuetransfers/packages/branchmanager/branchmanager.go +++ b/dapps/valuetransfers/packages/branchmanager/branchmanager.go @@ -14,6 +14,8 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/storageprefix" ) +// BranchManager is an entity, that manages the branches of a UTXODAG. It offers methods to add, delete and modify +// Branches. It automatically keeps track of maintaining a valid perception. type BranchManager struct { branchStorage *objectstorage.ObjectStorage childBranchStorage *objectstorage.ObjectStorage @@ -23,6 +25,7 @@ type BranchManager struct { Events *Events } +// New is the constructor of the BranchManager. It creates a new instance with the given storage details. func New(badgerInstance *badger.DB) (result *BranchManager) { osFactory := objectstorage.NewFactory(badgerInstance, storageprefix.ValueTransfers) @@ -35,26 +38,29 @@ func New(badgerInstance *badger.DB) (result *BranchManager) { } func (branchManager *BranchManager) init() { - branchManager.branchStorage.StoreIfAbsent(NewBranch(MasterBranchId, []BranchId{}, []ConflictId{})) + branchManager.branchStorage.StoreIfAbsent(NewBranch(MasterBranchID, []BranchID{}, []ConflictID{})) } -func (branchManager *BranchManager) Conflict(conflictId ConflictId) *CachedConflict { - return &CachedConflict{CachedObject: branchManager.conflictStorage.Load(conflictId.Bytes())} +// Conflict loads the corresponding Conflict from the objectstorage. +func (branchManager *BranchManager) Conflict(conflictID ConflictID) *CachedConflict { + return &CachedConflict{CachedObject: branchManager.conflictStorage.Load(conflictID.Bytes())} } -func (branchManager *BranchManager) ConflictMembers(conflictId ConflictId) CachedConflictMembers { +// ConflictMembers loads the ConflictMembers that are part of the same Conflict from the objectstorage. +func (branchManager *BranchManager) ConflictMembers(conflictID ConflictID) CachedConflictMembers { conflictMembers := make(CachedConflictMembers, 0) branchManager.conflictMemberStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { conflictMembers = append(conflictMembers, &CachedConflictMember{CachedObject: cachedObject}) return true - }, conflictId.Bytes()) + }, conflictID.Bytes()) return conflictMembers } +// AddBranch adds a new Branch to the branch-DAG. func (branchManager *BranchManager) AddBranch(branch *Branch) *CachedBranch { - return &CachedBranch{CachedObject: branchManager.branchStorage.ComputeIfAbsent(branch.Id().Bytes(), func(key []byte) objectstorage.StorableObject { + return &CachedBranch{CachedObject: branchManager.branchStorage.ComputeIfAbsent(branch.ID().Bytes(), func(key []byte) objectstorage.StorableObject { branch.Persist() branch.SetModified() @@ -62,20 +68,22 @@ func (branchManager *BranchManager) AddBranch(branch *Branch) *CachedBranch { })} } -func (branchManager *BranchManager) GetBranch(branchId BranchId) *CachedBranch { - return &CachedBranch{CachedObject: branchManager.branchStorage.Load(branchId.Bytes())} +// Branch loads a Branch from the objectstorage. +func (branchManager *BranchManager) Branch(branchID BranchID) *CachedBranch { + return &CachedBranch{CachedObject: branchManager.branchStorage.Load(branchID.Bytes())} } -func (branchManager *BranchManager) InheritBranches(branches ...BranchId) (cachedAggregatedBranch *CachedBranch, err error) { +// InheritBranches takes a list of BranchIDs and tries to "inherit" the given IDs into a new Branch. +func (branchManager *BranchManager) InheritBranches(branches ...BranchID) (cachedAggregatedBranch *CachedBranch, err error) { // return the MasterBranch if we have no branches in the parameters if len(branches) == 0 { - cachedAggregatedBranch = branchManager.GetBranch(MasterBranchId) + cachedAggregatedBranch = branchManager.Branch(MasterBranchID) return } if len(branches) == 1 { - cachedAggregatedBranch = branchManager.GetBranch(branches[0]) + cachedAggregatedBranch = branchManager.Branch(branches[0]) return } @@ -96,19 +104,19 @@ func (branchManager *BranchManager) InheritBranches(branches ...BranchId) (cache } // if there is more than one parents: aggregate - aggregatedBranchId, aggregatedBranchParents, err := branchManager.determineAggregatedBranchDetails(deepestCommonAncestors) + aggregatedBranchID, aggregatedBranchParents, err := branchManager.determineAggregatedBranchDetails(deepestCommonAncestors) if err != nil { return } newAggregatedBranchCreated := false - cachedAggregatedBranch = &CachedBranch{CachedObject: branchManager.branchStorage.ComputeIfAbsent(aggregatedBranchId.Bytes(), func(key []byte) (object objectstorage.StorableObject) { - aggregatedReality := NewBranch(aggregatedBranchId, aggregatedBranchParents, []ConflictId{}) + cachedAggregatedBranch = &CachedBranch{CachedObject: branchManager.branchStorage.ComputeIfAbsent(aggregatedBranchID.Bytes(), func(key []byte) (object objectstorage.StorableObject) { + aggregatedReality := NewBranch(aggregatedBranchID, aggregatedBranchParents, []ConflictID{}) // TODO: FIX /* for _, parentRealityId := range aggregatedBranchParents { - tangle.GetBranch(parentRealityId).Consume(func(branch *Branch) { + tangle.Branch(parentRealityId).Consume(func(branch *Branch) { branch.RegisterSubReality(aggregatedRealityId) }) } @@ -129,7 +137,7 @@ func (branchManager *BranchManager) InheritBranches(branches ...BranchId) (cache for _, realityId := range aggregatedBranchParents { if aggregatedBranch.AddParentReality(realityId) { - tangle.GetBranch(realityId).Consume(func(branch *Branch) { + tangle.Branch(realityId).Consume(func(branch *Branch) { branch.RegisterSubReality(aggregatedRealityId) }) } @@ -140,19 +148,21 @@ func (branchManager *BranchManager) InheritBranches(branches ...BranchId) (cache return } -func (branchManager *BranchManager) ChildBranches(branchId BranchId) CachedChildBranches { +// ChildBranches loads the ChildBranches that are forking off, of the given Branch. +func (branchManager *BranchManager) ChildBranches(branchID BranchID) CachedChildBranches { childBranches := make(CachedChildBranches, 0) branchManager.childBranchStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { childBranches = append(childBranches, &CachedChildBranch{CachedObject: cachedObject}) return true - }, branchId.Bytes()) + }, branchID.Bytes()) return childBranches } -func (branchManager *BranchManager) SetBranchPreferred(branchId BranchId, preferred bool) (modified bool, err error) { - return branchManager.setBranchPreferred(branchManager.GetBranch(branchId), preferred) +// SetBranchPreferred is the method that allows us to modify the preferred flag of a transaction. +func (branchManager *BranchManager) SetBranchPreferred(branchID BranchID, preferred bool) (modified bool, err error) { + return branchManager.setBranchPreferred(branchManager.Branch(branchID), preferred) } func (branchManager *BranchManager) setBranchPreferred(cachedBranch *CachedBranch, preferred bool) (modified bool, err error) { @@ -174,13 +184,13 @@ func (branchManager *BranchManager) setBranchPreferred(cachedBranch *CachedBranc return } - for conflictId := range branch.Conflicts() { - branchManager.ConflictMembers(conflictId).Consume(func(conflictMember *ConflictMember) { - if conflictMember.BranchId() == branch.Id() { + for conflictID := range branch.Conflicts() { + branchManager.ConflictMembers(conflictID).Consume(func(conflictMember *ConflictMember) { + if conflictMember.BranchID() == branch.ID() { return } - _, _ = branchManager.setBranchPreferred(branchManager.GetBranch(conflictMember.BranchId()), false) + _, _ = branchManager.setBranchPreferred(branchManager.Branch(conflictMember.BranchID()), false) }) } @@ -204,14 +214,14 @@ func (branchManager *BranchManager) propagateLike(cachedBranch *CachedBranch) (e } // check if parents are liked - for _, parentBranchId := range branch.ParentBranches() { + for _, parentBranchID := range branch.ParentBranches() { // abort, if the parent branch can not be loaded - cachedParentBranch := branchManager.GetBranch(parentBranchId) + cachedParentBranch := branchManager.Branch(parentBranchID) parentBranch := cachedParentBranch.Unwrap() if parentBranch == nil { cachedParentBranch.Release() - return fmt.Errorf("failed to load parent branch '%s' of branch '%s'", parentBranchId, branch.Id()) + return fmt.Errorf("failed to load parent branch '%s' of branch '%s'", parentBranchID, branch.ID()) } // abort if the parent branch is not liked @@ -233,7 +243,7 @@ func (branchManager *BranchManager) propagateLike(cachedBranch *CachedBranch) (e branchManager.Events.BranchLiked.Trigger(cachedBranch) // propagate liked checks to the children - for _, cachedChildBranch := range branchManager.ChildBranches(branch.Id()) { + for _, cachedChildBranch := range branchManager.ChildBranches(branch.ID()) { childBranch := cachedChildBranch.Unwrap() if childBranch == nil { cachedChildBranch.Release() @@ -241,7 +251,7 @@ func (branchManager *BranchManager) propagateLike(cachedBranch *CachedBranch) (e continue } - if err = branchManager.propagateLike(branchManager.GetBranch(childBranch.Id())); err != nil { + if err = branchManager.propagateLike(branchManager.Branch(childBranch.ChildID())); err != nil { cachedChildBranch.Release() return @@ -262,17 +272,17 @@ func (branchManager *BranchManager) propagateDislike(cachedBranch *CachedBranch) branchManager.Events.BranchDisliked.Trigger(cachedBranch) - branchManager.ChildBranches(branch.Id()).Consume(func(childBranch *ChildBranch) { - branchManager.propagateDislike(branchManager.GetBranch(childBranch.Id())) + branchManager.ChildBranches(branch.ID()).Consume(func(childBranch *ChildBranch) { + branchManager.propagateDislike(branchManager.Branch(childBranch.ChildID())) }) } -func (branchManager *BranchManager) determineAggregatedBranchDetails(deepestCommonAncestors CachedBranches) (aggregatedBranchId BranchId, aggregatedBranchParents []BranchId, err error) { - aggregatedBranchParents = make([]BranchId, len(deepestCommonAncestors)) +func (branchManager *BranchManager) determineAggregatedBranchDetails(deepestCommonAncestors CachedBranches) (aggregatedBranchID BranchID, aggregatedBranchParents []BranchID, err error) { + aggregatedBranchParents = make([]BranchID, len(deepestCommonAncestors)) i := 0 aggregatedBranchConflictParents := make(CachedBranches) - for branchId, cachedBranch := range deepestCommonAncestors { + for branchID, cachedBranch := range deepestCommonAncestors { // release all following entries if we have encountered an error if err != nil { cachedBranch.Release() @@ -280,8 +290,8 @@ func (branchManager *BranchManager) determineAggregatedBranchDetails(deepestComm continue } - // store BranchId as parent - aggregatedBranchParents[i] = branchId + // store BranchID as parent + aggregatedBranchParents[i] = branchID i++ // abort if we could not unwrap the Branch (should never happen) @@ -289,13 +299,13 @@ func (branchManager *BranchManager) determineAggregatedBranchDetails(deepestComm if branch == nil { cachedBranch.Release() - err = fmt.Errorf("failed to unwrap brach '%s'", branchId) + err = fmt.Errorf("failed to unwrap brach '%s'", branchID) continue } if branch.IsAggregated() { - aggregatedBranchConflictParents[branchId] = cachedBranch + aggregatedBranchConflictParents[branchID] = cachedBranch continue } @@ -312,27 +322,27 @@ func (branchManager *BranchManager) determineAggregatedBranchDetails(deepestComm return } - aggregatedBranchId = branchManager.generateAggregatedBranchId(aggregatedBranchConflictParents) + aggregatedBranchID = branchManager.generateAggregatedBranchID(aggregatedBranchConflictParents) return } -func (branchManager *BranchManager) generateAggregatedBranchId(aggregatedBranches CachedBranches) BranchId { +func (branchManager *BranchManager) generateAggregatedBranchID(aggregatedBranches CachedBranches) BranchID { counter := 0 - branchIds := make([]BranchId, len(aggregatedBranches)) - for branchId, cachedBranch := range aggregatedBranches { - branchIds[counter] = branchId + branchIDs := make([]BranchID, len(aggregatedBranches)) + for branchID, cachedBranch := range aggregatedBranches { + branchIDs[counter] = branchID counter++ cachedBranch.Release() } - sort.Slice(branchIds, func(i, j int) bool { - for k := 0; k < len(branchIds[k]); k++ { - if branchIds[i][k] < branchIds[j][k] { + sort.Slice(branchIDs, func(i, j int) bool { + for k := 0; k < len(branchIDs[k]); k++ { + if branchIDs[i][k] < branchIDs[j][k] { return true - } else if branchIds[i][k] > branchIds[j][k] { + } else if branchIDs[i][k] > branchIDs[j][k] { return false } } @@ -340,9 +350,9 @@ func (branchManager *BranchManager) generateAggregatedBranchId(aggregatedBranche return false }) - marshalUtil := marshalutil.New(BranchIdLength * len(branchIds)) - for _, branchId := range branchIds { - marshalUtil.WriteBytes(branchId.Bytes()) + marshalUtil := marshalutil.New(BranchIDLength * len(branchIDs)) + for _, branchID := range branchIDs { + marshalUtil.WriteBytes(branchID.Bytes()) } return blake2b.Sum256(marshalUtil.Bytes()) @@ -351,47 +361,47 @@ func (branchManager *BranchManager) generateAggregatedBranchId(aggregatedBranche func (branchManager *BranchManager) collectClosestConflictAncestors(branch *Branch, closestConflictAncestors CachedBranches) (err error) { // initialize stack stack := list.New() - for _, parentRealityId := range branch.ParentBranches() { - stack.PushBack(parentRealityId) + for _, parentRealityID := range branch.ParentBranches() { + stack.PushBack(parentRealityID) } // work through stack - processedBranches := make(map[BranchId]types.Empty) + processedBranches := make(map[BranchID]types.Empty) for stack.Len() != 0 { // iterate through the parents (in a func so we can used defer) err = func() error { // pop parent branch id from stack firstStackElement := stack.Front() defer stack.Remove(firstStackElement) - parentBranchId := stack.Front().Value.(BranchId) + parentBranchID := stack.Front().Value.(BranchID) // abort if the parent has been processed already - if _, branchProcessed := processedBranches[parentBranchId]; branchProcessed { + if _, branchProcessed := processedBranches[parentBranchID]; branchProcessed { return nil } - processedBranches[parentBranchId] = types.Void + processedBranches[parentBranchID] = types.Void // load parent branch from database - cachedParentBranch := branchManager.GetBranch(parentBranchId) + cachedParentBranch := branchManager.Branch(parentBranchID) // abort if the parent branch could not be found (should never happen) parentBranch := cachedParentBranch.Unwrap() if parentBranch == nil { cachedParentBranch.Release() - return fmt.Errorf("failed to load branch '%s'", parentBranchId) + return fmt.Errorf("failed to load branch '%s'", parentBranchID) } // if the parent Branch is not aggregated, then we have found the closest conflict ancestor if !parentBranch.IsAggregated() { - closestConflictAncestors[parentBranchId] = cachedParentBranch + closestConflictAncestors[parentBranchID] = cachedParentBranch return nil } // queue parents for additional check (recursion) - for _, parentRealityId := range parentBranch.ParentBranches() { - stack.PushBack(parentRealityId) + for _, parentRealityID := range parentBranch.ParentBranches() { + stack.PushBack(parentRealityID) } // release the branch (we don't need it anymore) @@ -413,35 +423,35 @@ func (branchManager *BranchManager) collectClosestConflictAncestors(branch *Bran // // Example: If we hand in "A, B" and B has A as its parent, then the result will contain the Branch B, because B is a // child of A. -func (branchManager *BranchManager) findDeepestCommonAncestorBranches(branches ...BranchId) (result CachedBranches, err error) { +func (branchManager *BranchManager) findDeepestCommonAncestorBranches(branches ...BranchID) (result CachedBranches, err error) { result = make(CachedBranches) - processedBranches := make(map[BranchId]types.Empty) - for _, branchId := range branches { + processedBranches := make(map[BranchID]types.Empty) + for _, branchID := range branches { err = func() error { // continue, if we have processed this branch already - if _, exists := processedBranches[branchId]; exists { + if _, exists := processedBranches[branchID]; exists { return nil } - processedBranches[branchId] = types.Void + processedBranches[branchID] = types.Void // load branch from objectstorage - cachedBranch := branchManager.GetBranch(branchId) + cachedBranch := branchManager.Branch(branchID) // abort if we could not load the CachedBranch branch := cachedBranch.Unwrap() if branch == nil { cachedBranch.Release() - return fmt.Errorf("could not load branch '%s'", branchId) + return fmt.Errorf("could not load branch '%s'", branchID) } // check branches position relative to already aggregated branches - for aggregatedBranchId, cachedAggregatedBranch := range result { + for aggregatedBranchID, cachedAggregatedBranch := range result { // abort if we can not load the branch aggregatedBranch := cachedAggregatedBranch.Unwrap() if aggregatedBranch == nil { - return fmt.Errorf("could not load branch '%s'", aggregatedBranchId) + return fmt.Errorf("could not load branch '%s'", aggregatedBranchID) } // if the current branch is an ancestor of an already aggregated branch, then we have found the more @@ -460,10 +470,10 @@ func (branchManager *BranchManager) findDeepestCommonAncestorBranches(branches . // Branch and replace the old one with this one. if isAncestor { // replace aggregated branch if we have found a more specialized on - delete(result, aggregatedBranchId) + delete(result, aggregatedBranchID) cachedAggregatedBranch.Release() - result[branchId] = cachedBranch + result[branchID] = cachedBranch return nil } @@ -471,7 +481,7 @@ func (branchManager *BranchManager) findDeepestCommonAncestorBranches(branches . // store the branch as a new aggregate candidate if it was not found to be in any relation with the already // aggregated ones. - result[branchId] = cachedBranch + result[branchID] = cachedBranch return nil }() @@ -489,7 +499,7 @@ func (branchManager *BranchManager) findDeepestCommonAncestorBranches(branches . } func (branchManager *BranchManager) branchIsAncestorOfBranch(ancestor *Branch, descendant *Branch) (isAncestor bool, err error) { - if ancestor.Id() == descendant.Id() { + if ancestor.ID() == descendant.ID() { return true, nil } @@ -499,7 +509,7 @@ func (branchManager *BranchManager) branchIsAncestorOfBranch(ancestor *Branch, d } ancestorBranches.Consume(func(ancestorOfDescendant *Branch) { - if ancestorOfDescendant.Id() == ancestor.Id() { + if ancestorOfDescendant.ID() == ancestor.ID() { isAncestor = true } }) @@ -513,8 +523,8 @@ func (branchManager *BranchManager) getAncestorBranches(branch *Branch) (ancesto // initialize stack stack := list.New() - for _, parentRealityId := range branch.ParentBranches() { - stack.PushBack(parentRealityId) + for _, parentRealityID := range branch.ParentBranches() { + stack.PushBack(parentRealityID) } // work through stack @@ -524,30 +534,30 @@ func (branchManager *BranchManager) getAncestorBranches(branch *Branch) (ancesto // pop parent branch id from stack firstStackElement := stack.Front() defer stack.Remove(firstStackElement) - parentBranchId := stack.Front().Value.(BranchId) + parentBranchID := stack.Front().Value.(BranchID) // abort if the parent has been processed already - if _, branchProcessed := ancestorBranches[parentBranchId]; branchProcessed { + if _, branchProcessed := ancestorBranches[parentBranchID]; branchProcessed { return nil } // load parent branch from database - cachedParentBranch := branchManager.GetBranch(parentBranchId) + cachedParentBranch := branchManager.Branch(parentBranchID) // abort if the parent branch could not be founds (should never happen) parentBranch := cachedParentBranch.Unwrap() if parentBranch == nil { cachedParentBranch.Release() - return fmt.Errorf("failed to unwrap branch '%s'", parentBranchId) + return fmt.Errorf("failed to unwrap branch '%s'", parentBranchID) } // store parent branch in result - ancestorBranches[parentBranchId] = cachedParentBranch + ancestorBranches[parentBranchID] = cachedParentBranch // queue parents for additional check (recursion) - for _, parentRealityId := range parentBranch.ParentBranches() { - stack.PushBack(parentRealityId) + for _, parentRealityID := range parentBranch.ParentBranches() { + stack.PushBack(parentRealityID) } return nil diff --git a/dapps/valuetransfers/packages/branchmanager/child_branch.go b/dapps/valuetransfers/packages/branchmanager/child_branch.go index a434262821045a79830cd8d252bf30cc4c7023dd..4b6e4013d90b5a85cf20b99921219f6152f241b2 100644 --- a/dapps/valuetransfers/packages/branchmanager/child_branch.go +++ b/dapps/valuetransfers/packages/branchmanager/child_branch.go @@ -5,21 +5,26 @@ import ( "github.com/iotaledger/hive.go/objectstorage" ) +// ChildBranch represents the relationship between a Branch and its children. Since a Branch can have a potentially +// unbounded amount of child Branches, we store this as a separate k/v pair instead of a marshaled list of children +// inside the Branch. type ChildBranch struct { objectstorage.StorableObjectFlags - parentId BranchId - id BranchId + parentID BranchID + childID BranchID } -func NewChildBranch(parentId BranchId, id BranchId) *ChildBranch { +// NewChildBranch is the constructor of the ChildBranch reference. +func NewChildBranch(parentID BranchID, childID BranchID) *ChildBranch { return &ChildBranch{ - parentId: parentId, - id: id, + parentID: parentID, + childID: childID, } } -func ChildBranchFromBytes(bytes []byte, optionalTargetObject ...*ChildBranch) (result *ChildBranch, err error, consumedBytes int) { +// ChildBranchFromBytes unmarshals a ChildBranch from a sequence of bytes. +func ChildBranchFromBytes(bytes []byte, optionalTargetObject ...*ChildBranch) (result *ChildBranch, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseChildBranch(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -27,7 +32,9 @@ func ChildBranchFromBytes(bytes []byte, optionalTargetObject ...*ChildBranch) (r return } -func ChildBranchFromStorageKey(key []byte, optionalTargetObject ...*ChildBranch) (result *ChildBranch, err error, consumedBytes int) { +// ChildBranchFromStorageKey is a factory method that creates a new ChildBranch instance from a storage key of the +// objectstorage. It is used by the objectstorage, to create new instances of this entity. +func ChildBranchFromStorageKey(key []byte, optionalTargetObject ...*ChildBranch) (result *ChildBranch, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -40,10 +47,10 @@ func ChildBranchFromStorageKey(key []byte, optionalTargetObject ...*ChildBranch) // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if result.parentId, err = ParseBranchId(marshalUtil); err != nil { + if result.parentID, err = ParseBranchID(marshalUtil); err != nil { return } - if result.id, err = ParseBranchId(marshalUtil); err != nil { + if result.childID, err = ParseBranchID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() @@ -51,19 +58,21 @@ func ChildBranchFromStorageKey(key []byte, optionalTargetObject ...*ChildBranch) return } +// ParseChildBranch unmarshals a ChildBranch using the given marshalUtil (for easier marshaling/unmarshaling). func ParseChildBranch(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*ChildBranch) (result *ChildBranch, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ChildBranchFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*ChildBranch) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*ChildBranch) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -73,63 +82,83 @@ func ParseChildBranch(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject return } -func (childBranch *ChildBranch) ParentId() BranchId { - return childBranch.parentId +// ParentID returns the ID of the Branch that plays the role of the parent in this relationship. +func (childBranch *ChildBranch) ParentID() BranchID { + return childBranch.parentID } -func (childBranch *ChildBranch) Id() BranchId { - return childBranch.id +// ChildID returns the ID of the Branch that plays the role of the child in this relationship. +func (childBranch *ChildBranch) ChildID() BranchID { + return childBranch.childID } +// ObjectStorageKey returns the bytes that are used a key when storing the Branch in an objectstorage. func (childBranch ChildBranch) ObjectStorageKey() []byte { - return marshalutil.New(ConflictIdLength + BranchIdLength). - WriteBytes(childBranch.parentId.Bytes()). - WriteBytes(childBranch.id.Bytes()). + return marshalutil.New(ConflictIDLength + BranchIDLength). + WriteBytes(childBranch.parentID.Bytes()). + WriteBytes(childBranch.childID.Bytes()). Bytes() } +// ObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a marshaled +// ChildBranch. func (childBranch ChildBranch) ObjectStorageValue() []byte { return nil } -func (childBranch ChildBranch) UnmarshalObjectStorageValue([]byte) (err error, consumedBytes int) { +// UnmarshalObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a +// marshaled Branch. +func (childBranch ChildBranch) UnmarshalObjectStorageValue([]byte) (consumedBytes int, err error) { return } -func (childBranch ChildBranch) Update(other objectstorage.StorableObject) { +// Update is disabled but needs to be implemented to be compatible with the objectstorage. +func (childBranch ChildBranch) Update(objectstorage.StorableObject) { panic("updates are disabled - use the setters") } var _ objectstorage.StorableObject = &ChildBranch{} +// CachedChildBranch is a wrapper for the generic CachedObject returned by the objectstorage that overrides the +// accessor methods, with a type-casted one. type CachedChildBranch struct { objectstorage.CachedObject } +// Retain marks this CachedObject to still be in use by the program. func (cachedChildBranch *CachedChildBranch) Retain() *CachedChildBranch { return &CachedChildBranch{cachedChildBranch.CachedObject.Retain()} } +// Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. func (cachedChildBranch *CachedChildBranch) Unwrap() *ChildBranch { - if untypedObject := cachedChildBranch.Get(); untypedObject == nil { + untypedObject := cachedChildBranch.Get() + if untypedObject == nil { return nil - } else { - if typedObject := untypedObject.(*ChildBranch); typedObject == nil || typedObject.IsDeleted() { - return nil - } else { - return typedObject - } } + + typedObject := untypedObject.(*ChildBranch) + if typedObject == nil || typedObject.IsDeleted() { + return nil + } + + return typedObject } +// Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it +// exists). It automatically releases the object when the consumer finishes. func (cachedChildBranch *CachedChildBranch) Consume(consumer func(childBranch *ChildBranch), forceRelease ...bool) (consumed bool) { return cachedChildBranch.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*ChildBranch)) }, forceRelease...) } +// CachedChildBranches represents a collection of CachedChildBranches. type CachedChildBranches []*CachedChildBranch +// Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object +// is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at +// least one object was consumed. func (cachedChildBranches CachedChildBranches) Consume(consumer func(childBranch *ChildBranch)) (consumed bool) { for _, cachedChildBranch := range cachedChildBranches { consumed = cachedChildBranch.Consume(func(output *ChildBranch) { @@ -140,6 +169,7 @@ func (cachedChildBranches CachedChildBranches) Consume(consumer func(childBranch return } +// Release is a utility function that allows us to release all CachedObjects in the collection. func (cachedChildBranches CachedChildBranches) Release(force ...bool) { for _, cachedChildBranch := range cachedChildBranches { cachedChildBranch.Release(force...) diff --git a/dapps/valuetransfers/packages/branchmanager/conflict.go b/dapps/valuetransfers/packages/branchmanager/conflict.go index e7d4f0e52dbc5cfdb4de977a0124ebcf5c4bfccf..1d08a55b3b45071c2513a83e6837c9bb4d05bd46 100644 --- a/dapps/valuetransfers/packages/branchmanager/conflict.go +++ b/dapps/valuetransfers/packages/branchmanager/conflict.go @@ -8,25 +8,29 @@ import ( "github.com/iotaledger/hive.go/stringify" ) +// Conflict represents a type Conflict struct { objectstorage.StorableObjectFlags - id ConflictId + id ConflictID memberCount uint32 memberCountMutex sync.RWMutex } -func NewConflict(id ConflictId) *Conflict { +// NewConflict is the constructor for new Conflicts. +func NewConflict(id ConflictID) *Conflict { return &Conflict{ id: id, } } -func (conflict *Conflict) Id() ConflictId { +// ID returns the identifier of this Conflict. +func (conflict *Conflict) ID() ConflictID { return conflict.id } +// MemberCount returns the amount of Branches that are part of this Conflict. func (conflict *Conflict) MemberCount() int { conflict.memberCountMutex.RLock() defer conflict.memberCountMutex.RLock() @@ -34,6 +38,7 @@ func (conflict *Conflict) MemberCount() int { return int(conflict.memberCount) } +// IncreaseMemberCount offers a thread safe way to increase the MemberCount property. func (conflict *Conflict) IncreaseMemberCount(optionalDelta ...int) (newMemberCount int) { delta := uint32(1) if len(optionalDelta) >= 1 { @@ -50,6 +55,7 @@ func (conflict *Conflict) IncreaseMemberCount(optionalDelta ...int) (newMemberCo return } +// DecreaseMemberCount offers a thread safe way to decrease the MemberCount property. func (conflict *Conflict) DecreaseMemberCount(optionalDelta ...int) (newMemberCount int) { delta := uint32(1) if len(optionalDelta) >= 1 { @@ -66,6 +72,7 @@ func (conflict *Conflict) DecreaseMemberCount(optionalDelta ...int) (newMemberCo return } +// Bytes returns a marshaled version of this Conflict. func (conflict *Conflict) Bytes() []byte { return marshalutil.New(). WriteBytes(conflict.ObjectStorageKey()). @@ -73,6 +80,7 @@ func (conflict *Conflict) Bytes() []byte { Bytes() } +// String returns a human readable version of this Conflict (for debug purposes). func (conflict *Conflict) String() string { return stringify.Struct("Conflict", stringify.StructField("id", conflict.id), @@ -80,17 +88,21 @@ func (conflict *Conflict) String() string { ) } +// ObjectStorageKey returns the bytes that are used a key when storing the Branch in an objectstorage. func (conflict *Conflict) ObjectStorageKey() []byte { return conflict.id.Bytes() } +// ObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a marshaled +// Branch. func (conflict *Conflict) ObjectStorageValue() []byte { return marshalutil.New(marshalutil.UINT32_SIZE). WriteUint32(conflict.memberCount). Bytes() } -func (conflict *Conflict) UnmarshalObjectStorageValue(valueBytes []byte) (err error, consumedBytes int) { +// UnmarshalObjectStorageValue unmarshals the bytes that are stored in the value of the objectstorage. +func (conflict *Conflict) UnmarshalObjectStorageValue(valueBytes []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(valueBytes) conflict.memberCount, err = marshalUtil.ReadUint32() if err != nil { @@ -101,32 +113,41 @@ func (conflict *Conflict) UnmarshalObjectStorageValue(valueBytes []byte) (err er return } +// Update is disabled but needs to be implemented to be compatible with the objectstorage. func (conflict *Conflict) Update(other objectstorage.StorableObject) { panic("updates are disabled - use the setters") } var _ objectstorage.StorableObject = &Conflict{} +// CachedConflict is a wrapper for the generic CachedObject returned by the objectstorage, that overrides the accessor +// methods, with a type-casted one. type CachedConflict struct { objectstorage.CachedObject } +// Retain marks this CachedObject to still be in use by the program. func (cachedConflict *CachedConflict) Retain() *CachedConflict { return &CachedConflict{cachedConflict.CachedObject.Retain()} } +// Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. func (cachedConflict *CachedConflict) Unwrap() *Conflict { - if untypedObject := cachedConflict.Get(); untypedObject == nil { + untypedObject := cachedConflict.Get() + if untypedObject == nil { return nil - } else { - if typedObject := untypedObject.(*Conflict); typedObject == nil || typedObject.IsDeleted() { - return nil - } else { - return typedObject - } } + + typedObject := untypedObject.(*Conflict) + if typedObject == nil || typedObject.IsDeleted() { + return nil + } + + return typedObject } +// Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it +// exists). It automatically releases the object when the consumer finishes. func (cachedConflict *CachedConflict) Consume(consumer func(branch *Conflict), forceRelease ...bool) (consumed bool) { return cachedConflict.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*Conflict)) diff --git a/dapps/valuetransfers/packages/branchmanager/conflict_id.go b/dapps/valuetransfers/packages/branchmanager/conflict_id.go index afbb3f58a06540583c2e73d06820d76aa9cb0e5e..5b5db0da3d45a5e5fb99543f6543d86acc1251c1 100644 --- a/dapps/valuetransfers/packages/branchmanager/conflict_id.go +++ b/dapps/valuetransfers/packages/branchmanager/conflict_id.go @@ -4,11 +4,18 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" ) -type ConflictId = transaction.OutputId +// ConflictID represents an identifier of a Conflict. Since conflicts, are created by multiple transactions spending the +// same Output, the ConflictID is simply an alias for the conflicting OutputID. +type ConflictID = transaction.OutputID var ( - ParseConflictId = transaction.ParseOutputId - ConflictIdFromBytes = transaction.OutputIdFromBytes + // ParseConflictID is a wrapper for simplified unmarshaling of Ids from a byte stream using the marshalUtil package. + ParseConflictID = transaction.ParseOutputID + + // ConflictIDFromBytes unmarshals a ConflictID from a sequence of bytes. + ConflictIDFromBytes = transaction.OutputIDFromBytes ) -const ConflictIdLength = transaction.OutputIdLength +// ConflictIDLength encodes the length of a Conflict identifier - since Conflicts get created by transactions spending +// the same Output, it has the same length as an OutputID. +const ConflictIDLength = transaction.OutputIDLength diff --git a/dapps/valuetransfers/packages/branchmanager/conflict_member.go b/dapps/valuetransfers/packages/branchmanager/conflict_member.go index 61d78c2ef2f81f67434f4d17bc6b3339a88d793e..1938d92faeff3e12ed348e9ca8f39bf97763c603 100644 --- a/dapps/valuetransfers/packages/branchmanager/conflict_member.go +++ b/dapps/valuetransfers/packages/branchmanager/conflict_member.go @@ -5,21 +5,26 @@ import ( "github.com/iotaledger/hive.go/objectstorage" ) +// ConflictMember represents the relationship between a Conflict and its Branches. Since a Conflict can have a +// potentially unbounded amount of conflicting Consumers, we store this as a separate k/v pair instead of a marshaled +// ist of members inside the Branch. type ConflictMember struct { objectstorage.StorableObjectFlags - conflictId ConflictId - branchId BranchId + conflictID ConflictID + branchID BranchID } -func NewConflictMember(conflictId ConflictId, branchId BranchId) *ConflictMember { +// NewConflictMember is the constructor of the ConflictMember reference. +func NewConflictMember(conflictID ConflictID, branchID BranchID) *ConflictMember { return &ConflictMember{ - conflictId: conflictId, - branchId: branchId, + conflictID: conflictID, + branchID: branchID, } } -func ConflictMemberFromBytes(bytes []byte, optionalTargetObject ...*ConflictMember) (result *ConflictMember, err error, consumedBytes int) { +// ConflictMemberFromBytes unmarshals a ConflictMember from a sequence of bytes. +func ConflictMemberFromBytes(bytes []byte, optionalTargetObject ...*ConflictMember) (result *ConflictMember, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseConflictMember(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -27,7 +32,9 @@ func ConflictMemberFromBytes(bytes []byte, optionalTargetObject ...*ConflictMemb return } -func ConflictMemberFromStorageKey(key []byte, optionalTargetObject ...*ConflictMember) (result *ConflictMember, err error, consumedBytes int) { +// ConflictMemberFromStorageKey is a factory method that creates a new ConflictMember instance from a storage key of the +// objectstorage. It is used by the objectstorage, to create new instances of this entity. +func ConflictMemberFromStorageKey(key []byte, optionalTargetObject ...*ConflictMember) (result *ConflictMember, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -40,10 +47,10 @@ func ConflictMemberFromStorageKey(key []byte, optionalTargetObject ...*ConflictM // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if result.conflictId, err = ParseConflictId(marshalUtil); err != nil { + if result.conflictID, err = ParseConflictID(marshalUtil); err != nil { return } - if result.branchId, err = ParseBranchId(marshalUtil); err != nil { + if result.branchID, err = ParseBranchID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() @@ -51,19 +58,21 @@ func ConflictMemberFromStorageKey(key []byte, optionalTargetObject ...*ConflictM return } +// ParseConflictMember unmarshals a ConflictMember using the given marshalUtil (for easier marshaling/unmarshaling). func ParseConflictMember(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*ConflictMember) (result *ConflictMember, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ConflictMemberFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*ConflictMember) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*ConflictMember) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -73,63 +82,83 @@ func ParseConflictMember(marshalUtil *marshalutil.MarshalUtil, optionalTargetObj return } -func (conflictMember *ConflictMember) ConflictId() ConflictId { - return conflictMember.conflictId +// ConflictID returns the identifier of the Conflict that this conflictMember belongs to. +func (conflictMember *ConflictMember) ConflictID() ConflictID { + return conflictMember.conflictID } -func (conflictMember *ConflictMember) BranchId() BranchId { - return conflictMember.branchId +// BranchID returns the identifier of the Branch that this conflictMember references. +func (conflictMember *ConflictMember) BranchID() BranchID { + return conflictMember.branchID } +// ObjectStorageKey returns the bytes that are used a key when storing the Branch in an objectstorage. func (conflictMember ConflictMember) ObjectStorageKey() []byte { - return marshalutil.New(ConflictIdLength + BranchIdLength). - WriteBytes(conflictMember.conflictId.Bytes()). - WriteBytes(conflictMember.branchId.Bytes()). + return marshalutil.New(ConflictIDLength + BranchIDLength). + WriteBytes(conflictMember.conflictID.Bytes()). + WriteBytes(conflictMember.branchID.Bytes()). Bytes() } +// ObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a marshaled +// ConflictMember. func (conflictMember ConflictMember) ObjectStorageValue() []byte { return nil } -func (conflictMember ConflictMember) UnmarshalObjectStorageValue([]byte) (err error, consumedBytes int) { +// UnmarshalObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a +// marshaled Branch. +func (conflictMember ConflictMember) UnmarshalObjectStorageValue([]byte) (consumedBytes int, err error) { return } +// Update is disabled but needs to be implemented to be compatible with the objectstorage. func (conflictMember ConflictMember) Update(other objectstorage.StorableObject) { panic("updates are disabled - use the setters") } var _ objectstorage.StorableObject = &ConflictMember{} +// CachedConflictMember is a wrapper for the generic CachedObject returned by the objectstorage that overrides the +// accessor methods, with a type-casted one. type CachedConflictMember struct { objectstorage.CachedObject } +// Retain marks this CachedObject to still be in use by the program. func (cachedConflictMember *CachedConflictMember) Retain() *CachedConflictMember { return &CachedConflictMember{cachedConflictMember.CachedObject.Retain()} } +// Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. func (cachedConflictMember *CachedConflictMember) Unwrap() *ConflictMember { - if untypedObject := cachedConflictMember.Get(); untypedObject == nil { + untypedObject := cachedConflictMember.Get() + if untypedObject == nil { return nil - } else { - if typedObject := untypedObject.(*ConflictMember); typedObject == nil || typedObject.IsDeleted() { - return nil - } else { - return typedObject - } } + + typedObject := untypedObject.(*ConflictMember) + if typedObject == nil || typedObject.IsDeleted() { + return nil + } + + return typedObject } +// Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it +// exists). It automatically releases the object when the consumer finishes. func (cachedConflictMember *CachedConflictMember) Consume(consumer func(conflictMember *ConflictMember), forceRelease ...bool) (consumed bool) { return cachedConflictMember.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*ConflictMember)) }, forceRelease...) } +// CachedConflictMembers represents a collection of CachedConflictMembers. type CachedConflictMembers []*CachedConflictMember +// Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object +// is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at +// least one object was consumed. func (cachedConflictMembers CachedConflictMembers) Consume(consumer func(conflictMember *ConflictMember)) (consumed bool) { for _, cachedConflictMember := range cachedConflictMembers { consumed = cachedConflictMember.Consume(func(output *ConflictMember) { @@ -140,6 +169,7 @@ func (cachedConflictMembers CachedConflictMembers) Consume(consumer func(conflic return } +// Release is a utility function that allows us to release all CachedObjects in the collection. func (cachedConflictMembers CachedConflictMembers) Release(force ...bool) { for _, cachedConflictMember := range cachedConflictMembers { cachedConflictMember.Release(force...) diff --git a/dapps/valuetransfers/packages/branchmanager/events.go b/dapps/valuetransfers/packages/branchmanager/events.go index b74fd4820de37c3af57d1ed2b80a5c493034e0a8..7f2cc58e189a861721b648dfa4bd9856ca89064d 100644 --- a/dapps/valuetransfers/packages/branchmanager/events.go +++ b/dapps/valuetransfers/packages/branchmanager/events.go @@ -4,9 +4,17 @@ import ( "github.com/iotaledger/hive.go/events" ) +// Events is a container for the different kind of events of the BranchManager. type Events struct { - BranchPreferred *events.Event + // BranchPreferred gets triggered whenever a Branch becomes preferred that was not preferred before. + BranchPreferred *events.Event + + // BranchUnpreferred gets triggered whenever a Branch becomes unpreferred that was preferred before. BranchUnpreferred *events.Event - BranchLiked *events.Event - BranchDisliked *events.Event + + // BranchLiked gets triggered whenever a Branch becomes liked that was not liked before. + BranchLiked *events.Event + + // BranchLiked gets triggered whenever a Branch becomes preferred that was not preferred before. + BranchDisliked *events.Event } diff --git a/dapps/valuetransfers/packages/branchmanager/objectstorage.go b/dapps/valuetransfers/packages/branchmanager/objectstorage.go index af513752ea8601a9c6f3d0a6cc575dc4adcd981d..dc341e1316a0b01c30e2c8dee0b6543db07e658e 100644 --- a/dapps/valuetransfers/packages/branchmanager/objectstorage.go +++ b/dapps/valuetransfers/packages/branchmanager/objectstorage.go @@ -26,6 +26,6 @@ var ( } ) -func osBranchFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osBranchFactory(key []byte) (objectstorage.StorableObject, int, error) { return BranchFromStorageKey(key) } diff --git a/dapps/valuetransfers/packages/ledgerstate/ledgerstate.go b/dapps/valuetransfers/packages/ledgerstate/ledgerstate.go index 76bc1c0a318f18f6b95756b61b63e48d1367ce35..5cb09096b181e83d1f30aee9b242c0db714fd75f 100644 --- a/dapps/valuetransfers/packages/ledgerstate/ledgerstate.go +++ b/dapps/valuetransfers/packages/ledgerstate/ledgerstate.go @@ -4,10 +4,13 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/utxodag" ) +// LedgerState represents a struct, that allows us to read the balances from the UTXODAG by filtering the existing +// unspent Outputs depending on the liked branches. type LedgerState struct { utxoDAG *utxodag.UTXODAG } +// New is the constructor of the LedgerState. It creates a new instance with the given UTXODAG. func New(utxoDAG *utxodag.UTXODAG) *LedgerState { return &LedgerState{ utxoDAG: utxoDAG, diff --git a/dapps/valuetransfers/packages/payload/id.go b/dapps/valuetransfers/packages/payload/id.go index 43241a6c059da3ad23a2b68712f709ad87bfa21f..7b901ff92440e97dad81b5790e4c37edc98720fb 100644 --- a/dapps/valuetransfers/packages/payload/id.go +++ b/dapps/valuetransfers/packages/payload/id.go @@ -8,17 +8,17 @@ import ( "github.com/mr-tron/base58" ) -// Id represents the hash of a payload that is used to identify the given payload. -type Id [IdLength]byte +// ID represents the hash of a payload that is used to identify the given payload. +type ID [IDLength]byte -// NewId creates a payload id from a base58 encoded string. -func NewId(base58EncodedString string) (result Id, err error) { +// NewID creates a payload id from a base58 encoded string. +func NewID(base58EncodedString string) (result ID, err error) { bytes, err := base58.Decode(base58EncodedString) if err != nil { return } - if len(bytes) != IdLength { + if len(bytes) != IDLength { err = fmt.Errorf("length of base58 formatted payload id is wrong") return @@ -29,34 +29,35 @@ func NewId(base58EncodedString string) (result Id, err error) { 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 +// ParseID is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. +func ParseID(marshalUtil *marshalutil.MarshalUtil) (ID, error) { + id, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return IDFromBytes(data) }) + if err != nil { + return ID{}, err } + + return id.(ID), nil } -// IdFromBytes unmarshals a payload id from a sequence of bytes. +// IDFromBytes 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 IdFromBytes(bytes []byte, optionalTargetObject ...*Id) (result Id, err error, consumedBytes int) { +func IDFromBytes(bytes []byte, optionalTargetObject ...*ID) (result ID, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information - var targetObject *Id + var targetObject *ID switch len(optionalTargetObject) { case 0: targetObject = &result case 1: targetObject = optionalTargetObject[0] default: - panic("too many arguments in call to IdFromBytes") + panic("too many arguments in call to IDFromBytes") } // initialize helper marshalUtil := marshalutil.New(bytes) // read id from bytes - idBytes, err := marshalUtil.ReadBytes(IdLength) + idBytes, err := marshalUtil.ReadBytes(IDLength) if err != nil { return } @@ -71,10 +72,10 @@ func IdFromBytes(bytes []byte, optionalTargetObject ...*Id) (result Id, err erro return } -// Random creates a random id which can for example be used in unit tests. -func RandomId() (id Id) { +// RandomID creates a random payload id which can for example be used in unit tests. +func RandomID() (id ID) { // generate a random sequence of bytes - idBytes := make([]byte, IdLength) + idBytes := make([]byte, IDLength) if _, err := rand.Read(idBytes); err != nil { panic(err) } @@ -86,16 +87,17 @@ func RandomId() (id Id) { } // String returns a base58 encoded version of the payload id. -func (id Id) String() string { +func (id ID) String() string { return base58.Encode(id[:]) } -func (id Id) Bytes() []byte { +// Bytes returns a marshaled version of this ID. +func (id ID) Bytes() []byte { return id[:] } -// Empty represents the id encoding the genesis. -var GenesisId Id +// GenesisID contains the zero value of this ID which represents the genesis. +var GenesisID ID -// IdLength defined the amount of bytes in a payload id (32 bytes hash value). -const IdLength = 32 +// IDLength defined the amount of bytes in a payload id (32 bytes hash value). +const IDLength = 32 diff --git a/dapps/valuetransfers/packages/payload/id_test.go b/dapps/valuetransfers/packages/payload/id_test.go index 22ff3b66bd5c0cdafb153e354453473c52d5281b..3a3558c293462833d5868ba66f6e1aa25f6d63fa 100644 --- a/dapps/valuetransfers/packages/payload/id_test.go +++ b/dapps/valuetransfers/packages/payload/id_test.go @@ -8,19 +8,19 @@ import ( func Test(t *testing.T) { // create variable for id - sourceId, err := NewId("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") + sourceID, err := NewID("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") if err != nil { panic(err) } // read serialized id into both variables - var restoredIdPointer Id - restoredIdValue, err, _ := IdFromBytes(sourceId.Bytes(), &restoredIdPointer) + var restoredIDPointer ID + restoredIDValue, _, err := IDFromBytes(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) + assert.Equal(t, sourceID, restoredIDValue) + assert.Equal(t, sourceID, restoredIDPointer) } diff --git a/dapps/valuetransfers/packages/payload/payload.go b/dapps/valuetransfers/packages/payload/payload.go index 3aadd4af0eb03c581d184f30582a76c856920697..d9ed9664ab73173a5d160625cecf7d72f54b3743 100644 --- a/dapps/valuetransfers/packages/payload/payload.go +++ b/dapps/valuetransfers/packages/payload/payload.go @@ -12,30 +12,33 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/messagelayer/payload" ) +// Payload represents the entity that forms the Tangle by referencing other Payloads using their trunk and branch. +// A Payload contains a transaction and defines, where in the Tangle a transaction is attached. type Payload struct { objectstorage.StorableObjectFlags - id *Id + id *ID idMutex sync.RWMutex - trunkPayloadId Id - branchPayloadId Id + trunkPayloadID ID + branchPayloadID ID transaction *transaction.Transaction bytes []byte bytesMutex sync.RWMutex } -func New(trunkPayloadId, branchPayloadId Id, valueTransfer *transaction.Transaction) *Payload { +// New is the constructor of a Payload and creates a new Payload object from the given details. +func New(trunkPayloadID, branchPayloadID ID, valueTransfer *transaction.Transaction) *Payload { return &Payload{ - trunkPayloadId: trunkPayloadId, - branchPayloadId: branchPayloadId, + trunkPayloadID: trunkPayloadID, + branchPayloadID: branchPayloadID, transaction: valueTransfer, } } // 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) { +func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = Parse(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -43,7 +46,9 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, return } -func FromStorageKey(key []byte, optionalTargetObject ...*Payload) (result *Payload, err error, consumedBytes int) { +// FromStorageKey is a factory method that creates a new Payload instance from a storage key of the objectstorage. +// It is used by the objectstorage, to create new instances of this entity. +func FromStorageKey(key []byte, optionalTargetObject ...*Payload) (result *Payload, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -56,18 +61,19 @@ func FromStorageKey(key []byte, optionalTargetObject ...*Payload) (result *Paylo // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if payloadId, idErr := ParseId(marshalUtil); idErr != nil { + payloadID, idErr := ParseID(marshalUtil) + if idErr != nil { err = idErr return - } else { - result.id = &payloadId } + result.id = &payloadID consumedBytes = marshalUtil.ReadOffset() return } +// Parse unmarshals a Payload using the given marshalUtil (for easier marshaling/unmarshaling). func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Payload) (result *Payload, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { @@ -79,8 +85,8 @@ func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Payloa panic("too many arguments in call to Parse") } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -90,7 +96,8 @@ func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Payloa return } -func (payload *Payload) Id() Id { +// ID returns the identifier if the Payload. +func (payload *Payload) ID() ID { // acquire lock for reading id payload.idMutex.RLock() @@ -112,50 +119,58 @@ func (payload *Payload) Id() Id { } // otherwise calculate the id - marshalUtil := marshalutil.New(IdLength + IdLength + transaction.IdLength) - marshalUtil.WriteBytes(payload.trunkPayloadId.Bytes()) - marshalUtil.WriteBytes(payload.branchPayloadId.Bytes()) - marshalUtil.WriteBytes(payload.Transaction().Id().Bytes()) + marshalUtil := marshalutil.New(IDLength + IDLength + transaction.IDLength) + marshalUtil.WriteBytes(payload.trunkPayloadID.Bytes()) + marshalUtil.WriteBytes(payload.branchPayloadID.Bytes()) + marshalUtil.WriteBytes(payload.Transaction().ID().Bytes()) - var id Id = blake2b.Sum256(marshalUtil.Bytes()) + var id ID = blake2b.Sum256(marshalUtil.Bytes()) payload.id = &id return id } -func (payload *Payload) TrunkId() Id { - return payload.trunkPayloadId +// TrunkID returns the first Payload that is referenced by this Payload. +func (payload *Payload) TrunkID() ID { + return payload.trunkPayloadID } -func (payload *Payload) BranchId() Id { - return payload.branchPayloadId +// BranchID returns the second Payload that is referenced by this Payload. +func (payload *Payload) BranchID() ID { + return payload.branchPayloadID } +// Transaction returns the Transaction that is being attached in this Payload. func (payload *Payload) Transaction() *transaction.Transaction { return payload.transaction } +// Bytes returns a marshaled version of this Payload. func (payload *Payload) Bytes() []byte { return payload.ObjectStorageValue() } func (payload *Payload) String() string { return stringify.Struct("Payload", - stringify.StructField("id", payload.Id()), - stringify.StructField("trunk", payload.TrunkId()), - stringify.StructField("branch", payload.BranchId()), + stringify.StructField("id", payload.ID()), + stringify.StructField("trunk", payload.TrunkID()), + stringify.StructField("branch", payload.BranchID()), stringify.StructField("transfer", payload.Transaction()), ) } // region Payload implementation /////////////////////////////////////////////////////////////////////////////////////// -var Type = payload.Type(1) +// Type represents the identifier which addresses the value Payload type. +const Type = payload.Type(1) +// Type returns the type of the Payload. func (payload *Payload) Type() payload.Type { return Type } +// ObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a marshaled +// Branch. func (payload *Payload) ObjectStorageValue() (bytes []byte) { // acquire lock for reading bytes payload.bytesMutex.RLock() @@ -181,12 +196,12 @@ func (payload *Payload) ObjectStorageValue() (bytes []byte) { transferBytes := payload.Transaction().ObjectStorageValue() // marshal fields - payloadLength := IdLength + IdLength + len(transferBytes) + payloadLength := IDLength + IDLength + 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(payload.trunkPayloadID.Bytes()) + marshalUtil.WriteBytes(payload.branchPayloadID.Bytes()) marshalUtil.WriteBytes(transferBytes) bytes = marshalUtil.Bytes() @@ -196,7 +211,8 @@ func (payload *Payload) ObjectStorageValue() (bytes []byte) { return } -func (payload *Payload) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +// UnmarshalObjectStorageValue unmarshals the bytes that are stored in the value of the objectstorage. +func (payload *Payload) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) // read information that are required to identify the payload from the outside @@ -210,10 +226,10 @@ func (payload *Payload) UnmarshalObjectStorageValue(data []byte) (err error, con } // parse trunk payload id - if payload.trunkPayloadId, err = ParseId(marshalUtil); err != nil { + if payload.trunkPayloadID, err = ParseID(marshalUtil); err != nil { return } - if payload.branchPayloadId, err = ParseId(marshalUtil); err != nil { + if payload.branchPayloadID, err = ParseID(marshalUtil); err != nil { return } if payload.transaction, err = transaction.Parse(marshalUtil); err != nil { @@ -230,15 +246,16 @@ func (payload *Payload) UnmarshalObjectStorageValue(data []byte) (err error, con return } +// Unmarshal unmarshals a given slice of bytes and fills the object with the. func (payload *Payload) Unmarshal(data []byte) (err error) { - _, err, _ = FromBytes(data) + _, _, err = FromBytes(data, payload) return } func init() { payload.RegisterType(Type, func(data []byte) (payload payload.Payload, err error) { - payload, err, _ = FromBytes(data) + payload, _, err = FromBytes(data) return }) @@ -251,14 +268,12 @@ var _ payload.Payload = &Payload{} // region StorableObject implementation //////////////////////////////////////////////////////////////////////////////// -// ObjectStorageValue() (bytes []byte, err error) already implemented by Payload - -// UnmarshalObjectStorageValue(data []byte) (err error) already implemented by Payload - +// ObjectStorageKey returns the bytes that are used a key when storing the Branch in an objectstorage. func (payload *Payload) ObjectStorageKey() []byte { - return payload.Id().Bytes() + return payload.ID().Bytes() } +// Update is disabled but needs to be implemented to be compatible with the objectstorage. func (payload *Payload) Update(other objectstorage.StorableObject) { panic("a Payload should never be updated") } @@ -291,13 +306,15 @@ func (cachedPayload *CachedPayload) Consume(consumer func(payload *Payload)) boo // Unwrap provides a way to "Get" a type casted version of the underlying object. func (cachedPayload *CachedPayload) Unwrap() *Payload { - if untypedTransaction := cachedPayload.Get(); untypedTransaction == nil { + untypedTransaction := cachedPayload.Get() + if untypedTransaction == nil { + return nil + } + + typeCastedTransaction := untypedTransaction.(*Payload) + if typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { return nil - } else { - if typeCastedTransaction := untypedTransaction.(*Payload); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } } + + return typeCastedTransaction } diff --git a/dapps/valuetransfers/packages/payload/payload_test.go b/dapps/valuetransfers/packages/payload/payload_test.go index cee322a98765e86d064b43a161c69316f4956f34..fbc7c9690fc8fb0142a268bafcbaebf5fd4705b6 100644 --- a/dapps/valuetransfers/packages/payload/payload_test.go +++ b/dapps/valuetransfers/packages/payload/payload_test.go @@ -21,8 +21,8 @@ func ExamplePayload() { valueTransfer := transaction.New( // inputs transaction.NewInputs( - transaction.NewOutputId(address.Random(), transaction.RandomId()), - transaction.NewOutputId(address.Random(), transaction.RandomId()), + transaction.NewOutputID(address.Random(), transaction.RandomID()), + transaction.NewOutputID(address.Random(), transaction.RandomID()), ), // outputs @@ -36,10 +36,10 @@ func ExamplePayload() { // 2. create value payload (the ontology creates this and wraps the user provided transfer accordingly) valuePayload := New( // trunk in "value transfer ontology" (filled by ontology tipSelector) - GenesisId, + GenesisID, // branch in "value transfer ontology" (filled by ontology tipSelector) - GenesisId, + GenesisID, // value transfer valueTransfer, @@ -75,12 +75,12 @@ func TestPayload(t *testing.T) { addressKeyPair2 := ed25519.GenerateKeyPair() originalPayload := New( - GenesisId, - GenesisId, + GenesisID, + GenesisID, transaction.New( transaction.NewInputs( - transaction.NewOutputId(address.FromED25519PubKey(addressKeyPair1.PublicKey), transaction.RandomId()), - transaction.NewOutputId(address.FromED25519PubKey(addressKeyPair2.PublicKey), transaction.RandomId()), + transaction.NewOutputID(address.FromED25519PubKey(addressKeyPair1.PublicKey), transaction.RandomID()), + transaction.NewOutputID(address.FromED25519PubKey(addressKeyPair2.PublicKey), transaction.RandomID()), ), transaction.NewOutputs(map[address.Address][]*balance.Balance{ @@ -101,22 +101,22 @@ func TestPayload(t *testing.T) { assert.Equal(t, true, originalPayload.Transaction().SignaturesValid()) - clonedPayload1, err, _ := FromBytes(originalPayload.Bytes()) + clonedPayload1, _, err := FromBytes(originalPayload.Bytes()) if err != nil { panic(err) } - assert.Equal(t, originalPayload.BranchId(), clonedPayload1.BranchId()) - assert.Equal(t, originalPayload.TrunkId(), clonedPayload1.TrunkId()) + assert.Equal(t, originalPayload.BranchID(), clonedPayload1.BranchID()) + assert.Equal(t, originalPayload.TrunkID(), clonedPayload1.TrunkID()) assert.Equal(t, originalPayload.Transaction().Bytes(), clonedPayload1.Transaction().Bytes()) - assert.Equal(t, originalPayload.Id(), clonedPayload1.Id()) + assert.Equal(t, originalPayload.ID(), clonedPayload1.ID()) assert.Equal(t, true, clonedPayload1.Transaction().SignaturesValid()) - clonedPayload2, err, _ := FromBytes(clonedPayload1.Bytes()) + clonedPayload2, _, err := FromBytes(clonedPayload1.Bytes()) if err != nil { panic(err) } - assert.Equal(t, originalPayload.Id(), clonedPayload2.Id()) + assert.Equal(t, originalPayload.ID(), clonedPayload2.ID()) assert.Equal(t, true, clonedPayload2.Transaction().SignaturesValid()) } diff --git a/dapps/valuetransfers/packages/tangle/constants.go b/dapps/valuetransfers/packages/tangle/constants.go index 937b67282aaa2828313d58abb363c7844df4906b..f862156f666f8cfd48d39ff4ac5776bc44bc9faa 100644 --- a/dapps/valuetransfers/packages/tangle/constants.go +++ b/dapps/valuetransfers/packages/tangle/constants.go @@ -5,6 +5,10 @@ import ( ) const ( - MAX_MISSING_TIME_BEFORE_CLEANUP = 30 * time.Second - MISSING_CHECK_INTERVAL = 5 * time.Second + // MaxMissingTimeBeforeCleanup defines how long a transaction can be "missing", before we start pruning its future + // cone. + MaxMissingTimeBeforeCleanup = 30 * time.Second + + // MissingCheckInterval defines how often we check if missing transactions have been received. + MissingCheckInterval = 5 * time.Second ) diff --git a/dapps/valuetransfers/packages/tangle/events.go b/dapps/valuetransfers/packages/tangle/events.go index 1e37eb6c02fe2744c0479b4d0f215424637cd00c..a807d72805277840c7e428026d2434c985a67b8f 100644 --- a/dapps/valuetransfers/packages/tangle/events.go +++ b/dapps/valuetransfers/packages/tangle/events.go @@ -6,6 +6,7 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload" ) +// Events is a container for the different kind of events of the Tangle. type Events struct { // Get's called whenever a transaction PayloadAttached *events.Event @@ -20,13 +21,13 @@ func newEvents() *Events { PayloadAttached: events.NewEvent(cachedPayloadEvent), PayloadSolid: events.NewEvent(cachedPayloadEvent), MissingPayloadReceived: events.NewEvent(cachedPayloadEvent), - PayloadMissing: events.NewEvent(payloadIdEvent), - PayloadUnsolidifiable: events.NewEvent(payloadIdEvent), + PayloadMissing: events.NewEvent(payloadIDEvent), + PayloadUnsolidifiable: events.NewEvent(payloadIDEvent), } } -func payloadIdEvent(handler interface{}, params ...interface{}) { - handler.(func(payload.Id))(params[0].(payload.Id)) +func payloadIDEvent(handler interface{}, params ...interface{}) { + handler.(func(payload.ID))(params[0].(payload.ID)) } func cachedPayloadEvent(handler interface{}, params ...interface{}) { diff --git a/dapps/valuetransfers/packages/tangle/missingpayload.go b/dapps/valuetransfers/packages/tangle/missingpayload.go index 910d65783b0c4d37d8c92fa65159ea1bb1fc04e1..9c304b6f8460ec7f46e5089f960b0af4d9736c11 100644 --- a/dapps/valuetransfers/packages/tangle/missingpayload.go +++ b/dapps/valuetransfers/packages/tangle/missingpayload.go @@ -14,21 +14,21 @@ import ( type MissingPayload struct { objectstorage.StorableObjectFlags - payloadId payload.Id + payloadID payload.ID missingSince time.Time } // NewMissingPayload creates an entry for a missing value transfer payload. -func NewMissingPayload(payloadId payload.Id) *MissingPayload { +func NewMissingPayload(payloadID payload.ID) *MissingPayload { return &MissingPayload{ - payloadId: payloadId, + payloadID: payloadID, missingSince: time.Now(), } } // MissingPayloadFromBytes 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 MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) { +func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseMissingPayload(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -36,19 +36,21 @@ func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPaylo return } +// ParseMissingPayload unmarshals a MissingPayload using the given marshalUtil (for easier marshaling/unmarshaling). func ParseMissingPayload(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return MissingPayloadFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*MissingPayload) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*MissingPayload) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -60,7 +62,7 @@ func ParseMissingPayload(marshalUtil *marshalutil.MarshalUtil, optionalTargetObj // MissingPayloadFromStorageKey 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.ObjectStorageValue interface. -func MissingPayloadFromStorageKey(key []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) { +func MissingPayloadFromStorageKey(key []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -73,7 +75,7 @@ func MissingPayloadFromStorageKey(key []byte, optionalTargetObject ...*MissingPa // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if result.payloadId, err = payload.ParseId(marshalUtil); err != nil { + if result.payloadID, err = payload.ParseID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() @@ -81,19 +83,19 @@ func MissingPayloadFromStorageKey(key []byte, optionalTargetObject ...*MissingPa return } -// GetId returns the payload id, that is missing. -func (missingPayload *MissingPayload) GetId() payload.Id { - return missingPayload.payloadId +// ID returns the payload id, that is missing. +func (missingPayload *MissingPayload) ID() payload.ID { + return missingPayload.payloadID } // MissingSince returns the time.Time since the transaction was first reported as being missing. -func (missingPayload *MissingPayload) GetMissingSince() time.Time { +func (missingPayload *MissingPayload) MissingSince() time.Time { return missingPayload.missingSince } // Bytes marshals the missing payload into a sequence of bytes. func (missingPayload *MissingPayload) Bytes() []byte { - return marshalutil.New(payload.IdLength + marshalutil.TIME_SIZE). + return marshalutil.New(payload.IDLength + marshalutil.TIME_SIZE). WriteBytes(missingPayload.ObjectStorageKey()). WriteBytes(missingPayload.ObjectStorageValue()). Bytes() @@ -108,7 +110,7 @@ func (missingPayload *MissingPayload) Update(other objectstorage.StorableObject) // ObjectStorageKey returns the key that is used to store the object in the database. // It is required to match StorableObject interface. func (missingPayload *MissingPayload) ObjectStorageKey() []byte { - return missingPayload.payloadId.Bytes() + return missingPayload.payloadID.Bytes() } // ObjectStorageValue is required to match the encoding.BinaryMarshaler interface. @@ -119,7 +121,7 @@ func (missingPayload *MissingPayload) ObjectStorageValue() (data []byte) { } // UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface. -func (missingPayload *MissingPayload) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (missingPayload *MissingPayload) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) if missingPayload.missingSince, err = marshalUtil.ReadTime(); err != nil { return diff --git a/dapps/valuetransfers/packages/tangle/objectstorage.go b/dapps/valuetransfers/packages/tangle/objectstorage.go index 7523a67bab754d713059454298b1c26d42ada530..4052ae56ac8e1035718e893096eca3cc3b53c4ff 100644 --- a/dapps/valuetransfers/packages/tangle/objectstorage.go +++ b/dapps/valuetransfers/packages/tangle/objectstorage.go @@ -17,18 +17,18 @@ const ( osApprover ) -func osPayloadFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osPayloadFactory(key []byte) (objectstorage.StorableObject, int, error) { return payload.FromStorageKey(key) } -func osPayloadMetadataFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osPayloadMetadataFactory(key []byte) (objectstorage.StorableObject, int, error) { return PayloadMetadataFromStorageKey(key) } -func osMissingPayloadFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osMissingPayloadFactory(key []byte) (objectstorage.StorableObject, int, error) { return MissingPayloadFromStorageKey(key) } -func osPayloadApproverFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osPayloadApproverFactory(key []byte) (objectstorage.StorableObject, int, error) { return PayloadApproverFromStorageKey(key) } diff --git a/dapps/valuetransfers/packages/tangle/payloadapprover.go b/dapps/valuetransfers/packages/tangle/payloadapprover.go index ca605a01051cb057bbdb74a89593b7f756d8a940..ea233d46e077d459a8fec8bc6b8b4b7e7d0a55f1 100644 --- a/dapps/valuetransfers/packages/tangle/payloadapprover.go +++ b/dapps/valuetransfers/packages/tangle/payloadapprover.go @@ -14,24 +14,25 @@ type PayloadApprover struct { objectstorage.StorableObjectFlags storageKey []byte - referencedPayloadId payload.Id - approvingPayloadId payload.Id + referencedPayloadID payload.ID + approvingPayloadID payload.ID } // NewPayloadApprover creates an approver object that encodes a single relation between an approved and an approving payload. -func NewPayloadApprover(referencedPayload payload.Id, approvingPayload payload.Id) *PayloadApprover { - marshalUtil := marshalutil.New(payload.IdLength + payload.IdLength) +func NewPayloadApprover(referencedPayload payload.ID, approvingPayload payload.ID) *PayloadApprover { + marshalUtil := marshalutil.New(payload.IDLength + payload.IDLength) marshalUtil.WriteBytes(referencedPayload.Bytes()) marshalUtil.WriteBytes(approvingPayload.Bytes()) return &PayloadApprover{ - referencedPayloadId: referencedPayload, - approvingPayloadId: approvingPayload, + referencedPayloadID: referencedPayload, + approvingPayloadID: approvingPayload, storageKey: marshalUtil.Bytes(), } } -func PayloadApproverFromBytes(bytes []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error, consumedBytes int) { +// PayloadApproverFromBytes unmarshals a PayloadApprover from a sequence of bytes. +func PayloadApproverFromBytes(bytes []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParsePayloadApprover(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -39,19 +40,21 @@ func PayloadApproverFromBytes(bytes []byte, optionalTargetObject ...*PayloadAppr return } +// ParsePayloadApprover unmarshals a PayloadApprover using the given marshalUtil (for easier marshaling/unmarshaling). func ParsePayloadApprover(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return PayloadApproverFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*PayloadApprover) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*PayloadApprover) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -64,7 +67,7 @@ func ParsePayloadApprover(marshalUtil *marshalutil.MarshalUtil, optionalTargetOb // PayloadApproverFromStorageKey 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 UnmarshalObjectStorageValue // method. -func PayloadApproverFromStorageKey(key []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error, consumedBytes int) { +func PayloadApproverFromStorageKey(key []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -77,10 +80,10 @@ func PayloadApproverFromStorageKey(key []byte, optionalTargetObject ...*PayloadA // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if result.referencedPayloadId, err = payload.ParseId(marshalUtil); err != nil { + if result.referencedPayloadID, err = payload.ParseID(marshalUtil); err != nil { return } - if result.approvingPayloadId, err = payload.ParseId(marshalUtil); err != nil { + if result.approvingPayloadID, err = payload.ParseID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() @@ -89,9 +92,9 @@ func PayloadApproverFromStorageKey(key []byte, optionalTargetObject ...*PayloadA return } -// GetApprovingPayloadId returns the id of the approving payload. -func (payloadApprover *PayloadApprover) GetApprovingPayloadId() payload.Id { - return payloadApprover.approvingPayloadId +// ApprovingPayloadID returns the identifier of the approving payload. +func (payloadApprover *PayloadApprover) ApprovingPayloadID() payload.ID { + return payloadApprover.approvingPayloadID } // ObjectStorageKey returns the key that is used to store the object in the database. @@ -108,7 +111,7 @@ func (payloadApprover *PayloadApprover) ObjectStorageValue() (data []byte) { // UnmarshalObjectStorageValue 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 (payloadApprover *PayloadApprover) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (payloadApprover *PayloadApprover) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { return } @@ -141,19 +144,25 @@ func (cachedPayloadApprover *CachedPayloadApprover) Consume(consumer func(payloa // Unwrap provides a way to "Get" a type casted version of the underlying object. func (cachedPayloadApprover *CachedPayloadApprover) Unwrap() *PayloadApprover { - if untypedTransaction := cachedPayloadApprover.Get(); untypedTransaction == nil { + untypedTransaction := cachedPayloadApprover.Get() + if untypedTransaction == nil { + return nil + } + + typeCastedTransaction := untypedTransaction.(*PayloadApprover) + if typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { return nil - } else { - if typeCastedTransaction := untypedTransaction.(*PayloadApprover); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } } + + return typeCastedTransaction } +// CachedApprovers represents a collection of CachedPayloadApprover. type CachedApprovers []*CachedPayloadApprover +// Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object +// is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at +// least one object was consumed. func (cachedApprovers CachedApprovers) Consume(consumer func(approver *PayloadApprover)) (consumed bool) { for _, cachedApprover := range cachedApprovers { consumed = cachedApprover.Consume(consumer) || consumed diff --git a/dapps/valuetransfers/packages/tangle/payloadmetadata.go b/dapps/valuetransfers/packages/tangle/payloadmetadata.go index 3501c74a26ab9c45a451d78e6ef7a4a2c03c98ef..3fd3d20784628b354bfeb5da23c413e1514dab0f 100644 --- a/dapps/valuetransfers/packages/tangle/payloadmetadata.go +++ b/dapps/valuetransfers/packages/tangle/payloadmetadata.go @@ -16,7 +16,7 @@ import ( type PayloadMetadata struct { objectstorage.StorableObjectFlags - payloadId payload.Id + payloadID payload.ID solid bool solidificationTime time.Time @@ -25,15 +25,15 @@ type PayloadMetadata struct { } // NewPayloadMetadata creates an empty container for the metadata of a value transfer payload. -func NewPayloadMetadata(payloadId payload.Id) *PayloadMetadata { +func NewPayloadMetadata(payloadID payload.ID) *PayloadMetadata { return &PayloadMetadata{ - payloadId: payloadId, + payloadID: payloadID, } } // PayloadMetadataFromBytes 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 PayloadMetadataFromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) { +func PayloadMetadataFromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParsePayloadMetadata(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -43,30 +43,28 @@ func PayloadMetadataFromBytes(bytes []byte, optionalTargetObject ...*PayloadMeta // ParsePayloadMetadata is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. func ParsePayloadMetadata(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return PayloadMetadataFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*PayloadMetadata) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*PayloadMetadata) + _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return - }); err != nil { - return - } + }) return } // PayloadMetadataFromStorageKey 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.ObjectStorageValue interface. -func PayloadMetadataFromStorageKey(id []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) { +func PayloadMetadataFromStorageKey(id []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -79,7 +77,7 @@ func PayloadMetadataFromStorageKey(id []byte, optionalTargetObject ...*PayloadMe // parse the properties that are stored in the key marshalUtil := marshalutil.New(id) - if result.payloadId, err = payload.ParseId(marshalUtil); err != nil { + if result.payloadID, err = payload.ParseID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() @@ -87,9 +85,9 @@ func PayloadMetadataFromStorageKey(id []byte, optionalTargetObject ...*PayloadMe return } -// GetPayloadId return the id of the payload that this metadata is associated to. -func (payloadMetadata *PayloadMetadata) GetPayloadId() payload.Id { - return payloadMetadata.payloadId +// PayloadID return the id of the payload that this metadata is associated to. +func (payloadMetadata *PayloadMetadata) PayloadID() payload.ID { + return payloadMetadata.payloadID } // IsSolid returns true if the payload has been marked as solid. @@ -131,7 +129,7 @@ func (payloadMetadata *PayloadMetadata) SetSolid(solid bool) (modified bool) { } // SoldificationTime returns the time when the payload was marked to be solid. -func (payloadMetadata *PayloadMetadata) GetSoldificationTime() time.Time { +func (payloadMetadata *PayloadMetadata) SoldificationTime() time.Time { payloadMetadata.solidificationTimeMutex.RLock() defer payloadMetadata.solidificationTimeMutex.RUnlock() @@ -140,7 +138,7 @@ func (payloadMetadata *PayloadMetadata) GetSoldificationTime() time.Time { // Bytes marshals the metadata into a sequence of bytes. func (payloadMetadata *PayloadMetadata) Bytes() []byte { - return marshalutil.New(payload.IdLength + marshalutil.TIME_SIZE + marshalutil.BOOL_SIZE). + return marshalutil.New(payload.IDLength + marshalutil.TIME_SIZE + marshalutil.BOOL_SIZE). WriteBytes(payloadMetadata.ObjectStorageKey()). WriteBytes(payloadMetadata.ObjectStorageValue()). Bytes() @@ -149,16 +147,16 @@ func (payloadMetadata *PayloadMetadata) Bytes() []byte { // 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("payloadId", payloadMetadata.PayloadID()), stringify.StructField("solid", payloadMetadata.IsSolid()), - stringify.StructField("solidificationTime", payloadMetadata.GetSoldificationTime()), + stringify.StructField("solidificationTime", payloadMetadata.SoldificationTime()), ) } // ObjectStorageKey returns the key that is used to store the object in the database. // It is required to match StorableObject interface. func (payloadMetadata *PayloadMetadata) ObjectStorageKey() []byte { - return payloadMetadata.payloadId.Bytes() + return payloadMetadata.payloadID.Bytes() } // Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters. @@ -176,7 +174,7 @@ func (payloadMetadata *PayloadMetadata) ObjectStorageValue() []byte { } // UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface. -func (payloadMetadata *PayloadMetadata) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (payloadMetadata *PayloadMetadata) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) if payloadMetadata.solidificationTime, err = marshalUtil.ReadTime(); err != nil { return @@ -212,13 +210,15 @@ func (cachedPayloadMetadata *CachedPayloadMetadata) Consume(consumer func(payloa // Unwrap provides a way to "Get" a type casted version of the underlying object. func (cachedPayloadMetadata *CachedPayloadMetadata) Unwrap() *PayloadMetadata { - if untypedTransaction := cachedPayloadMetadata.Get(); untypedTransaction == nil { + untypedTransaction := cachedPayloadMetadata.Get() + if untypedTransaction == nil { return nil - } else { - if typeCastedTransaction := untypedTransaction.(*PayloadMetadata); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } } + + typeCastedTransaction := untypedTransaction.(*PayloadMetadata) + if typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } + + return typeCastedTransaction } diff --git a/dapps/valuetransfers/packages/tangle/payloadmetadata_test.go b/dapps/valuetransfers/packages/tangle/payloadmetadata_test.go index 84cb2e5a511c72144699e8ea7faa6bec29937cc2..0b02834175651a4d7a833da8c2af536ffc9a2b0b 100644 --- a/dapps/valuetransfers/packages/tangle/payloadmetadata_test.go +++ b/dapps/valuetransfers/packages/tangle/payloadmetadata_test.go @@ -10,37 +10,37 @@ import ( ) func TestMarshalUnmarshal(t *testing.T) { - originalMetadata := NewPayloadMetadata(payload.GenesisId) + originalMetadata := NewPayloadMetadata(payload.GenesisID) - clonedMetadata, err, _ := PayloadMetadataFromBytes(originalMetadata.Bytes()) + clonedMetadata, _, err := PayloadMetadataFromBytes(originalMetadata.Bytes()) if err != nil { panic(err) } - assert.Equal(t, originalMetadata.GetPayloadId(), clonedMetadata.GetPayloadId()) + assert.Equal(t, originalMetadata.PayloadID(), clonedMetadata.PayloadID()) assert.Equal(t, originalMetadata.IsSolid(), clonedMetadata.IsSolid()) - assert.Equal(t, originalMetadata.GetSoldificationTime().Round(time.Second), clonedMetadata.GetSoldificationTime().Round(time.Second)) + assert.Equal(t, originalMetadata.SoldificationTime().Round(time.Second), clonedMetadata.SoldificationTime().Round(time.Second)) originalMetadata.SetSolid(true) - clonedMetadata, err, _ = PayloadMetadataFromBytes(originalMetadata.Bytes()) + clonedMetadata, _, err = PayloadMetadataFromBytes(originalMetadata.Bytes()) if err != nil { panic(err) } - assert.Equal(t, originalMetadata.GetPayloadId(), clonedMetadata.GetPayloadId()) + assert.Equal(t, originalMetadata.PayloadID(), clonedMetadata.PayloadID()) assert.Equal(t, originalMetadata.IsSolid(), clonedMetadata.IsSolid()) - assert.Equal(t, originalMetadata.GetSoldificationTime().Round(time.Second), clonedMetadata.GetSoldificationTime().Round(time.Second)) + assert.Equal(t, originalMetadata.SoldificationTime().Round(time.Second), clonedMetadata.SoldificationTime().Round(time.Second)) } func TestPayloadMetadata_SetSolid(t *testing.T) { - originalMetadata := NewPayloadMetadata(payload.GenesisId) + originalMetadata := NewPayloadMetadata(payload.GenesisID) assert.Equal(t, false, originalMetadata.IsSolid()) - assert.Equal(t, time.Time{}, originalMetadata.GetSoldificationTime()) + assert.Equal(t, time.Time{}, originalMetadata.SoldificationTime()) originalMetadata.SetSolid(true) assert.Equal(t, true, originalMetadata.IsSolid()) - assert.Equal(t, time.Now().Round(time.Second), originalMetadata.GetSoldificationTime().Round(time.Second)) + assert.Equal(t, time.Now().Round(time.Second), originalMetadata.SoldificationTime().Round(time.Second)) } diff --git a/dapps/valuetransfers/packages/tangle/tangle.go b/dapps/valuetransfers/packages/tangle/tangle.go index 240f0e9c818ab76530fe972f97872b067cbb39ca..6332933bff2a6a1bd71749fe53972edc0f4484cf 100644 --- a/dapps/valuetransfers/packages/tangle/tangle.go +++ b/dapps/valuetransfers/packages/tangle/tangle.go @@ -27,6 +27,7 @@ type Tangle struct { cleanupWorkerPool async.WorkerPool } +// New is the constructor of a Tangle and creates a new Tangle object from the given details. func New(badgerInstance *badger.DB) (result *Tangle) { osFactory := objectstorage.NewFactory(badgerInstance, storageprefix.ValueTransfers) @@ -34,7 +35,7 @@ func New(badgerInstance *badger.DB) (result *Tangle) { payloadStorage: osFactory.New(osPayload, osPayloadFactory, objectstorage.CacheTime(time.Second)), payloadMetadataStorage: osFactory.New(osPayloadMetadata, osPayloadMetadataFactory, objectstorage.CacheTime(time.Second)), missingPayloadStorage: osFactory.New(osMissingPayload, osMissingPayloadFactory, objectstorage.CacheTime(time.Second)), - approverStorage: osFactory.New(osApprover, osPayloadApproverFactory, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)), + approverStorage: osFactory.New(osApprover, osPayloadApproverFactory, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IDLength, payload.IDLength), objectstorage.KeysOnly(true)), Events: *newEvents(), } @@ -48,23 +49,23 @@ func (tangle *Tangle) AttachPayload(payload *payload.Payload) { } // GetPayload retrieves a payload from the object storage. -func (tangle *Tangle) GetPayload(payloadId payload.Id) *payload.CachedPayload { - return &payload.CachedPayload{CachedObject: tangle.payloadStorage.Load(payloadId.Bytes())} +func (tangle *Tangle) GetPayload(payloadID payload.ID) *payload.CachedPayload { + return &payload.CachedPayload{CachedObject: tangle.payloadStorage.Load(payloadID.Bytes())} } -// GetPayloadMetadata retrieves the metadata of a value payload from the object storage. -func (tangle *Tangle) GetPayloadMetadata(payloadId payload.Id) *CachedPayloadMetadata { - return &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Load(payloadId.Bytes())} +// PayloadMetadata retrieves the metadata of a value payload from the object storage. +func (tangle *Tangle) PayloadMetadata(payloadID payload.ID) *CachedPayloadMetadata { + return &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Load(payloadID.Bytes())} } // GetApprovers retrieves the approvers of a payload from the object storage. -func (tangle *Tangle) GetApprovers(payloadId payload.Id) CachedApprovers { +func (tangle *Tangle) GetApprovers(payloadID payload.ID) CachedApprovers { approvers := make(CachedApprovers, 0) tangle.approverStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { approvers = append(approvers, &CachedPayloadApprover{CachedObject: cachedObject}) return true - }, payloadId.Bytes()) + }, payloadID.Bytes()) return approvers } @@ -113,7 +114,7 @@ func (tangle *Tangle) storePayloadWorker(payloadToStore *payload.Payload) { tangle.storePayloadReferences(payloadToStore) // trigger events - if tangle.missingPayloadStorage.DeleteIfPresent(payloadToStore.Id().Bytes()) { + if tangle.missingPayloadStorage.DeleteIfPresent(payloadToStore.ID().Bytes()) { tangle.Events.MissingPayloadReceived.Trigger(cachedPayload, cachedPayloadMetadata) } tangle.Events.PayloadAttached.Trigger(cachedPayload, cachedPayloadMetadata) @@ -125,25 +126,26 @@ func (tangle *Tangle) storePayloadWorker(payloadToStore *payload.Payload) { } func (tangle *Tangle) storePayload(payloadToStore *payload.Payload) (cachedPayload *payload.CachedPayload, cachedMetadata *CachedPayloadMetadata, payloadStored bool) { - if _tmp, transactionIsNew := tangle.payloadStorage.StoreIfAbsent(payloadToStore); !transactionIsNew { - return - } else { - cachedPayload = &payload.CachedPayload{CachedObject: _tmp} - cachedMetadata = &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Store(NewPayloadMetadata(payloadToStore.Id()))} - payloadStored = true - + storedTransaction, transactionIsNew := tangle.payloadStorage.StoreIfAbsent(payloadToStore) + if !transactionIsNew { return } + + cachedPayload = &payload.CachedPayload{CachedObject: storedTransaction} + cachedMetadata = &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Store(NewPayloadMetadata(payloadToStore.ID()))} + payloadStored = true + + return } func (tangle *Tangle) storePayloadReferences(payload *payload.Payload) { // store trunk approver - trunkId := payload.TrunkId() - tangle.approverStorage.Store(NewPayloadApprover(trunkId, payload.Id())).Release() + trunkID := payload.TrunkID() + tangle.approverStorage.Store(NewPayloadApprover(trunkID, payload.ID())).Release() // store branch approver - if branchId := payload.BranchId(); branchId != trunkId { - tangle.approverStorage.Store(NewPayloadApprover(branchId, trunkId)).Release() + if branchID := payload.BranchID(); branchID != trunkID { + tangle.approverStorage.Store(NewPayloadApprover(branchID, trunkID)).Release() } } @@ -184,20 +186,21 @@ func (tangle *Tangle) solidifyPayloadWorker(cachedPayload *payload.CachedPayload tangle.Events.PayloadSolid.Trigger(currentCachedPayload, currentCachedMetadata) // ... and schedule check of approvers - tangle.ForeachApprovers(currentPayload.Id(), func(payload *payload.CachedPayload, payloadMetadata *CachedPayloadMetadata) { + tangle.ForeachApprovers(currentPayload.ID(), func(payload *payload.CachedPayload, payloadMetadata *CachedPayloadMetadata) { solidificationStack.PushBack([2]interface{}{payload, payloadMetadata}) }) }() } } -func (tangle *Tangle) ForeachApprovers(payloadId payload.Id, consume func(payload *payload.CachedPayload, payloadMetadata *CachedPayloadMetadata)) { - tangle.GetApprovers(payloadId).Consume(func(approver *PayloadApprover) { - approvingPayloadId := approver.GetApprovingPayloadId() - approvingCachedPayload := tangle.GetPayload(approvingPayloadId) +// ForeachApprovers iterates through the approvers of a payload and calls the passed in consumer function. +func (tangle *Tangle) ForeachApprovers(payloadID payload.ID, consume func(payload *payload.CachedPayload, payloadMetadata *CachedPayloadMetadata)) { + tangle.GetApprovers(payloadID).Consume(func(approver *PayloadApprover) { + approvingPayloadID := approver.ApprovingPayloadID() + approvingCachedPayload := tangle.GetPayload(approvingPayloadID) approvingCachedPayload.Consume(func(payload *payload.Payload) { - consume(approvingCachedPayload, tangle.GetPayloadMetadata(approvingPayloadId)) + consume(approvingCachedPayload, tangle.PayloadMetadata(approvingPayloadID)) }) }) } @@ -217,24 +220,24 @@ func (tangle *Tangle) isPayloadSolid(payload *payload.Payload, metadata *Payload return true } - return tangle.isPayloadMarkedAsSolid(payload.TrunkId()) && tangle.isPayloadMarkedAsSolid(payload.BranchId()) + return tangle.isPayloadMarkedAsSolid(payload.TrunkID()) && tangle.isPayloadMarkedAsSolid(payload.BranchID()) } // isPayloadMarkedAsSolid returns true if the payload was marked as solid already (by setting the corresponding flags // in its metadata. -func (tangle *Tangle) isPayloadMarkedAsSolid(payloadId payload.Id) bool { - if payloadId == payload.GenesisId { +func (tangle *Tangle) isPayloadMarkedAsSolid(payloadID payload.ID) bool { + if payloadID == payload.GenesisID { return true } - transactionMetadataCached := tangle.GetPayloadMetadata(payloadId) + transactionMetadataCached := tangle.PayloadMetadata(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(NewMissingPayload(payloadId)); missingPayloadStored { + if cachedMissingPayload, missingPayloadStored := tangle.missingPayloadStorage.StoreIfAbsent(NewMissingPayload(payloadID)); missingPayloadStored { cachedMissingPayload.Consume(func(object objectstorage.StorableObject) { - tangle.Events.PayloadMissing.Trigger(object.(*MissingPayload).GetId()) + tangle.Events.PayloadMissing.Trigger(object.(*MissingPayload).ID()) }) } diff --git a/dapps/valuetransfers/packages/transaction/id.go b/dapps/valuetransfers/packages/transaction/id.go index 3352d007cedf0082fe16cf08bf31acebd8396483..aa333343d30d345c96e153c920ebc3949f7a92c0 100644 --- a/dapps/valuetransfers/packages/transaction/id.go +++ b/dapps/valuetransfers/packages/transaction/id.go @@ -8,11 +8,11 @@ import ( "github.com/mr-tron/base58" ) -// Id is the data type that represents the identifier for a Transaction. -type Id [IdLength]byte +// ID is the data type that represents the identifier for a Transaction. +type ID [IDLength]byte -// IdFromBase58 creates an id from a base58 encoded string. -func IdFromBase58(base58String string) (id Id, err error) { +// IDFromBase58 creates an id from a base58 encoded string. +func IDFromBase58(base58String string) (id ID, err error) { // decode string bytes, err := base58.Decode(base58String) if err != nil { @@ -20,7 +20,7 @@ func IdFromBase58(base58String string) (id Id, err error) { } // sanitize input - if len(bytes) != IdLength { + if len(bytes) != IDLength { err = fmt.Errorf("base58 encoded string does not match the length of a transaction id") return @@ -32,35 +32,36 @@ func IdFromBase58(base58String string) (id Id, err error) { return } -// IdFromBytes unmarshals an Id from a sequence of bytes. -func IdFromBytes(bytes []byte) (result Id, err error, consumedBytes int) { +// IDFromBytes unmarshals an ID from a sequence of bytes. +func IDFromBytes(bytes []byte) (result ID, consumedBytes int, err error) { // parse the bytes marshalUtil := marshalutil.New(bytes) - if idBytes, idErr := marshalUtil.ReadBytes(IdLength); idErr != nil { + idBytes, idErr := marshalUtil.ReadBytes(IDLength) + if idErr != nil { err = idErr return - } else { - copy(result[:], idBytes) } + copy(result[:], idBytes) consumedBytes = marshalUtil.ReadOffset() return } -// Parse is a wrapper for simplified unmarshaling of Ids from 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 +// ParseID is a wrapper for simplified unmarshaling of Ids from a byte stream using the marshalUtil package. +func ParseID(marshalUtil *marshalutil.MarshalUtil) (ID, error) { + id, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return IDFromBytes(data) }) + if err != nil { + return ID{}, err } + + return id.(ID), nil } -// Random creates a random id which can for example be used in unit tests. -func RandomId() (id Id) { +// RandomID creates a random id which can for example be used in unit tests. +func RandomID() (id ID) { // generate a random sequence of bytes - idBytes := make([]byte, IdLength) + idBytes := make([]byte, IDLength) if _, err := rand.Read(idBytes); err != nil { panic(err) } @@ -71,15 +72,15 @@ func RandomId() (id Id) { return } -// Bytes marshals the Id into a sequence of bytes. -func (id Id) Bytes() []byte { +// Bytes marshals the ID into a sequence of bytes. +func (id ID) Bytes() []byte { return id[:] } -// String creates a human readable version of the Id (for debug purposes). -func (id Id) String() string { +// String creates a human readable version of the ID (for debug purposes). +func (id ID) String() string { return base58.Encode(id[:]) } -// IdLength contains the amount of bytes that a marshaled version of the Id contains. -const IdLength = 32 +// IDLength contains the amount of bytes that a marshaled version of the ID contains. +const IDLength = 32 diff --git a/dapps/valuetransfers/packages/transaction/inputs.go b/dapps/valuetransfers/packages/transaction/inputs.go index 4c34103fb13842df42d731a1dc51006f716334b7..f4c638d17e6e0d4af5107a5628a567bc0dbeb302 100644 --- a/dapps/valuetransfers/packages/transaction/inputs.go +++ b/dapps/valuetransfers/packages/transaction/inputs.go @@ -7,20 +7,23 @@ import ( "github.com/iotaledger/hive.go/marshalutil" ) +// Inputs represents a list of referenced Outputs that are used as Inputs in a transaction. type Inputs struct { *orderedmap.OrderedMap } -func NewInputs(outputIds ...OutputId) (inputs *Inputs) { +// NewInputs is the constructor of the Inputs object and creates a new list with the given OutputIds. +func NewInputs(outputIds ...OutputID) (inputs *Inputs) { inputs = &Inputs{orderedmap.New()} - for _, outputId := range outputIds { - inputs.Add(outputId) + for _, outputID := range outputIds { + inputs.Add(outputID) } return } -func InputsFromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int) { +// InputsFromBytes unmarshals the Inputs from a sequence of bytes. +func InputsFromBytes(bytes []byte) (inputs *Inputs, consumedBytes int, err error) { inputs = NewInputs() marshalUtil := marshalutil.New(bytes) @@ -37,13 +40,13 @@ func InputsFromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int return } - idBytes, readErr := marshalUtil.ReadBytes(IdLength) + idBytes, readErr := marshalUtil.ReadBytes(IDLength) if readErr != nil { err = readErr return } - id, idErr, _ := IdFromBytes(idBytes) + id, _, idErr := IDFromBytes(idBytes) if idErr != nil { err = idErr @@ -56,7 +59,7 @@ func InputsFromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int inputs.Set(readAddress, addressMap) } - addressMap.(*orderedmap.OrderedMap).Set(id, NewOutputId(readAddress, id)) + addressMap.(*orderedmap.OrderedMap).Set(id, NewOutputID(readAddress, id)) } consumedBytes = marshalUtil.ReadOffset() @@ -64,9 +67,10 @@ func InputsFromBytes(bytes []byte) (inputs *Inputs, err error, consumedBytes int return } -func (inputs *Inputs) Add(input OutputId) *Inputs { +// Add allows us to add a new Output to the list of Inputs. +func (inputs *Inputs) Add(input OutputID) *Inputs { inputAddress := input.Address() - transactionId := input.TransactionId() + transactionID := input.TransactionID() addressMap, addressExists := inputs.Get(inputAddress) if !addressExists { @@ -75,17 +79,18 @@ func (inputs *Inputs) Add(input OutputId) *Inputs { inputs.Set(inputAddress, addressMap) } - addressMap.(*orderedmap.OrderedMap).Set(transactionId, input) + addressMap.(*orderedmap.OrderedMap).Set(transactionID, input) return inputs } +// Bytes returns a marshaled version of this list of Inputs. func (inputs *Inputs) Bytes() (bytes []byte) { marshalUtil := marshalutil.New() marshalUtil.WriteSeek(4) var inputCounter uint32 - inputs.ForEach(func(outputId OutputId) bool { + inputs.ForEach(func(outputId OutputID) bool { marshalUtil.WriteBytes(outputId.Bytes()) inputCounter++ @@ -98,34 +103,41 @@ func (inputs *Inputs) Bytes() (bytes []byte) { return marshalUtil.Bytes() } -func (inputs *Inputs) ForEach(consumer func(outputId OutputId) bool) bool { +// ForEach iterates through the referenced Outputs and calls the consumer function for every Output. The iteration can +// be aborted by returning false in the consumer. +func (inputs *Inputs) ForEach(consumer func(outputId OutputID) bool) bool { return inputs.OrderedMap.ForEach(func(key, value interface{}) bool { return value.(*orderedmap.OrderedMap).ForEach(func(key, value interface{}) bool { - return consumer(value.(OutputId)) + return consumer(value.(OutputID)) }) }) } +// ForEachAddress iterates through the input addresses and calls the consumer function for every Address. The iteration +// can be aborted by returning false in the consumer. func (inputs *Inputs) ForEachAddress(consumer func(currentAddress address.Address) bool) bool { return inputs.OrderedMap.ForEach(func(key, value interface{}) bool { return consumer(key.(address.Address)) }) } -func (inputs *Inputs) ForEachTransaction(consumer func(transactionId Id) bool) bool { - seenTransactions := make(map[Id]bool) +// ForEachTransaction iterates through the transactions that had their Outputs consumed and calls the consumer function +// for every founds transaction. The iteration can be aborted by returning false in the consumer. +func (inputs *Inputs) ForEachTransaction(consumer func(transactionId ID) bool) bool { + seenTransactions := make(map[ID]bool) - return inputs.ForEach(func(outputId OutputId) bool { - if currentTransactionId := outputId.TransactionId(); !seenTransactions[currentTransactionId] { - seenTransactions[currentTransactionId] = true + return inputs.ForEach(func(outputId OutputID) bool { + if currentTransactionID := outputId.TransactionID(); !seenTransactions[currentTransactionID] { + seenTransactions[currentTransactionID] = true - return consumer(currentTransactionId) + return consumer(currentTransactionID) } return true }) } +// String returns a human readable version of the list of Inputs (for debug purposes). func (inputs *Inputs) String() string { if inputs == nil { return "<nil>" @@ -134,7 +146,7 @@ func (inputs *Inputs) String() string { result := "[\n" empty := true - inputs.ForEach(func(outputId OutputId) bool { + inputs.ForEach(func(outputId OutputID) bool { empty = false result += " " + outputId.String() + ",\n" diff --git a/dapps/valuetransfers/packages/transaction/outputid.go b/dapps/valuetransfers/packages/transaction/outputid.go index 95fbe0c625681a10d763301479c1ac21da85c79e..3eadb0977520e425dc3fea61fd743ccaf665c893 100644 --- a/dapps/valuetransfers/packages/transaction/outputid.go +++ b/dapps/valuetransfers/packages/transaction/outputid.go @@ -8,65 +8,66 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address" ) -// OutputId is the data type that represents the identifier for a Output. -type OutputId [OutputIdLength]byte +// OutputID is the data type that represents the identifier for a Output. +type OutputID [OutputIDLength]byte -// NewOutputId is the constructor for the OutputId type. -func NewOutputId(outputAddress address.Address, transactionId Id) (outputId OutputId) { - copy(outputId[:address.Length], outputAddress.Bytes()) - copy(outputId[address.Length:], transactionId[:]) +// NewOutputID is the constructor for the OutputID type. +func NewOutputID(outputAddress address.Address, transactionID ID) (outputID OutputID) { + copy(outputID[:address.Length], outputAddress.Bytes()) + copy(outputID[address.Length:], transactionID[:]) return } -// OutputIdFromBytes unmarshals an OutputId from a sequence of bytes. -func OutputIdFromBytes(bytes []byte) (result OutputId, err error, consumedBytes int) { +// OutputIDFromBytes unmarshals an OutputID from a sequence of bytes. +func OutputIDFromBytes(bytes []byte) (result OutputID, consumedBytes int, err error) { // parse the bytes marshalUtil := marshalutil.New(bytes) - if idBytes, idErr := marshalUtil.ReadBytes(OutputIdLength); idErr != nil { + idBytes, idErr := marshalUtil.ReadBytes(OutputIDLength) + if idErr != nil { err = idErr return - } else { - copy(result[:], idBytes) } + copy(result[:], idBytes) consumedBytes = marshalUtil.ReadOffset() return } -// Parse is a wrapper for simplified unmarshaling of Ids from a byte stream using the marshalUtil package. -func ParseOutputId(marshalUtil *marshalutil.MarshalUtil) (OutputId, error) { - if outputId, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return OutputIdFromBytes(data) }); err != nil { - return OutputId{}, err - } else { - return outputId.(OutputId), nil +// ParseOutputID is a wrapper for simplified unmarshaling of Ids from a byte stream using the marshalUtil package. +func ParseOutputID(marshalUtil *marshalutil.MarshalUtil) (OutputID, error) { + outputID, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return OutputIDFromBytes(data) }) + if err != nil { + return OutputID{}, err } + + return outputID.(OutputID), nil } -// Address returns the address part of an OutputId. -func (outputId OutputId) Address() (address address.Address) { - copy(address[:], outputId[:]) +// Address returns the address part of an OutputID. +func (outputID OutputID) Address() (address address.Address) { + copy(address[:], outputID[:]) return } -// TransactionId returns the transaction id part of an OutputId. -func (outputId OutputId) TransactionId() (transactionId Id) { - copy(transactionId[:], outputId[address.Length:]) +// TransactionID returns the transaction id part of an OutputID. +func (outputID OutputID) TransactionID() (transactionID ID) { + copy(transactionID[:], outputID[address.Length:]) return } -// Bytes marshals the OutputId into a sequence of bytes. -func (outputId OutputId) Bytes() []byte { - return outputId[:] +// Bytes marshals the OutputID into a sequence of bytes. +func (outputID OutputID) Bytes() []byte { + return outputID[:] } -// String creates a human readable version of the OutputId (for debug purposes). -func (outputId OutputId) String() string { - return base58.Encode(outputId[:]) +// String creates a human readable version of the OutputID (for debug purposes). +func (outputID OutputID) String() string { + return base58.Encode(outputID[:]) } -// IdLength contains the amount of bytes that a marshaled version of the OutputId contains. -const OutputIdLength = address.Length + IdLength +// OutputIDLength contains the amount of bytes that a marshaled version of the OutputID contains. +const OutputIDLength = address.Length + IDLength diff --git a/dapps/valuetransfers/packages/transaction/outputs.go b/dapps/valuetransfers/packages/transaction/outputs.go index dc208a292ae4a4f7985ac462dba28f8c3e47a09b..fd825d65e73b57855c813e5926ccea32b507e1af 100644 --- a/dapps/valuetransfers/packages/transaction/outputs.go +++ b/dapps/valuetransfers/packages/transaction/outputs.go @@ -9,10 +9,12 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance" ) +// Outputs represents a list of Outputs that are part of a transaction. type Outputs struct { *orderedmap.OrderedMap } +// NewOutputs is the constructor of the Outputs struct and creates the list of Outputs from the given details. func NewOutputs(outputs map[address.Address][]*balance.Balance) (result *Outputs) { result = &Outputs{orderedmap.New()} for address, balances := range outputs { @@ -22,9 +24,9 @@ func NewOutputs(outputs map[address.Address][]*balance.Balance) (result *Outputs return } -// FromBytes reads the bytes and unmarshals the given information into an *Outputs object. It either creates a +// OutputsFromBytes reads the bytes and unmarshals the given information into an *Outputs object. It either creates a // new object, or uses the optional object provided in the arguments. -func OutputsFromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, err error, consumedBytes int) { +func OutputsFromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *Outputs, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -65,7 +67,7 @@ func OutputsFromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *O // iterate the corresponding times and collect balances coloredBalances := make([]*balance.Balance, balanceCount) for j := uint32(0); j < balanceCount; j++ { - coloredBalance, coloredBalanceErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return balance.FromBytes(data) }) + coloredBalance, coloredBalanceErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return balance.FromBytes(data) }) if coloredBalanceErr != nil { err = coloredBalanceErr @@ -85,18 +87,22 @@ func OutputsFromBytes(bytes []byte, optionalTargetObject ...*Outputs) (result *O return } +// Add adds a new Output to the list of Outputs. func (outputs *Outputs) Add(address address.Address, balances []*balance.Balance) *Outputs { outputs.Set(address, balances) return outputs } +// ForEach iterates through the Outputs and calls them consumer for every found one. The iteration can be aborted by +// returning false in the consumer. func (outputs *Outputs) ForEach(consumer func(address address.Address, balances []*balance.Balance) bool) bool { return outputs.OrderedMap.ForEach(func(key, value interface{}) bool { return consumer(key.(address.Address), value.([]*balance.Balance)) }) } +// Bytes returns a marshaled version of this list of Outputs. func (outputs *Outputs) Bytes() []byte { marshalUtil := marshalutil.New() @@ -121,6 +127,7 @@ func (outputs *Outputs) Bytes() []byte { return marshalUtil.Bytes() } +// String returns a human readable version of this list of Outputs (for debug purposes). func (outputs *Outputs) String() string { if outputs == nil { return "<nil>" diff --git a/dapps/valuetransfers/packages/transaction/signatures.go b/dapps/valuetransfers/packages/transaction/signatures.go index 79e2fa838bd99519a763c0497e7c3dd330f4e88e..2a5879c03e454d7b577025c8beae6b09ee1be959 100644 --- a/dapps/valuetransfers/packages/transaction/signatures.go +++ b/dapps/valuetransfers/packages/transaction/signatures.go @@ -15,16 +15,16 @@ type Signatures struct { orderedMap *orderedmap.OrderedMap } -// New creates an empty container for the address signatures of a value transfer. +// NewSignatures creates an empty container for the address signatures of a value transfer. func NewSignatures() *Signatures { return &Signatures{ orderedMap: orderedmap.New(), } } -// FromBytes unmarshals a container with signatures from a sequence of bytes. +// SignaturesFromBytes 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 SignaturesFromBytes(bytes []byte, optionalTargetObject ...*Signatures) (result *Signatures, err error, consumedBytes int) { +func SignaturesFromBytes(bytes []byte, optionalTargetObject ...*Signatures) (result *Signatures, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -50,9 +50,9 @@ func SignaturesFromBytes(bytes []byte, optionalTargetObject ...*Signatures) (res typeCastedSignature = nil // perform signature scheme specific decoding switch versionByte { - case address.VERSION_ED25519: + case address.VersionED25519: marshalUtil.ReadSeek(-1) - signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return signaturescheme.Ed25519SignatureFromBytes(data) }) + signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return signaturescheme.Ed25519SignatureFromBytes(data) }) if signatureErr != nil { err = signatureErr @@ -60,9 +60,9 @@ func SignaturesFromBytes(bytes []byte, optionalTargetObject ...*Signatures) (res } typeCastedSignature = signature.(signaturescheme.Signature) - case address.VERSION_BLS: + case address.VersionBLS: marshalUtil.ReadSeek(-1) - signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return signaturescheme.BLSSignatureFromBytes(data) }) + signature, signatureErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return signaturescheme.BLSSignatureFromBytes(data) }) if signatureErr != nil { err = signatureErr @@ -88,10 +88,12 @@ func SignaturesFromBytes(bytes []byte, optionalTargetObject ...*Signatures) (res return } +// Add adds a new Signature to this container. func (signatures *Signatures) Add(address address.Address, signature signaturescheme.Signature) { signatures.orderedMap.Set(address, signature) } +// Get returns the Signature, that belongs to an Address. func (signatures *Signatures) Get(address address.Address) (signaturescheme.Signature, bool) { signature, exists := signatures.orderedMap.Get(address) if !exists { diff --git a/dapps/valuetransfers/packages/transaction/signatures_test.go b/dapps/valuetransfers/packages/transaction/signatures_test.go index cc8aecef9388c28bde4935e972cb85f88f6c0db6..61d03a26e949792c3de6cf5bb866c1af4207d4e8 100644 --- a/dapps/valuetransfers/packages/transaction/signatures_test.go +++ b/dapps/valuetransfers/packages/transaction/signatures_test.go @@ -34,7 +34,7 @@ func TestSignatures(t *testing.T) { return true }) - clonedSignatures, err, _ := SignaturesFromBytes(signatures.Bytes()) + clonedSignatures, _, err := SignaturesFromBytes(signatures.Bytes()) if err != nil { t.Error(err) diff --git a/dapps/valuetransfers/packages/transaction/transaction.go b/dapps/valuetransfers/packages/transaction/transaction.go index fa82a911673cd9ceee3bf8f022b4a28a9e159cce..45d3e620480ba747e9ad1467c70dd513238257cf 100644 --- a/dapps/valuetransfers/packages/transaction/transaction.go +++ b/dapps/valuetransfers/packages/transaction/transaction.go @@ -16,6 +16,9 @@ import ( // region IMPLEMENT Transaction //////////////////////////////////////////////////////////////////////////////////////////// +// Transaction represents a value transfer for IOTA. It consists out of a number of inputs, a number of outputs and their +// corresponding signature. Additionally, there is an optional data field, that can be used to include payment details or +// processing information. type Transaction struct { objectstorage.StorableObjectFlags @@ -23,7 +26,7 @@ type Transaction struct { outputs *Outputs signatures *Signatures - id *Id + id *ID idMutex sync.RWMutex essenceBytes []byte @@ -39,6 +42,8 @@ type Transaction struct { bytesMutex sync.RWMutex } +// New creates a new Transaction from the given details. The signatures are omitted as signing requires us to marshal +// the transaction into a sequence of bytes and these bytes are unknown at the time of the creation of the Transaction. func New(inputs *Inputs, outputs *Outputs) *Transaction { return &Transaction{ inputs: inputs, @@ -47,7 +52,8 @@ func New(inputs *Inputs, outputs *Outputs) *Transaction { } } -func FromBytes(bytes []byte, optionalTargetObject ...*Transaction) (result *Transaction, err error, consumedBytes int) { +// FromBytes unmarshals a Transaction from a sequence of bytes. +func FromBytes(bytes []byte, optionalTargetObject ...*Transaction) (result *Transaction, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = Parse(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -55,7 +61,9 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Transaction) (result *Tran return } -func FromStorageKey(key []byte, optionalTargetObject ...*Transaction) (result objectstorage.StorableObject, err error, consumedBytes int) { +// FromStorageKey is a factory method that creates a new Transaction instance from a storage key of the objectstorage. +// It is used by the objectstorage, to create new instances of this entity. +func FromStorageKey(key []byte, optionalTargetObject ...*Transaction) (result objectstorage.StorableObject, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -67,7 +75,7 @@ func FromStorageKey(key []byte, optionalTargetObject ...*Transaction) (result ob } marshalUtil := marshalutil.New(key) - id, err := ParseId(marshalUtil) + id, err := ParseID(marshalUtil) if err != nil { return } @@ -76,6 +84,7 @@ func FromStorageKey(key []byte, optionalTargetObject ...*Transaction) (result ob return } +// Parse unmarshals a Transaction using the given marshalUtil (for easier marshaling/unmarshaling). func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Transaction) (result *Transaction, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { @@ -87,8 +96,8 @@ func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Transa panic("too many arguments in call to Parse") } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -98,7 +107,8 @@ func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Transa return } -func (transaction *Transaction) Id() Id { +// ID returns the identifier of this Transaction. +func (transaction *Transaction) ID() ID { // acquire lock for reading id transaction.idMutex.RLock() @@ -121,7 +131,7 @@ func (transaction *Transaction) Id() Id { // otherwise calculate the id idBytes := blake2b.Sum256(transaction.Bytes()) - id, err, _ := IdFromBytes(idBytes[:]) + id, _, err := IDFromBytes(idBytes[:]) if err != nil { panic(err) } @@ -132,14 +142,17 @@ func (transaction *Transaction) Id() Id { return id } +// Inputs returns the list of Inputs that were consumed by this Transaction. func (transaction *Transaction) Inputs() *Inputs { return transaction.inputs } +// Outputs returns the list of Outputs where this Transaction moves its consumed funds. func (transaction *Transaction) Outputs() *Outputs { return transaction.outputs } +// SignaturesValid returns true if the Signatures in this transaction func (transaction *Transaction) SignaturesValid() bool { signaturesValid := true transaction.inputs.ForEachAddress(func(address address.Address) bool { @@ -155,6 +168,8 @@ func (transaction *Transaction) SignaturesValid() bool { return signaturesValid } +// EssenceBytes return the bytes of the transaction excluding the Signatures. These bytes are later signed and used to +// generate the Signatures. func (transaction *Transaction) EssenceBytes() []byte { // acquire read lock on essenceBytes transaction.essenceBytesMutex.RLock() @@ -197,6 +212,7 @@ func (transaction *Transaction) EssenceBytes() []byte { return transaction.essenceBytes } +// SignatureBytes returns the bytes of all of the signatures in the Transaction. func (transaction *Transaction) SignatureBytes() []byte { transaction.signatureBytesMutex.RLock() if transaction.signatureBytes != nil { @@ -219,6 +235,7 @@ func (transaction *Transaction) SignatureBytes() []byte { return transaction.signatureBytes } +// Bytes returns a marshaled version of this Transaction (essence + signatures). func (transaction *Transaction) Bytes() []byte { // acquire read lock on bytes transaction.bytesMutex.RLock() @@ -255,14 +272,16 @@ func (transaction *Transaction) Bytes() []byte { return transaction.bytes } +// Sign adds a new signature to the Transaction. func (transaction *Transaction) Sign(signature signaturescheme.SignatureScheme) *Transaction { transaction.signatures.Add(signature.Address(), signature.Sign(transaction.EssenceBytes())) return transaction } +// String returns a human readable version of this Transaction (for debug purposes). func (transaction *Transaction) String() string { - id := transaction.Id() + id := transaction.ID() return stringify.Struct("Transaction"+fmt.Sprintf("(%p)", transaction), stringify.StructField("id", base58.Encode(id[:])), @@ -273,16 +292,16 @@ func (transaction *Transaction) String() string { ) } -// max dataPayload size limit -const MAX_DATA_PAYLOAD_SIZE = 64 * 1024 +// MaxDataPayloadSize defines the maximum size (in bytes) of the data payload. +const MaxDataPayloadSize = 64 * 1024 // SetDataPayload sets yhe dataPayload and its type func (transaction *Transaction) SetDataPayload(data []byte) 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) + if len(data) > MaxDataPayloadSize { + return fmt.Errorf("maximum dataPayload size of %d bytes exceeded", MaxDataPayloadSize) } transaction.dataPayload = data return nil @@ -312,10 +331,12 @@ func (transaction *Transaction) DataPayloadSize() uint32 { // define contract (ensure that the struct fulfills the given interface) var _ objectstorage.StorableObject = &Transaction{} +// ObjectStorageKey returns the bytes that are used as a key when storing the Transaction in an objectstorage. func (transaction *Transaction) ObjectStorageKey() []byte { - return transaction.Id().Bytes() + return transaction.ID().Bytes() } +// Update is disabled but needs to be implemented to be compatible with the objectstorage. func (transaction *Transaction) Update(other objectstorage.StorableObject) { panic("update forbidden") } @@ -325,19 +346,20 @@ func (transaction *Transaction) ObjectStorageValue() []byte { return transaction.Bytes() } -func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (err error, consumedBytes int) { +// UnmarshalObjectStorageValue unmarshals the bytes that are stored in the value of the objectstorage. +func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (consumedBytes int, err error) { // initialize helper marshalUtil := marshalutil.New(bytes) // unmarshal inputs - parsedInputs, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return InputsFromBytes(data) }) + parsedInputs, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return InputsFromBytes(data) }) if err != nil { return } transaction.inputs = parsedInputs.(*Inputs) // unmarshal outputs - parsedOutputs, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return OutputsFromBytes(data) }) + parsedOutputs, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return OutputsFromBytes(data) }) if err != nil { return } @@ -349,9 +371,9 @@ func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (err e if err != nil { return } - if dataPayloadSize > MAX_DATA_PAYLOAD_SIZE { + if dataPayloadSize > MaxDataPayloadSize { err = fmt.Errorf("data payload size of %d bytes exceeds maximum limit of %d bytes", - dataPayloadSize, MAX_DATA_PAYLOAD_SIZE) + dataPayloadSize, MaxDataPayloadSize) return } @@ -367,7 +389,7 @@ func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (err e copy(transaction.essenceBytes, bytes[:essenceBytesCount]) // unmarshal outputs - parsedSignatures, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return SignaturesFromBytes(data) }) + parsedSignatures, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return SignaturesFromBytes(data) }) if err != nil { return } @@ -413,13 +435,15 @@ func (cachedTransaction *CachedTransaction) Consume(consumer func(metadata *Tran // Unwrap provides a way to retrieve a type casted version of the underlying object. func (cachedTransaction *CachedTransaction) Unwrap() *Transaction { - if untypedTransaction := cachedTransaction.Get(); untypedTransaction == nil { + untypedTransaction := cachedTransaction.Get() + if untypedTransaction == nil { return nil - } else { - if typeCastedTransaction := untypedTransaction.(*Transaction); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } } + + typeCastedTransaction := untypedTransaction.(*Transaction) + if typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } + + return typeCastedTransaction } diff --git a/dapps/valuetransfers/packages/transaction/transaction_test.go b/dapps/valuetransfers/packages/transaction/transaction_test.go index 51a7b2aa23dd0aa116ebd9a983974a592aad4b33..757a0060ac92821ab1a87b125018f56d55d30ac8 100644 --- a/dapps/valuetransfers/packages/transaction/transaction_test.go +++ b/dapps/valuetransfers/packages/transaction/transaction_test.go @@ -16,7 +16,7 @@ import ( func TestEmptyDataPayload(t *testing.T) { sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair()) addr := sigScheme.Address() - o1 := NewOutputId(addr, RandomId()) + o1 := NewOutputID(addr, RandomID()) inputs := NewInputs(o1) bal := balance.New(balance.ColorIOTA, 1) outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}}) @@ -30,7 +30,7 @@ func TestEmptyDataPayload(t *testing.T) { func TestShortDataPayload(t *testing.T) { sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair()) addr := sigScheme.Address() - o1 := NewOutputId(addr, RandomId()) + o1 := NewOutputID(addr, RandomID()) inputs := NewInputs(o1) bal := balance.New(balance.ColorIOTA, 1) outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}}) @@ -62,13 +62,13 @@ func TestShortDataPayload(t *testing.T) { func TestTooLongDataPayload(t *testing.T) { sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair()) addr := sigScheme.Address() - o1 := NewOutputId(addr, RandomId()) + o1 := NewOutputID(addr, RandomID()) inputs := NewInputs(o1) bal := balance.New(balance.ColorIOTA, 1) outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}}) tx := New(inputs, outputs) - dataPayload := []byte(strings.Repeat("1", MAX_DATA_PAYLOAD_SIZE+1)) + dataPayload := []byte(strings.Repeat("1", MaxDataPayloadSize+1)) err := tx.SetDataPayload(dataPayload) assert.Equal(t, true, err != nil) } @@ -76,7 +76,7 @@ func TestTooLongDataPayload(t *testing.T) { func TestMarshalingEmptyDataPayload(t *testing.T) { sigScheme := signaturescheme.RandBLS() addr := sigScheme.Address() - o1 := NewOutputId(addr, RandomId()) + o1 := NewOutputID(addr, RandomID()) inputs := NewInputs(o1) bal := balance.New(balance.ColorIOTA, 1) outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}}) @@ -89,18 +89,18 @@ func TestMarshalingEmptyDataPayload(t *testing.T) { v := tx.ObjectStorageValue() tx1 := Transaction{} - err, _ := tx1.UnmarshalObjectStorageValue(v) + _, err := tx1.UnmarshalObjectStorageValue(v) if err != nil { assert.Error(t, err) } assert.Equal(t, true, tx1.SignaturesValid()) - assert.Equal(t, true, bytes.Equal(tx1.Id().Bytes(), tx.Id().Bytes())) + assert.Equal(t, true, bytes.Equal(tx1.ID().Bytes(), tx.ID().Bytes())) } func TestMarshalingDataPayload(t *testing.T) { sigScheme := signaturescheme.RandBLS() addr := sigScheme.Address() - o1 := NewOutputId(addr, RandomId()) + o1 := NewOutputID(addr, RandomID()) inputs := NewInputs(o1) bal := balance.New(balance.ColorIOTA, 1) outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}}) @@ -117,10 +117,10 @@ func TestMarshalingDataPayload(t *testing.T) { v := tx.ObjectStorageValue() tx1 := Transaction{} - err, _ = tx1.UnmarshalObjectStorageValue(v) + _, err = tx1.UnmarshalObjectStorageValue(v) assert.Equal(t, nil, err) assert.Equal(t, true, tx1.SignaturesValid()) - assert.Equal(t, true, bytes.Equal(tx1.Id().Bytes(), tx.Id().Bytes())) + assert.Equal(t, true, bytes.Equal(tx1.ID().Bytes(), tx.ID().Bytes())) } diff --git a/dapps/valuetransfers/packages/utxodag/attachment.go b/dapps/valuetransfers/packages/utxodag/attachment.go index 54dfa8db95504c20d18204238569ad29f46d8d22..6104b014ec752eaeb24a92d70e4039d7bc8a41a6 100644 --- a/dapps/valuetransfers/packages/utxodag/attachment.go +++ b/dapps/valuetransfers/packages/utxodag/attachment.go @@ -14,28 +14,28 @@ import ( type Attachment struct { objectstorage.StorableObjectFlags - transactionId transaction.Id - payloadId payload.Id + transactionID transaction.ID + payloadID payload.ID storageKey []byte } // NewAttachment creates an attachment object with the given information. -func NewAttachment(transactionId transaction.Id, payloadId payload.Id) *Attachment { +func NewAttachment(transactionID transaction.ID, payloadID payload.ID) *Attachment { return &Attachment{ - transactionId: transactionId, - payloadId: payloadId, + transactionID: transactionID, + payloadID: payloadID, storageKey: marshalutil.New(AttachmentLength). - WriteBytes(transactionId.Bytes()). - WriteBytes(payloadId.Bytes()). + WriteBytes(transactionID.Bytes()). + WriteBytes(payloadID.Bytes()). Bytes(), } } // AttachmentFromBytes unmarshals an Attachment from a sequence of bytes - it either creates a new object or fills the // optionally provided one with the parsed information. -func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (result *Attachment, err error, consumedBytes int) { +func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (result *Attachment, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseAttachment(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -43,20 +43,21 @@ func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (res return } -// Parse is a wrapper for simplified unmarshaling of Attachments from a byte stream using the marshalUtil package. +// ParseAttachment is a wrapper for simplified unmarshaling of Attachments from a byte stream using the marshalUtil package. func ParseAttachment(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Attachment) (result *Attachment, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return AttachmentFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*Attachment) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*Attachment) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -68,7 +69,7 @@ func ParseAttachment(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject // AttachmentFromStorageKey gets called when we restore an Attachment from the storage - it parses the key bytes and // returns the new object. -func AttachmentFromStorageKey(key []byte, optionalTargetObject ...*Attachment) (result *Attachment, err error, consumedBytes int) { +func AttachmentFromStorageKey(key []byte, optionalTargetObject ...*Attachment) (result *Attachment, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -81,10 +82,10 @@ func AttachmentFromStorageKey(key []byte, optionalTargetObject ...*Attachment) ( // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if result.transactionId, err = transaction.ParseId(marshalUtil); err != nil { + if result.transactionID, err = transaction.ParseID(marshalUtil); err != nil { return } - if result.payloadId, err = payload.ParseId(marshalUtil); err != nil { + if result.payloadID, err = payload.ParseID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() @@ -93,14 +94,14 @@ func AttachmentFromStorageKey(key []byte, optionalTargetObject ...*Attachment) ( return } -// TransactionId returns the transaction id of this Attachment. -func (attachment *Attachment) TransactionId() transaction.Id { - return attachment.transactionId +// TransactionID returns the transaction id of this Attachment. +func (attachment *Attachment) TransactionID() transaction.ID { + return attachment.transactionID } -// PayloadId returns the payload id of this Attachment. -func (attachment *Attachment) PayloadId() payload.Id { - return attachment.payloadId +// PayloadID returns the payload id of this Attachment. +func (attachment *Attachment) PayloadID() payload.ID { + return attachment.payloadID } // Bytes marshals the Attachment into a sequence of bytes. @@ -111,8 +112,8 @@ func (attachment *Attachment) Bytes() []byte { // String returns a human readable version of the Attachment. func (attachment *Attachment) String() string { return stringify.Struct("Attachment", - stringify.StructField("transactionId", attachment.TransactionId()), - stringify.StructField("payloadId", attachment.PayloadId()), + stringify.StructField("transactionId", attachment.TransactionID()), + stringify.StructField("payloadId", attachment.PayloadID()), ) } @@ -129,7 +130,7 @@ func (attachment *Attachment) ObjectStorageValue() (data []byte) { // UnmarshalObjectStorageValue unmarshals the "content part" of an Attachment from a sequence of bytes. Since all of the information // for this object are stored in its key, this method does nothing and is only required to conform with the interface. -func (attachment *Attachment) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (attachment *Attachment) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { return } @@ -142,39 +143,50 @@ func (attachment *Attachment) Update(other objectstorage.StorableObject) { var _ objectstorage.StorableObject = &Attachment{} // AttachmentLength holds the length of a marshaled Attachment in bytes. -const AttachmentLength = transaction.IdLength + payload.IdLength +const AttachmentLength = transaction.IDLength + payload.IDLength // region CachedAttachment ///////////////////////////////////////////////////////////////////////////////////////////// +// CachedAttachment is a wrapper for the generic CachedObject returned by the objectstorage, that overrides the accessor +// methods, with a type-casted one. type CachedAttachment struct { objectstorage.CachedObject } -// Retain overrides the underlying method to return a new CachedTransaction instead of a generic CachedObject. +// Retain marks this CachedObject to still be in use by the program. func (cachedAttachment *CachedAttachment) Retain() *CachedAttachment { return &CachedAttachment{cachedAttachment.CachedObject.Retain()} } +// Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. func (cachedAttachment *CachedAttachment) Unwrap() *Attachment { - if untypedObject := cachedAttachment.Get(); untypedObject == nil { + untypedObject := cachedAttachment.Get() + if untypedObject == nil { + return nil + } + + typedObject := untypedObject.(*Attachment) + if typedObject == nil || typedObject.IsDeleted() { return nil - } else { - if typedObject := untypedObject.(*Attachment); typedObject == nil || typedObject.IsDeleted() { - return nil - } else { - return typedObject - } } + + return typedObject } +// Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it +// exists). It automatically releases the object when the consumer finishes. func (cachedAttachment *CachedAttachment) Consume(consumer func(attachment *Attachment)) (consumed bool) { return cachedAttachment.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*Attachment)) }) } +// CachedAttachments represents a collection of CachedAttachments. type CachedAttachments []*CachedAttachment +// Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object +// is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at +// least one object was consumed. func (cachedAttachments CachedAttachments) Consume(consumer func(attachment *Attachment)) (consumed bool) { for _, cachedAttachment := range cachedAttachments { consumed = cachedAttachment.Consume(func(output *Attachment) { diff --git a/dapps/valuetransfers/packages/utxodag/consumer.go b/dapps/valuetransfers/packages/utxodag/consumer.go index 34a0ac2981c3b300b4c91128d78da8b0c5d9065f..bf73fc293ae9e1c695a3f0524668f18939daa230 100644 --- a/dapps/valuetransfers/packages/utxodag/consumer.go +++ b/dapps/valuetransfers/packages/utxodag/consumer.go @@ -9,35 +9,36 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" ) -var ConsumerPartitionKeys = objectstorage.PartitionKey([]int{address.Length, transaction.IdLength, transaction.IdLength}...) +// ConsumerPartitionKeys defines the "layout" of the key. This enables prefix iterations in the objectstorage. +var ConsumerPartitionKeys = objectstorage.PartitionKey([]int{address.Length, transaction.IDLength, transaction.IDLength}...) // Consumer stores the information which transaction output was consumed by which transaction. We need this to be able // to perform reverse lookups from transaction outputs to their corresponding consuming transactions. type Consumer struct { objectstorage.StorableObjectFlags - consumedInput transaction.OutputId - transactionId transaction.Id + consumedInput transaction.OutputID + transactionID transaction.ID storageKey []byte } // NewConsumer creates a Consumer object with the given information. -func NewConsumer(consumedInput transaction.OutputId, transactionId transaction.Id) *Consumer { +func NewConsumer(consumedInput transaction.OutputID, transactionID transaction.ID) *Consumer { return &Consumer{ consumedInput: consumedInput, - transactionId: transactionId, + transactionID: transactionID, storageKey: marshalutil.New(ConsumerLength). WriteBytes(consumedInput.Bytes()). - WriteBytes(transactionId.Bytes()). + WriteBytes(transactionID.Bytes()). Bytes(), } } // ConsumerFromBytes unmarshals a Consumer from a sequence of bytes - it either creates a new object or fills the // optionally provided one with the parsed information. -func ConsumerFromBytes(bytes []byte, optionalTargetObject ...*Consumer) (result *Consumer, err error, consumedBytes int) { +func ConsumerFromBytes(bytes []byte, optionalTargetObject ...*Consumer) (result *Consumer, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseConsumer(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -45,19 +46,21 @@ func ConsumerFromBytes(bytes []byte, optionalTargetObject ...*Consumer) (result return } +// ParseConsumer unmarshals a Consumer using the given marshalUtil (for easier marshaling/unmarshaling). func ParseConsumer(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Consumer) (result *Consumer, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ConsumerFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*Consumer) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*Consumer) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -67,7 +70,9 @@ func ParseConsumer(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject .. return } -func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (result *Consumer, err error, consumedBytes int) { +// ConsumerFromStorageKey is a factory method that creates a new Consumer instance from a storage key of the +// objectstorage. It is used by the objectstorage, to create new instances of this entity. +func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (result *Consumer, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -80,10 +85,10 @@ func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (resu // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if result.consumedInput, err = transaction.ParseOutputId(marshalUtil); err != nil { + if result.consumedInput, err = transaction.ParseOutputID(marshalUtil); err != nil { return } - if result.transactionId, err = transaction.ParseId(marshalUtil); err != nil { + if result.transactionID, err = transaction.ParseID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() @@ -92,14 +97,14 @@ func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (resu return } -// ConsumedInput returns the OutputId of the Consumer. -func (consumer *Consumer) ConsumedInput() transaction.OutputId { +// ConsumedInput returns the OutputID of the Consumer. +func (consumer *Consumer) ConsumedInput() transaction.OutputID { return consumer.consumedInput } -// TransactionId returns the transaction Id of this Consumer. -func (consumer *Consumer) TransactionId() transaction.Id { - return consumer.transactionId +// TransactionID returns the transaction ID of this Consumer. +func (consumer *Consumer) TransactionID() transaction.ID { + return consumer.transactionID } // Bytes marshals the Consumer into a sequence of bytes. @@ -111,7 +116,7 @@ func (consumer *Consumer) Bytes() []byte { func (consumer *Consumer) String() string { return stringify.Struct("Consumer", stringify.StructField("consumedInput", consumer.ConsumedInput()), - stringify.StructField("transactionId", consumer.TransactionId()), + stringify.StructField("transactionId", consumer.TransactionID()), ) } @@ -128,7 +133,7 @@ func (consumer *Consumer) ObjectStorageValue() (data []byte) { // UnmarshalObjectStorageValue unmarshals the "content part" of a Consumer from a sequence of bytes. Since all of the information // for this object are stored in its key, this method does nothing and is only required to conform with the interface. -func (consumer *Consumer) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (consumer *Consumer) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { return } @@ -141,34 +146,45 @@ func (consumer *Consumer) Update(other objectstorage.StorableObject) { var _ objectstorage.StorableObject = &Consumer{} // ConsumerLength holds the length of a marshaled Consumer in bytes. -const ConsumerLength = transaction.OutputIdLength + transaction.IdLength +const ConsumerLength = transaction.OutputIDLength + transaction.IDLength // region CachedConsumer ///////////////////////////////////////////////////////////////////////////////////////////////// +// CachedConsumer is a wrapper for the generic CachedObject returned by the objectstorage, that overrides the accessor +// methods, with a type-casted one. type CachedConsumer struct { objectstorage.CachedObject } +// Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. func (cachedConsumer *CachedConsumer) Unwrap() *Consumer { - if untypedObject := cachedConsumer.Get(); untypedObject == nil { + untypedObject := cachedConsumer.Get() + if untypedObject == nil { + return nil + } + + typedObject := untypedObject.(*Consumer) + if typedObject == nil || typedObject.IsDeleted() { return nil - } else { - if typedObject := untypedObject.(*Consumer); typedObject == nil || typedObject.IsDeleted() { - return nil - } else { - return typedObject - } } + + return typedObject } +// Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it +// exists). It automatically releases the object when the consumer finishes. func (cachedConsumer *CachedConsumer) Consume(consumer func(consumer *Consumer)) (consumed bool) { return cachedConsumer.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*Consumer)) }) } +// CachedConsumers represents a collection of CachedConsumers. type CachedConsumers []*CachedConsumer +// Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object +// is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at +// least one object was consumed. func (cachedConsumers CachedConsumers) Consume(consumer func(consumer *Consumer)) (consumed bool) { for _, cachedConsumer := range cachedConsumers { consumed = cachedConsumer.Consume(func(output *Consumer) { diff --git a/dapps/valuetransfers/packages/utxodag/events.go b/dapps/valuetransfers/packages/utxodag/events.go index 0ef598b64789d3d8c78803b10ce33e6f1403c137..4140bbf5b805ca8d1a45cf5ed7da7c672f8c9a74 100644 --- a/dapps/valuetransfers/packages/utxodag/events.go +++ b/dapps/valuetransfers/packages/utxodag/events.go @@ -7,11 +7,17 @@ import ( "github.com/iotaledger/hive.go/events" ) +// Events is a container for the different kind of events of the UTXODAG. type Events struct { - // Get's called whenever a transaction + // TransactionReceived gets triggered whenever a transaction was received for the first time (not solid yet). TransactionReceived *events.Event - TransactionBooked *events.Event - Fork *events.Event + + // TransactionBooked gets triggered whenever a transactions becomes solid and gets booked into a particular branch. + TransactionBooked *events.Event + + // Fork gets triggered when a previously un-conflicting transaction get's some of its inputs double spend, so that a + // new Branch is created. + Fork *events.Event } func newEvents() *Events { @@ -23,21 +29,21 @@ func newEvents() *Events { } func transactionBookedEvent(handler interface{}, params ...interface{}) { - handler.(func(*transaction.CachedTransaction, *CachedTransactionMetadata, *branchmanager.CachedBranch, []transaction.OutputId, bool))( + handler.(func(*transaction.CachedTransaction, *CachedTransactionMetadata, *branchmanager.CachedBranch, []transaction.OutputID, bool))( params[0].(*transaction.CachedTransaction).Retain(), params[1].(*CachedTransactionMetadata).Retain(), params[2].(*branchmanager.CachedBranch).Retain(), - params[3].([]transaction.OutputId), + params[3].([]transaction.OutputID), params[4].(bool), ) } func forkEvent(handler interface{}, params ...interface{}) { - handler.(func(*transaction.CachedTransaction, *CachedTransactionMetadata, *branchmanager.CachedBranch, []transaction.OutputId))( + handler.(func(*transaction.CachedTransaction, *CachedTransactionMetadata, *branchmanager.CachedBranch, []transaction.OutputID))( params[0].(*transaction.CachedTransaction).Retain(), params[1].(*CachedTransactionMetadata).Retain(), params[2].(*branchmanager.CachedBranch).Retain(), - params[3].([]transaction.OutputId), + params[3].([]transaction.OutputID), ) } diff --git a/dapps/valuetransfers/packages/utxodag/missingoutput.go b/dapps/valuetransfers/packages/utxodag/missingoutput.go index 976111b9a4f0ec8527c69b37dddacd1da92b4a20..74287574195d386a08e7d0d33c421ee82b9bc1d9 100644 --- a/dapps/valuetransfers/packages/utxodag/missingoutput.go +++ b/dapps/valuetransfers/packages/utxodag/missingoutput.go @@ -10,27 +10,28 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" ) -var MissingOutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, transaction.IdLength}...) +// MissingOutputKeyPartitions defines the "layout" of the key. This enables prefix iterations in the objectstorage. +var MissingOutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, transaction.IDLength}...) -// MissingPayload represents an Output that was referenced by a Transaction, but that is missing in our object storage. +// MissingOutput represents an Output that was referenced by a Transaction, but that is missing in our object storage. type MissingOutput struct { objectstorage.StorableObjectFlags - outputId transaction.OutputId + outputID transaction.OutputID missingSince time.Time } // NewMissingOutput creates a new MissingOutput object, that . -func NewMissingOutput(outputId transaction.OutputId) *MissingOutput { +func NewMissingOutput(outputID transaction.OutputID) *MissingOutput { return &MissingOutput{ - outputId: outputId, + outputID: outputID, missingSince: time.Now(), } } // MissingOutputFromBytes unmarshals a MissingOutput from a sequence of bytes - it either creates a new object or fills // the optionally provided one with the parsed information. -func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error, consumedBytes int) { +func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseMissingOutput(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -38,19 +39,21 @@ func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput return } +// ParseMissingOutput unmarshals a MissingOutput using the given marshalUtil (for easier marshaling/unmarshaling). func ParseMissingOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return MissingOutputFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*MissingOutput) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*MissingOutput) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -62,7 +65,7 @@ func ParseMissingOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObje // MissingOutputFromStorageKey gets called when we restore a MissingOutput from the storage. The content will be // unmarshaled by an external caller using the binary.ObjectStorageValue interface. -func MissingOutputFromStorageKey(key []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error, consumedBytes int) { +func MissingOutputFromStorageKey(key []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -75,16 +78,16 @@ func MissingOutputFromStorageKey(key []byte, optionalTargetObject ...*MissingOut // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) - if result.outputId, err = transaction.ParseOutputId(marshalUtil); err != nil { + if result.outputID, err = transaction.ParseOutputID(marshalUtil); err != nil { return } return } -// Id returns the id of the Output that is missing. -func (missingOutput *MissingOutput) Id() transaction.OutputId { - return missingOutput.outputId +// ID returns the id of the Output that is missing. +func (missingOutput *MissingOutput) ID() transaction.OutputID { + return missingOutput.outputID } // MissingSince returns the Time since the transaction was first reported as being missing. @@ -94,7 +97,7 @@ func (missingOutput *MissingOutput) MissingSince() time.Time { // Bytes marshals the MissingOutput into a sequence of bytes. func (missingOutput *MissingOutput) Bytes() []byte { - return marshalutil.New(transaction.OutputIdLength + marshalutil.TIME_SIZE). + return marshalutil.New(transaction.OutputIDLength + marshalutil.TIME_SIZE). WriteBytes(missingOutput.ObjectStorageKey()). WriteBytes(missingOutput.ObjectStorageValue()). Bytes() @@ -102,7 +105,7 @@ func (missingOutput *MissingOutput) Bytes() []byte { // ObjectStorageKey returns the key that is used to store the object in the object storage. func (missingOutput *MissingOutput) ObjectStorageKey() []byte { - return missingOutput.outputId.Bytes() + return missingOutput.outputID.Bytes() } // ObjectStorageValue returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler @@ -115,7 +118,7 @@ func (missingOutput *MissingOutput) ObjectStorageValue() []byte { // UnmarshalObjectStorageValue restores the values of a MissingOutput from a sequence of bytes using the encoding.BinaryUnmarshaler // interface. -func (missingOutput *MissingOutput) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (missingOutput *MissingOutput) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) if missingOutput.missingSince, err = marshalUtil.ReadTime(); err != nil { return diff --git a/dapps/valuetransfers/packages/utxodag/objectstorage.go b/dapps/valuetransfers/packages/utxodag/objectstorage.go index e3cb65c40acfb044eff7c57c3239f887a279e473..3cee1878bdd43fc6c858012bab9cf94bd9c54a64 100644 --- a/dapps/valuetransfers/packages/utxodag/objectstorage.go +++ b/dapps/valuetransfers/packages/utxodag/objectstorage.go @@ -27,22 +27,22 @@ var ( }) ) -func osTransactionFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osTransactionFactory(key []byte) (objectstorage.StorableObject, int, error) { return transaction.FromStorageKey(key) } -func osTransactionMetadataFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osTransactionMetadataFactory(key []byte) (objectstorage.StorableObject, int, error) { return TransactionMetadataFromStorageKey(key) } -func osAttachmentFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osAttachmentFactory(key []byte) (objectstorage.StorableObject, int, error) { return AttachmentFromStorageKey(key) } -func osOutputFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osOutputFactory(key []byte) (objectstorage.StorableObject, int, error) { return OutputFromStorageKey(key) } -func osConsumerFactory(key []byte) (objectstorage.StorableObject, error, int) { +func osConsumerFactory(key []byte) (objectstorage.StorableObject, int, error) { return ConsumerFromStorageKey(key) } diff --git a/dapps/valuetransfers/packages/utxodag/output.go b/dapps/valuetransfers/packages/utxodag/output.go index b24a11306a21ee1b71ce99759f6ff375df7cb62d..4af2154a99d5e1ddf2dd72870b44a6a783d0f6a0 100644 --- a/dapps/valuetransfers/packages/utxodag/output.go +++ b/dapps/valuetransfers/packages/utxodag/output.go @@ -14,20 +14,21 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" ) -var OutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, transaction.IdLength}...) +// OutputKeyPartitions defines the "layout" of the key. This enables prefix iterations in the objectstorage. +var OutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, transaction.IDLength}...) // Output represents the output of a Transaction and contains the balances and the identifiers for this output. type Output struct { address address.Address - transactionId transaction.Id - branchId branchmanager.BranchId + transactionID transaction.ID + branchID branchmanager.BranchID solid bool solidificationTime time.Time - firstConsumer transaction.Id + firstConsumer transaction.ID consumerCount int balances []*balance.Balance - branchIdMutex sync.RWMutex + branchIDMutex sync.RWMutex solidMutex sync.RWMutex solidificationTimeMutex sync.RWMutex consumerMutex sync.RWMutex @@ -37,22 +38,22 @@ type Output struct { } // NewOutput creates an Output that contains the balances and identifiers of a Transaction. -func NewOutput(address address.Address, transactionId transaction.Id, branchId branchmanager.BranchId, balances []*balance.Balance) *Output { +func NewOutput(address address.Address, transactionID transaction.ID, branchID branchmanager.BranchID, balances []*balance.Balance) *Output { return &Output{ address: address, - transactionId: transactionId, - branchId: branchId, + transactionID: transactionID, + branchID: branchID, solid: false, solidificationTime: time.Time{}, balances: balances, - storageKey: marshalutil.New().WriteBytes(address.Bytes()).WriteBytes(transactionId.Bytes()).Bytes(), + storageKey: marshalutil.New().WriteBytes(address.Bytes()).WriteBytes(transactionID.Bytes()).Bytes(), } } // OutputFromBytes unmarshals an Output object from a sequence of bytes. // It either creates a new object or fills the optionally provided object with the parsed information. -func OutputFromBytes(bytes []byte, optionalTargetObject ...*Output) (result *Output, err error, consumedBytes int) { +func OutputFromBytes(bytes []byte, optionalTargetObject ...*Output) (result *Output, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseOutput(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -60,19 +61,21 @@ func OutputFromBytes(bytes []byte, optionalTargetObject ...*Output) (result *Out return } +// ParseOutput unmarshals an Output using the given marshalUtil (for easier marshaling/unmarshaling). func ParseOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Output) (result *Output, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return OutputFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*Output) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*Output) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -85,7 +88,7 @@ func ParseOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...* // OutputFromStorageKey get's called when we restore a Output from the storage. // In contrast to other database models, it unmarshals some information from the key so we simply store the key before // it gets handed over to UnmarshalObjectStorageValue (by the ObjectStorage). -func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (result *Output, err error, consumedBytes int) { +func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (result *Output, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -102,18 +105,19 @@ func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (res if err != nil { return } - result.transactionId, err = transaction.ParseId(marshalUtil) + result.transactionID, err = transaction.ParseID(marshalUtil) if err != nil { return } - result.storageKey = marshalutil.New(keyBytes[:transaction.OutputIdLength]).Bytes(true) + result.storageKey = marshalutil.New(keyBytes[:transaction.OutputIDLength]).Bytes(true) consumedBytes = marshalUtil.ReadOffset() return } -func (output *Output) Id() transaction.OutputId { - return transaction.NewOutputId(output.Address(), output.TransactionId()) +// ID returns the identifier of this Output. +func (output *Output) ID() transaction.OutputID { + return transaction.NewOutputID(output.Address(), output.TransactionID()) } // Address returns the address that this output belongs to. @@ -121,36 +125,37 @@ func (output *Output) Address() address.Address { return output.address } -// TransactionId returns the id of the Transaction, that created this output. -func (output *Output) TransactionId() transaction.Id { - return output.transactionId +// TransactionID returns the id of the Transaction, that created this output. +func (output *Output) TransactionID() transaction.ID { + return output.transactionID } -// BranchId returns the id of the ledger state branch, that this output was booked in. -func (output *Output) BranchId() branchmanager.BranchId { - output.branchIdMutex.RLock() - defer output.branchIdMutex.RUnlock() +// BranchID returns the id of the ledger state branch, that this output was booked in. +func (output *Output) BranchID() branchmanager.BranchID { + output.branchIDMutex.RLock() + defer output.branchIDMutex.RUnlock() - return output.branchId + return output.branchID } -func (output *Output) SetBranchId(branchId branchmanager.BranchId) (modified bool) { - output.branchIdMutex.RLock() - if output.branchId == branchId { - output.branchIdMutex.RUnlock() +// SetBranchID is the setter for the property that indicates in which ledger state branch the output is booked. +func (output *Output) SetBranchID(branchID branchmanager.BranchID) (modified bool) { + output.branchIDMutex.RLock() + if output.branchID == branchID { + output.branchIDMutex.RUnlock() return } - output.branchIdMutex.RUnlock() - output.branchIdMutex.Lock() - defer output.branchIdMutex.Unlock() + output.branchIDMutex.RUnlock() + output.branchIDMutex.Lock() + defer output.branchIDMutex.Unlock() - if output.branchId == branchId { + if output.branchID == branchID { return } - output.branchId = branchId + output.branchID = branchID modified = true return @@ -164,6 +169,7 @@ func (output *Output) Solid() bool { return output.solid } +// SetSolid is the setter of the solid flag. It returns true if the solid flag was modified. func (output *Output) SetSolid(solid bool) (modified bool) { output.solidMutex.RLock() if output.solid != solid { @@ -191,6 +197,7 @@ func (output *Output) SetSolid(solid bool) (modified bool) { return } +// SolidificationTime returns the time when this Output was marked to be solid. func (output *Output) SolidificationTime() time.Time { output.solidificationTimeMutex.RLock() defer output.solidificationTimeMutex.RUnlock() @@ -198,7 +205,9 @@ func (output *Output) SolidificationTime() time.Time { return output.solidificationTime } -func (output *Output) RegisterConsumer(consumer transaction.Id) (consumerCount int, firstConsumerId transaction.Id) { +// RegisterConsumer keeps track of the first transaction, that consumed an Output and consequently keeps track of the +// amount of other transactions spending the same Output. +func (output *Output) RegisterConsumer(consumer transaction.ID) (consumerCount int, firstConsumerID transaction.ID) { output.consumerMutex.Lock() defer output.consumerMutex.Unlock() @@ -207,7 +216,7 @@ func (output *Output) RegisterConsumer(consumer transaction.Id) (consumerCount i } output.consumerCount++ - firstConsumerId = output.firstConsumer + firstConsumerID = output.firstConsumer return } @@ -228,9 +237,9 @@ func (output *Output) Bytes() []byte { // ObjectStorageKey returns the key that is used to store the object in the database. // It is required to match StorableObject interface. func (output *Output) ObjectStorageKey() []byte { - return marshalutil.New(transaction.OutputIdLength). + return marshalutil.New(transaction.OutputIDLength). WriteBytes(output.address.Bytes()). - WriteBytes(output.transactionId.Bytes()). + WriteBytes(output.transactionID.Bytes()). Bytes() } @@ -241,8 +250,8 @@ func (output *Output) ObjectStorageValue() []byte { balanceCount := len(output.balances) // initialize helper - marshalUtil := marshalutil.New(branchmanager.BranchIdLength + marshalutil.BOOL_SIZE + marshalutil.TIME_SIZE + marshalutil.UINT32_SIZE + balanceCount*balance.Length) - marshalUtil.WriteBytes(output.branchId.Bytes()) + marshalUtil := marshalutil.New(branchmanager.BranchIDLength + marshalutil.BOOL_SIZE + marshalutil.TIME_SIZE + marshalutil.UINT32_SIZE + balanceCount*balance.Length) + marshalUtil.WriteBytes(output.branchID.Bytes()) marshalUtil.WriteBool(output.solid) marshalUtil.WriteTime(output.solidificationTime) marshalUtil.WriteUint32(uint32(balanceCount)) @@ -255,9 +264,9 @@ func (output *Output) ObjectStorageValue() []byte { // UnmarshalObjectStorageValue restores a Output from a serialized version in the ObjectStorage with parts of the object // being stored in its key rather than the content of the database to reduce storage requirements. -func (output *Output) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (output *Output) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) - if output.branchId, err = branchmanager.ParseBranchId(marshalUtil); err != nil { + if output.branchID, err = branchmanager.ParseBranchID(marshalUtil); err != nil { return } if output.solid, err = marshalUtil.ReadBool(); err != nil { @@ -269,13 +278,12 @@ func (output *Output) UnmarshalObjectStorageValue(data []byte) (err error, consu var balanceCount uint32 if balanceCount, err = marshalUtil.ReadUint32(); err != nil { return - } else { - output.balances = make([]*balance.Balance, balanceCount) - for i := uint32(0); i < balanceCount; i++ { - output.balances[i], err = balance.Parse(marshalUtil) - if err != nil { - return - } + } + output.balances = make([]*balance.Balance, balanceCount) + for i := uint32(0); i < balanceCount; i++ { + output.balances[i], err = balance.Parse(marshalUtil) + if err != nil { + return } } consumedBytes = marshalUtil.ReadOffset() @@ -291,8 +299,8 @@ func (output *Output) Update(other objectstorage.StorableObject) { func (output *Output) String() string { return stringify.Struct("Output", stringify.StructField("address", output.Address()), - stringify.StructField("transactionId", output.TransactionId()), - stringify.StructField("branchId", output.BranchId()), + stringify.StructField("transactionId", output.TransactionID()), + stringify.StructField("branchId", output.BranchID()), stringify.StructField("solid", output.Solid()), stringify.StructField("solidificationTime", output.SolidificationTime()), stringify.StructField("balances", output.Balances()), @@ -304,30 +312,41 @@ var _ objectstorage.StorableObject = &Output{} // region CachedOutput ///////////////////////////////////////////////////////////////////////////////////////////////// +// CachedOutput is a wrapper for the generic CachedObject returned by the objectstorage, that overrides the accessor +// methods, with a type-casted one. type CachedOutput struct { objectstorage.CachedObject } +// Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. func (cachedOutput *CachedOutput) Unwrap() *Output { - if untypedObject := cachedOutput.Get(); untypedObject == nil { + untypedObject := cachedOutput.Get() + if untypedObject == nil { + return nil + } + + typedObject := untypedObject.(*Output) + if typedObject == nil || typedObject.IsDeleted() { return nil - } else { - if typedObject := untypedObject.(*Output); typedObject == nil || typedObject.IsDeleted() { - return nil - } else { - return typedObject - } } + + return typedObject } +// Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it +// exists). It automatically releases the object when the consumer finishes. func (cachedOutput *CachedOutput) Consume(consumer func(output *Output)) (consumed bool) { return cachedOutput.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*Output)) }) } -type CachedOutputs map[transaction.OutputId]*CachedOutput +// CachedOutputs represents a collection of CachedOutputs. +type CachedOutputs map[transaction.OutputID]*CachedOutput +// Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object +// is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at +// least one object was consumed. func (cachedOutputs CachedOutputs) Consume(consumer func(output *Output)) (consumed bool) { for _, cachedOutput := range cachedOutputs { consumed = cachedOutput.Consume(func(output *Output) { @@ -338,6 +357,7 @@ func (cachedOutputs CachedOutputs) Consume(consumer func(output *Output)) (consu return } +// Release is a utility function, that allows us to release all CachedObjects in the collection. func (cachedOutputs CachedOutputs) Release(force ...bool) { for _, cachedOutput := range cachedOutputs { cachedOutput.Release(force...) diff --git a/dapps/valuetransfers/packages/utxodag/transactionmetadata.go b/dapps/valuetransfers/packages/utxodag/transactionmetadata.go index d7f75b4998bd4b15668d838f6295678c6f7ff920..980860ef4fbfba409106e07bd97667fb6c187bc7 100644 --- a/dapps/valuetransfers/packages/utxodag/transactionmetadata.go +++ b/dapps/valuetransfers/packages/utxodag/transactionmetadata.go @@ -17,21 +17,21 @@ import ( type TransactionMetadata struct { objectstorage.StorableObjectFlags - id transaction.Id - branchId branchmanager.BranchId + id transaction.ID + branchID branchmanager.BranchID solid bool finalized bool solidificationTime time.Time finalizationTime time.Time - branchIdMutex sync.RWMutex + branchIDMutex sync.RWMutex solidMutex sync.RWMutex finalizedMutex sync.RWMutex solidificationTimeMutex sync.RWMutex } // NewTransactionMetadata is the constructor for the TransactionMetadata type. -func NewTransactionMetadata(id transaction.Id) *TransactionMetadata { +func NewTransactionMetadata(id transaction.ID) *TransactionMetadata { return &TransactionMetadata{ id: id, } @@ -39,7 +39,7 @@ func NewTransactionMetadata(id transaction.Id) *TransactionMetadata { // TransactionMetadataFromBytes unmarshals a TransactionMetadata object from a sequence of bytes. // It either creates a new object or fills the optionally provided object with the parsed information. -func TransactionMetadataFromBytes(bytes []byte, optionalTargetObject ...*TransactionMetadata) (result *TransactionMetadata, err error, consumedBytes int) { +func TransactionMetadataFromBytes(bytes []byte, optionalTargetObject ...*TransactionMetadata) (result *TransactionMetadata, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseTransactionMetadata(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() @@ -50,7 +50,7 @@ func TransactionMetadataFromBytes(bytes []byte, optionalTargetObject ...*Transac // TransactionMetadataFromStorageKey get's called when we restore TransactionMetadata from the storage. // In contrast to other database models, it unmarshals some information from the key so we simply store the key before // it gets handed over to UnmarshalObjectStorageValue (by the ObjectStorage). -func TransactionMetadataFromStorageKey(keyBytes []byte, optionalTargetObject ...*TransactionMetadata) (result *TransactionMetadata, err error, consumedBytes int) { +func TransactionMetadataFromStorageKey(keyBytes []byte, optionalTargetObject ...*TransactionMetadata) (result *TransactionMetadata, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -63,7 +63,7 @@ func TransactionMetadataFromStorageKey(keyBytes []byte, optionalTargetObject ... // parse information marshalUtil := marshalutil.New(keyBytes) - result.id, err = transaction.ParseId(marshalUtil) + result.id, err = transaction.ParseID(marshalUtil) if err != nil { return } @@ -72,20 +72,21 @@ func TransactionMetadataFromStorageKey(keyBytes []byte, optionalTargetObject ... return } -// Parse is a wrapper for simplified unmarshaling of TransactionMetadata objects from a byte stream using the marshalUtil package. +// ParseTransactionMetadata is a wrapper for simplified unmarshaling of TransactionMetadata objects from a byte stream using the marshalUtil package. func ParseTransactionMetadata(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*TransactionMetadata) (result *TransactionMetadata, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return TransactionMetadataFromStorageKey(data, optionalTargetObject...) - }); parseErr != nil { + }) + if parseErr != nil { err = parseErr return - } else { - result = parsedObject.(*TransactionMetadata) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + result = parsedObject.(*TransactionMetadata) + + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -95,35 +96,37 @@ func ParseTransactionMetadata(marshalUtil *marshalutil.MarshalUtil, optionalTarg return } -// Id return the id of the Transaction that this TransactionMetadata is associated to. -func (transactionMetadata *TransactionMetadata) Id() transaction.Id { +// ID return the id of the Transaction that this TransactionMetadata is associated to. +func (transactionMetadata *TransactionMetadata) ID() transaction.ID { return transactionMetadata.id } -func (transactionMetadata *TransactionMetadata) BranchId() branchmanager.BranchId { - transactionMetadata.branchIdMutex.RLock() - defer transactionMetadata.branchIdMutex.RUnlock() +// BranchID returns the identifier of the Branch, that this transaction is booked into. +func (transactionMetadata *TransactionMetadata) BranchID() branchmanager.BranchID { + transactionMetadata.branchIDMutex.RLock() + defer transactionMetadata.branchIDMutex.RUnlock() - return transactionMetadata.branchId + return transactionMetadata.branchID } -func (transactionMetadata *TransactionMetadata) SetBranchId(branchId branchmanager.BranchId) (modified bool) { - transactionMetadata.branchIdMutex.RLock() - if transactionMetadata.branchId == branchId { - transactionMetadata.branchIdMutex.RUnlock() +// SetBranchID is the setter for the branch id. It returns true if the value of the flag has been updated. +func (transactionMetadata *TransactionMetadata) SetBranchID(branchID branchmanager.BranchID) (modified bool) { + transactionMetadata.branchIDMutex.RLock() + if transactionMetadata.branchID == branchID { + transactionMetadata.branchIDMutex.RUnlock() return } - transactionMetadata.branchIdMutex.RUnlock() - transactionMetadata.branchIdMutex.Lock() - defer transactionMetadata.branchIdMutex.Unlock() + transactionMetadata.branchIDMutex.RUnlock() + transactionMetadata.branchIDMutex.Lock() + defer transactionMetadata.branchIDMutex.Unlock() - if transactionMetadata.branchId == branchId { + if transactionMetadata.branchID == branchID { return } - transactionMetadata.branchId = branchId + transactionMetadata.branchID = branchID modified = true return @@ -167,6 +170,8 @@ func (transactionMetadata *TransactionMetadata) SetSolid(solid bool) (modified b return } +// SetFinalized allows us to set the finalized flag on the transactions. Finalized transactions will not be forked when +// a conflict arrives later. func (transactionMetadata *TransactionMetadata) SetFinalized(finalized bool) (modified bool) { transactionMetadata.finalizedMutex.RLock() if transactionMetadata.finalized == finalized { @@ -192,6 +197,7 @@ func (transactionMetadata *TransactionMetadata) SetFinalized(finalized bool) (mo return } +// Finalized returns true, if the decision if this transaction is liked or not has been finalized by consensus already. func (transactionMetadata *TransactionMetadata) Finalized() bool { transactionMetadata.finalizedMutex.RLock() defer transactionMetadata.finalizedMutex.RUnlock() @@ -199,6 +205,7 @@ func (transactionMetadata *TransactionMetadata) Finalized() bool { return transactionMetadata.finalized } +// FinalizationTime returns the time when this transaction was finalized. func (transactionMetadata *TransactionMetadata) FinalizationTime() time.Time { transactionMetadata.finalizedMutex.RLock() defer transactionMetadata.finalizedMutex.RUnlock() @@ -216,8 +223,8 @@ func (transactionMetadata *TransactionMetadata) SoldificationTime() time.Time { // Bytes marshals the TransactionMetadata object into a sequence of bytes. func (transactionMetadata *TransactionMetadata) Bytes() []byte { - return marshalutil.New(branchmanager.BranchIdLength + 2*marshalutil.TIME_SIZE + 2*marshalutil.BOOL_SIZE). - WriteBytes(transactionMetadata.BranchId().Bytes()). + return marshalutil.New(branchmanager.BranchIDLength + 2*marshalutil.TIME_SIZE + 2*marshalutil.BOOL_SIZE). + WriteBytes(transactionMetadata.BranchID().Bytes()). WriteTime(transactionMetadata.solidificationTime). WriteTime(transactionMetadata.finalizationTime). WriteBool(transactionMetadata.solid). @@ -228,8 +235,8 @@ func (transactionMetadata *TransactionMetadata) Bytes() []byte { // String creates a human readable version of the metadata (for debug purposes). func (transactionMetadata *TransactionMetadata) String() string { return stringify.Struct("transaction.TransactionMetadata", - stringify.StructField("id", transactionMetadata.Id()), - stringify.StructField("branchId", transactionMetadata.BranchId()), + stringify.StructField("id", transactionMetadata.ID()), + stringify.StructField("branchId", transactionMetadata.BranchID()), stringify.StructField("solid", transactionMetadata.Solid()), stringify.StructField("solidificationTime", transactionMetadata.SoldificationTime()), ) @@ -253,9 +260,9 @@ func (transactionMetadata *TransactionMetadata) ObjectStorageValue() []byte { // UnmarshalObjectStorageValue restores the values of a TransactionMetadata object from a sequence of bytes and matches the // encoding.BinaryUnmarshaler interface. -func (transactionMetadata *TransactionMetadata) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (transactionMetadata *TransactionMetadata) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) - if transactionMetadata.branchId, err = branchmanager.ParseBranchId(marshalUtil); err != nil { + if transactionMetadata.branchID, err = branchmanager.ParseBranchID(marshalUtil); err != nil { return } if transactionMetadata.solidificationTime, err = marshalUtil.ReadTime(); err != nil { @@ -299,15 +306,17 @@ func (cachedTransactionMetadata *CachedTransactionMetadata) Consume(consumer fun // Unwrap provides a way to retrieve a type casted version of the underlying object. func (cachedTransactionMetadata *CachedTransactionMetadata) Unwrap() *TransactionMetadata { - if untypedTransaction := cachedTransactionMetadata.Get(); untypedTransaction == nil { + untypedTransaction := cachedTransactionMetadata.Get() + if untypedTransaction == nil { return nil - } else { - if typeCastedTransaction := untypedTransaction.(*TransactionMetadata); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { - return nil - } else { - return typeCastedTransaction - } } + + typeCastedTransaction := untypedTransaction.(*TransactionMetadata) + if typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() { + return nil + } + + return typeCastedTransaction } // Interface contract: make compiler warn if the interface is not implemented correctly. diff --git a/dapps/valuetransfers/packages/utxodag/utxodag.go b/dapps/valuetransfers/packages/utxodag/utxodag.go index e27c6cfa1f82194115c1730e756e4b04f3d3bbba..5148eecd8e5d75691454fcde04e3b30cb074cb8e 100644 --- a/dapps/valuetransfers/packages/utxodag/utxodag.go +++ b/dapps/valuetransfers/packages/utxodag/utxodag.go @@ -22,6 +22,8 @@ import ( "github.com/iotaledger/goshimmer/packages/binary/storageprefix" ) +// UTXODAG represents the DAG of funds that are flowing from the genesis, to the addresses that have balance now, that +// is embedded as another layer in the message tangle. type UTXODAG struct { tangle *tangle.Tangle branchManager *branchmanager.BranchManager @@ -37,6 +39,7 @@ type UTXODAG struct { workerPool async.WorkerPool } +// New is the constructor of the UTXODAG and creates a new DAG on top a tangle. func New(badgerInstance *badger.DB, tangle *tangle.Tangle) (result *UTXODAG) { osFactory := objectstorage.NewFactory(badgerInstance, storageprefix.ValueTransfers) @@ -58,47 +61,51 @@ func New(badgerInstance *badger.DB, tangle *tangle.Tangle) (result *UTXODAG) { return } +// BranchManager is the getter for the manager that takes care of creating and updating branches. func (utxoDAG *UTXODAG) BranchManager() *branchmanager.BranchManager { return utxoDAG.branchManager } +// ProcessSolidPayload is the main method of this struct. It is used to add new solid Payloads to the DAG. func (utxoDAG *UTXODAG) ProcessSolidPayload(cachedPayload *payload.CachedPayload, cachedMetadata *tangle.CachedPayloadMetadata) { utxoDAG.workerPool.Submit(func() { utxoDAG.storeTransactionWorker(cachedPayload, cachedMetadata) }) } -func (utxoDAG *UTXODAG) Transaction(transactionId transaction.Id) *transaction.CachedTransaction { - return &transaction.CachedTransaction{CachedObject: utxoDAG.transactionStorage.Load(transactionId.Bytes())} +// Transaction loads the given transaction from the objectstorage. +func (utxoDAG *UTXODAG) Transaction(transactionID transaction.ID) *transaction.CachedTransaction { + return &transaction.CachedTransaction{CachedObject: utxoDAG.transactionStorage.Load(transactionID.Bytes())} } -// GetPayloadMetadata retrieves the metadata of a value payload from the object storage. -func (utxoDAG *UTXODAG) TransactionMetadata(transactionId transaction.Id) *CachedTransactionMetadata { - return &CachedTransactionMetadata{CachedObject: utxoDAG.transactionMetadataStorage.Load(transactionId.Bytes())} +// TransactionMetadata retrieves the metadata of a value payload from the object storage. +func (utxoDAG *UTXODAG) TransactionMetadata(transactionID transaction.ID) *CachedTransactionMetadata { + return &CachedTransactionMetadata{CachedObject: utxoDAG.transactionMetadataStorage.Load(transactionID.Bytes())} } -func (utxoDAG *UTXODAG) GetTransactionOutput(outputId transaction.OutputId) *CachedOutput { - return &CachedOutput{CachedObject: utxoDAG.outputStorage.Load(outputId.Bytes())} +// TransactionOutput loads the given output from the objectstorage. +func (utxoDAG *UTXODAG) TransactionOutput(outputID transaction.OutputID) *CachedOutput { + return &CachedOutput{CachedObject: utxoDAG.outputStorage.Load(outputID.Bytes())} } // GetConsumers retrieves the approvers of a payload from the object storage. -func (utxoDAG *UTXODAG) GetConsumers(outputId transaction.OutputId) CachedConsumers { +func (utxoDAG *UTXODAG) GetConsumers(outputID transaction.OutputID) CachedConsumers { consumers := make(CachedConsumers, 0) utxoDAG.consumerStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { consumers = append(consumers, &CachedConsumer{CachedObject: cachedObject}) return true - }, outputId.Bytes()) + }, outputID.Bytes()) return consumers } // GetAttachments retrieves the att of a payload from the object storage. -func (utxoDAG *UTXODAG) GetAttachments(transactionId transaction.Id) CachedAttachments { +func (utxoDAG *UTXODAG) GetAttachments(transactionID transaction.ID) CachedAttachments { attachments := make(CachedAttachments, 0) utxoDAG.attachmentStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool { attachments = append(attachments, &CachedAttachment{CachedObject: cachedObject}) return true - }, transactionId.Bytes()) + }, transactionID.Bytes()) return attachments } @@ -166,7 +173,7 @@ func (utxoDAG *UTXODAG) storeTransactionWorker(cachedPayload *payload.CachedPayl } func (utxoDAG *UTXODAG) storeTransactionModels(solidPayload *payload.Payload) (cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *CachedTransactionMetadata, cachedAttachment *CachedAttachment, transactionIsNew bool) { - cachedTransaction = &transaction.CachedTransaction{CachedObject: utxoDAG.transactionStorage.ComputeIfAbsent(solidPayload.Transaction().Id().Bytes(), func(key []byte) objectstorage.StorableObject { + cachedTransaction = &transaction.CachedTransaction{CachedObject: utxoDAG.transactionStorage.ComputeIfAbsent(solidPayload.Transaction().ID().Bytes(), func(key []byte) objectstorage.StorableObject { transactionIsNew = true result := solidPayload.Transaction() @@ -177,20 +184,20 @@ func (utxoDAG *UTXODAG) storeTransactionModels(solidPayload *payload.Payload) (c })} if transactionIsNew { - cachedTransactionMetadata = &CachedTransactionMetadata{CachedObject: utxoDAG.transactionMetadataStorage.Store(NewTransactionMetadata(solidPayload.Transaction().Id()))} + cachedTransactionMetadata = &CachedTransactionMetadata{CachedObject: utxoDAG.transactionMetadataStorage.Store(NewTransactionMetadata(solidPayload.Transaction().ID()))} // store references to the consumed outputs - solidPayload.Transaction().Inputs().ForEach(func(outputId transaction.OutputId) bool { - utxoDAG.consumerStorage.Store(NewConsumer(outputId, solidPayload.Transaction().Id())).Release() + solidPayload.Transaction().Inputs().ForEach(func(outputId transaction.OutputID) bool { + utxoDAG.consumerStorage.Store(NewConsumer(outputId, solidPayload.Transaction().ID())).Release() return true }) } else { - cachedTransactionMetadata = &CachedTransactionMetadata{CachedObject: utxoDAG.transactionMetadataStorage.Load(solidPayload.Transaction().Id().Bytes())} + cachedTransactionMetadata = &CachedTransactionMetadata{CachedObject: utxoDAG.transactionMetadataStorage.Load(solidPayload.Transaction().ID().Bytes())} } // store a reference from the transaction to the payload that attached it or abort, if we have processed this attachment already - attachment, stored := utxoDAG.attachmentStorage.StoreIfAbsent(NewAttachment(solidPayload.Transaction().Id(), solidPayload.Id())) + attachment, stored := utxoDAG.attachmentStorage.StoreIfAbsent(NewAttachment(solidPayload.Transaction().ID(), solidPayload.ID())) if !stored { return } @@ -286,7 +293,7 @@ func (utxoDAG *UTXODAG) isTransactionSolid(tx *transaction.Transaction, metadata } if !utxoDAG.checkTransactionOutputs(consumedBalances, tx.Outputs()) { - return false, fmt.Errorf("the outputs do not match the inputs in transaction with id '%s'", tx.Id()) + return false, fmt.Errorf("the outputs do not match the inputs in transaction with id '%s'", tx.ID()) } return true, nil @@ -294,8 +301,8 @@ func (utxoDAG *UTXODAG) isTransactionSolid(tx *transaction.Transaction, metadata func (utxoDAG *UTXODAG) getCachedOutputsFromTransactionInputs(tx *transaction.Transaction) (result CachedOutputs) { result = make(CachedOutputs) - tx.Inputs().ForEach(func(inputId transaction.OutputId) bool { - result[inputId] = utxoDAG.GetTransactionOutput(inputId) + tx.Inputs().ForEach(func(inputId transaction.OutputID) bool { + result[inputId] = utxoDAG.TransactionOutput(inputId) return true }) @@ -413,16 +420,17 @@ func (utxoDAG *UTXODAG) checkTransactionOutputs(inputBalances map[balance.Color] return unspentCoins == newlyColoredCoins } +// ForEachConsumers iterates through the transactions that are consuming outputs of the given transactions func (utxoDAG *UTXODAG) ForEachConsumers(currentTransaction *transaction.Transaction, consume func(cachedTransaction *transaction.CachedTransaction, transactionMetadata *CachedTransactionMetadata, cachedAttachment *CachedAttachment)) { - seenTransactions := make(map[transaction.Id]types.Empty) + seenTransactions := make(map[transaction.ID]types.Empty) currentTransaction.Outputs().ForEach(func(address address.Address, balances []*balance.Balance) bool { - utxoDAG.GetConsumers(transaction.NewOutputId(address, currentTransaction.Id())).Consume(func(consumer *Consumer) { - if _, transactionSeen := seenTransactions[consumer.TransactionId()]; !transactionSeen { - seenTransactions[consumer.TransactionId()] = types.Void + utxoDAG.GetConsumers(transaction.NewOutputID(address, currentTransaction.ID())).Consume(func(consumer *Consumer) { + if _, transactionSeen := seenTransactions[consumer.TransactionID()]; !transactionSeen { + seenTransactions[consumer.TransactionID()] = types.Void - cachedTransaction := utxoDAG.Transaction(consumer.TransactionId()) - cachedTransactionMetadata := utxoDAG.TransactionMetadata(consumer.TransactionId()) - for _, cachedAttachment := range utxoDAG.GetAttachments(consumer.TransactionId()) { + cachedTransaction := utxoDAG.Transaction(consumer.TransactionID()) + cachedTransactionMetadata := utxoDAG.TransactionMetadata(consumer.TransactionID()) + for _, cachedAttachment := range utxoDAG.GetAttachments(consumer.TransactionID()) { consume(cachedTransaction, cachedTransactionMetadata, cachedAttachment) } } @@ -451,11 +459,11 @@ func (utxoDAG *UTXODAG) bookTransaction(cachedTransaction *transaction.CachedTra } consumedBranches := make(branchmanager.BranchIds) - conflictingInputs := make([]transaction.OutputId, 0) - conflictingInputsOfConflictingConsumers := make(map[transaction.Id][]transaction.OutputId) + conflictingInputs := make([]transaction.OutputID, 0) + conflictingInputsOfConflictingConsumers := make(map[transaction.ID][]transaction.OutputID) - if !transactionToBook.Inputs().ForEach(func(outputId transaction.OutputId) bool { - cachedOutput := utxoDAG.GetTransactionOutput(outputId) + if !transactionToBook.Inputs().ForEach(func(outputId transaction.OutputID) bool { + cachedOutput := utxoDAG.TransactionOutput(outputId) defer cachedOutput.Release() // abort if the output could not be found @@ -466,10 +474,10 @@ func (utxoDAG *UTXODAG) bookTransaction(cachedTransaction *transaction.CachedTra return false } - consumedBranches[output.BranchId()] = types.Void + consumedBranches[output.BranchID()] = types.Void // continue if we are the first consumer and there is no double spend - consumerCount, firstConsumerId := output.RegisterConsumer(transactionToBook.Id()) + consumerCount, firstConsumerID := output.RegisterConsumer(transactionToBook.ID()) if consumerCount == 0 { return true } @@ -479,11 +487,11 @@ func (utxoDAG *UTXODAG) bookTransaction(cachedTransaction *transaction.CachedTra // also keep track of conflicting inputs of previous consumers if consumerCount == 1 { - if _, conflictingInputsExist := conflictingInputsOfConflictingConsumers[firstConsumerId]; !conflictingInputsExist { - conflictingInputsOfConflictingConsumers[firstConsumerId] = make([]transaction.OutputId, 0) + if _, conflictingInputsExist := conflictingInputsOfConflictingConsumers[firstConsumerID]; !conflictingInputsExist { + conflictingInputsOfConflictingConsumers[firstConsumerID] = make([]transaction.OutputID, 0) } - conflictingInputsOfConflictingConsumers[firstConsumerId] = append(conflictingInputsOfConflictingConsumers[firstConsumerId], outputId) + conflictingInputsOfConflictingConsumers[firstConsumerID] = append(conflictingInputsOfConflictingConsumers[firstConsumerID], outputId) } return true @@ -501,7 +509,7 @@ func (utxoDAG *UTXODAG) bookTransaction(cachedTransaction *transaction.CachedTra targetBranch.Persist() if len(conflictingInputs) >= 1 { - cachedTargetBranch = utxoDAG.branchManager.AddBranch(branchmanager.NewBranch(branchmanager.NewBranchId(transactionToBook.Id()), []branchmanager.BranchId{targetBranch.Id()}, conflictingInputs)) + cachedTargetBranch = utxoDAG.branchManager.AddBranch(branchmanager.NewBranch(branchmanager.NewBranchID(transactionToBook.ID()), []branchmanager.BranchID{targetBranch.ID()}, conflictingInputs)) defer cachedTargetBranch.Release() targetBranch = cachedTargetBranch.Unwrap() @@ -518,11 +526,11 @@ func (utxoDAG *UTXODAG) bookTransaction(cachedTransaction *transaction.CachedTra } // book transaction into target reality - transactionMetadata.SetBranchId(targetBranch.Id()) + transactionMetadata.SetBranchID(targetBranch.ID()) // book outputs into the target branch transactionToBook.Outputs().ForEach(func(address address.Address, balances []*balance.Balance) bool { - newOutput := NewOutput(address, transactionToBook.Id(), targetBranch.Id(), balances) + newOutput := NewOutput(address, transactionToBook.ID(), targetBranch.ID(), balances) newOutput.SetSolid(true) utxoDAG.outputStorage.Store(newOutput).Release() @@ -531,8 +539,8 @@ func (utxoDAG *UTXODAG) bookTransaction(cachedTransaction *transaction.CachedTra // fork the conflicting transactions into their own branch previousConsumerForked := false - for consumerId, conflictingInputs := range conflictingInputsOfConflictingConsumers { - consumerForked, forkedErr := utxoDAG.Fork(consumerId, conflictingInputs) + for consumerID, conflictingInputs := range conflictingInputsOfConflictingConsumers { + consumerForked, forkedErr := utxoDAG.Fork(consumerID, conflictingInputs) if forkedErr != nil { err = forkedErr @@ -552,8 +560,8 @@ func (utxoDAG *UTXODAG) bookTransaction(cachedTransaction *transaction.CachedTra func (utxoDAG *UTXODAG) calculateBranchOfTransaction(currentTransaction *transaction.Transaction) (branch *branchmanager.CachedBranch, err error) { consumedBranches := make(branchmanager.BranchIds) - if !currentTransaction.Inputs().ForEach(func(outputId transaction.OutputId) bool { - cachedTransactionOutput := utxoDAG.GetTransactionOutput(outputId) + if !currentTransaction.Inputs().ForEach(func(outputId transaction.OutputID) bool { + cachedTransactionOutput := utxoDAG.TransactionOutput(outputId) defer cachedTransactionOutput.Release() transactionOutput := cachedTransactionOutput.Unwrap() @@ -563,7 +571,7 @@ func (utxoDAG *UTXODAG) calculateBranchOfTransaction(currentTransaction *transac return false } - consumedBranches[transactionOutput.BranchId()] = types.Void + consumedBranches[transactionOutput.BranchID()] = types.Void return true }) { @@ -579,7 +587,7 @@ func (utxoDAG *UTXODAG) moveTransactionToBranch(cachedTransaction *transaction.C // push transaction that shall be moved to the stack transactionStack := list.New() branchStack := list.New() - branchStack.PushBack([3]interface{}{cachedTransactionMetadata.Unwrap().BranchId(), cachedTargetBranch, transactionStack}) + branchStack.PushBack([3]interface{}{cachedTransactionMetadata.Unwrap().BranchID(), cachedTargetBranch, transactionStack}) transactionStack.PushBack([2]interface{}{cachedTransaction, cachedTransactionMetadata}) // iterate through all transactions (grouped by their branch) @@ -587,7 +595,7 @@ func (utxoDAG *UTXODAG) moveTransactionToBranch(cachedTransaction *transaction.C if err = func() error { // retrieve branch details from stack currentSolidificationEntry := branchStack.Front() - currentSourceBranch := currentSolidificationEntry.Value.([3]interface{})[0].(branchmanager.BranchId) + currentSourceBranch := currentSolidificationEntry.Value.([3]interface{})[0].(branchmanager.BranchID) currentCachedTargetBranch := currentSolidificationEntry.Value.([3]interface{})[1].(*branchmanager.CachedBranch) transactionStack := currentSolidificationEntry.Value.([3]interface{})[2].(*list.List) branchStack.Remove(currentSolidificationEntry) @@ -623,7 +631,7 @@ func (utxoDAG *UTXODAG) moveTransactionToBranch(cachedTransaction *transaction.C } // if we arrived at a nested branch - if currentTransactionMetadata.BranchId() != currentSourceBranch { + if currentTransactionMetadata.BranchID() != currentSourceBranch { // determine the new branch of the transaction newCachedTargetBranch, branchErr := utxoDAG.calculateBranchOfTransaction(currentTransaction) if branchErr != nil { @@ -641,45 +649,45 @@ func (utxoDAG *UTXODAG) moveTransactionToBranch(cachedTransaction *transaction.C // add the new branch (with the current transaction as a starting point to the branch stack) newTransactionStack := list.New() newTransactionStack.PushBack([2]interface{}{currentCachedTransaction.Retain(), currentCachedTransactionMetadata.Retain()}) - branchStack.PushBack([3]interface{}{currentTransactionMetadata.BranchId(), newCachedTargetBranch.Retain(), newTransactionStack}) + branchStack.PushBack([3]interface{}{currentTransactionMetadata.BranchID(), newCachedTargetBranch.Retain(), newTransactionStack}) return nil } // abort if we did not modify the branch of the transaction - if !currentTransactionMetadata.SetBranchId(targetBranch.Id()) { + if !currentTransactionMetadata.SetBranchID(targetBranch.ID()) { return nil } // iterate through the outputs of the moved transaction currentTransaction.Outputs().ForEach(func(address address.Address, balances []*balance.Balance) bool { // create reference to the output - outputId := transaction.NewOutputId(address, currentTransaction.Id()) + outputID := transaction.NewOutputID(address, currentTransaction.ID()) // load output from database - cachedOutput := utxoDAG.GetTransactionOutput(outputId) + cachedOutput := utxoDAG.TransactionOutput(outputID) defer cachedOutput.Release() // unwrap output output := cachedOutput.Unwrap() if output == nil { - err = fmt.Errorf("failed to load output '%s'", outputId) + err = fmt.Errorf("failed to load output '%s'", outputID) return false } // abort if the output was moved already - if !output.SetBranchId(targetBranch.Id()) { + if !output.SetBranchID(targetBranch.ID()) { return true } // schedule consumers for further checks - consumingTransactions := make(map[transaction.Id]types.Empty) - utxoDAG.GetConsumers(transaction.NewOutputId(address, currentTransaction.Id())).Consume(func(consumer *Consumer) { - consumingTransactions[consumer.TransactionId()] = types.Void + consumingTransactions := make(map[transaction.ID]types.Empty) + utxoDAG.GetConsumers(transaction.NewOutputID(address, currentTransaction.ID())).Consume(func(consumer *Consumer) { + consumingTransactions[consumer.TransactionID()] = types.Void }) - for transactionId := range consumingTransactions { - transactionStack.PushBack([2]interface{}{utxoDAG.Transaction(transactionId), utxoDAG.TransactionMetadata(transactionId)}) + for transactionID := range consumingTransactions { + transactionStack.PushBack([2]interface{}{utxoDAG.Transaction(transactionID), utxoDAG.TransactionMetadata(transactionID)}) } return true @@ -700,21 +708,22 @@ func (utxoDAG *UTXODAG) moveTransactionToBranch(cachedTransaction *transaction.C return } -func (utxoDAG *UTXODAG) Fork(transactionId transaction.Id, conflictingInputs []transaction.OutputId) (forked bool, err error) { - cachedTransaction := utxoDAG.Transaction(transactionId) - cachedTransactionMetadata := utxoDAG.TransactionMetadata(transactionId) +// Fork creates a new branch from an existing transaction. +func (utxoDAG *UTXODAG) Fork(transactionID transaction.ID, conflictingInputs []transaction.OutputID) (forked bool, err error) { + cachedTransaction := utxoDAG.Transaction(transactionID) + cachedTransactionMetadata := utxoDAG.TransactionMetadata(transactionID) defer cachedTransaction.Release() defer cachedTransactionMetadata.Release() tx := cachedTransaction.Unwrap() if tx == nil { - err = fmt.Errorf("failed to load transaction '%s'", transactionId) + err = fmt.Errorf("failed to load transaction '%s'", transactionID) return } txMetadata := cachedTransactionMetadata.Unwrap() if txMetadata == nil { - err = fmt.Errorf("failed to load metadata of transaction '%s'", transactionId) + err = fmt.Errorf("failed to load metadata of transaction '%s'", transactionID) return } @@ -724,12 +733,12 @@ func (utxoDAG *UTXODAG) Fork(transactionId transaction.Id, conflictingInputs []t return } - cachedTargetBranch := utxoDAG.branchManager.AddBranch(branchmanager.NewBranch(branchmanager.NewBranchId(tx.Id()), []branchmanager.BranchId{txMetadata.BranchId()}, conflictingInputs)) + cachedTargetBranch := utxoDAG.branchManager.AddBranch(branchmanager.NewBranch(branchmanager.NewBranchID(tx.ID()), []branchmanager.BranchID{txMetadata.BranchID()}, conflictingInputs)) defer cachedTargetBranch.Release() targetBranch := cachedTargetBranch.Unwrap() if targetBranch == nil { - err = fmt.Errorf("failed to create branch for transaction '%s'", transactionId) + err = fmt.Errorf("failed to create branch for transaction '%s'", transactionID) return } diff --git a/dapps/valuetransfers/packages/utxodag/utxodag_test.go b/dapps/valuetransfers/packages/utxodag/utxodag_test.go index 4c7ab856a4bab8506062558a322ee5337735e660..4db41241e32c185c4ea0fe3ba7af431c2ea7b95c 100644 --- a/dapps/valuetransfers/packages/utxodag/utxodag_test.go +++ b/dapps/valuetransfers/packages/utxodag/utxodag_test.go @@ -22,14 +22,14 @@ import ( func TestNewOutput(t *testing.T) { randomAddress := address.Random() - randomTransactionId := transaction.RandomId() + randomTransactionID := transaction.RandomID() - output := NewOutput(randomAddress, randomTransactionId, branchmanager.MasterBranchId, []*balance.Balance{ + output := NewOutput(randomAddress, randomTransactionID, branchmanager.MasterBranchID, []*balance.Balance{ balance.New(balance.ColorIOTA, 1337), }) assert.Equal(t, randomAddress, output.Address()) - assert.Equal(t, randomTransactionId, output.TransactionId()) + assert.Equal(t, randomTransactionID, output.TransactionID()) assert.Equal(t, false, output.Solid()) assert.Equal(t, time.Time{}, output.SolidificationTime()) assert.Equal(t, []*balance.Balance{ @@ -41,35 +41,35 @@ func TestNewOutput(t *testing.T) { assert.Equal(t, true, output.Solid()) assert.NotEqual(t, time.Time{}, output.SolidificationTime()) - clonedOutput, err, _ := OutputFromBytes(output.Bytes()) + clonedOutput, _, err := OutputFromBytes(output.Bytes()) if err != nil { panic(err) } assert.Equal(t, output.Address(), clonedOutput.Address()) - assert.Equal(t, output.TransactionId(), clonedOutput.TransactionId()) + assert.Equal(t, output.TransactionID(), clonedOutput.TransactionID()) assert.Equal(t, output.Solid(), clonedOutput.Solid()) assert.Equal(t, output.SolidificationTime().Round(time.Second), clonedOutput.SolidificationTime().Round(time.Second)) assert.Equal(t, output.Balances(), clonedOutput.Balances()) } func TestAttachment(t *testing.T) { - transactionId := transaction.RandomId() - payloadId := payload.RandomId() + transactionID := transaction.RandomID() + payloadID := payload.RandomID() - attachment := NewAttachment(transactionId, payloadId) + attachment := NewAttachment(transactionID, payloadID) - assert.Equal(t, transactionId, attachment.TransactionId()) - assert.Equal(t, payloadId, attachment.PayloadId()) + assert.Equal(t, transactionID, attachment.TransactionID()) + assert.Equal(t, payloadID, attachment.PayloadID()) - clonedAttachment, err, consumedBytes := AttachmentFromBytes(attachment.Bytes()) + clonedAttachment, consumedBytes, err := AttachmentFromBytes(attachment.Bytes()) if err != nil { panic(err) } assert.Equal(t, AttachmentLength, consumedBytes) - assert.Equal(t, transactionId, clonedAttachment.TransactionId()) - assert.Equal(t, payloadId, clonedAttachment.PayloadId()) + assert.Equal(t, transactionID, clonedAttachment.TransactionID()) + assert.Equal(t, payloadID, clonedAttachment.PayloadID()) } func TestTangle_AttachPayload(t *testing.T) { @@ -91,14 +91,14 @@ func TestTangle_AttachPayload(t *testing.T) { addressKeyPair1 := ed25519.GenerateKeyPair() addressKeyPair2 := ed25519.GenerateKeyPair() - transferId1, _ := transaction.IdFromBase58("8opHzTAnfzRpPEx21XtnrVTX28YQuCpAjcn1PczScKh") - transferId2, _ := transaction.IdFromBase58("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") + transferID1, _ := transaction.IDFromBase58("8opHzTAnfzRpPEx21XtnrVTX28YQuCpAjcn1PczScKh") + transferID2, _ := transaction.IDFromBase58("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM") - input1 := NewOutput(address.FromED25519PubKey(addressKeyPair1.PublicKey), transferId1, branchmanager.MasterBranchId, []*balance.Balance{ + input1 := NewOutput(address.FromED25519PubKey(addressKeyPair1.PublicKey), transferID1, branchmanager.MasterBranchID, []*balance.Balance{ balance.New(balance.ColorIOTA, 337), }) input1.SetSolid(true) - input2 := NewOutput(address.FromED25519PubKey(addressKeyPair2.PublicKey), transferId2, branchmanager.MasterBranchId, []*balance.Balance{ + input2 := NewOutput(address.FromED25519PubKey(addressKeyPair2.PublicKey), transferID2, branchmanager.MasterBranchID, []*balance.Balance{ balance.New(balance.ColorIOTA, 1000), }) input2.SetSolid(true) @@ -110,10 +110,10 @@ func TestTangle_AttachPayload(t *testing.T) { outputAddress2 := address.Random() // attach first spend - valueTangle.AttachPayload(payload.New(payload.GenesisId, payload.GenesisId, transaction.New( + valueTangle.AttachPayload(payload.New(payload.GenesisID, payload.GenesisID, transaction.New( transaction.NewInputs( - input1.Id(), - input2.Id(), + input1.ID(), + input2.ID(), ), transaction.NewOutputs(map[address.Address][]*balance.Balance{ @@ -124,10 +124,10 @@ func TestTangle_AttachPayload(t *testing.T) { ))) // attach double spend - valueTangle.AttachPayload(payload.New(payload.GenesisId, payload.GenesisId, transaction.New( + valueTangle.AttachPayload(payload.New(payload.GenesisID, payload.GenesisID, transaction.New( transaction.NewInputs( - input1.Id(), - input2.Id(), + input1.ID(), + input2.ID(), ), transaction.NewOutputs(map[address.Address][]*balance.Balance{ diff --git a/go.mod b/go.mod index 74d38eccada4cb2a2c8ba31e6b7780ca5994091a..09c7ead2dbe8e3483484e4b30c7beea36705ee56 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,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-20200403132600-4c10556e08a0 + github.com/iotaledger/hive.go v0.0.0-20200428004254-2aad9483e71c 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 diff --git a/go.sum b/go.sum index b7b8038a2a1537ea955b0e5a113a93d0713cfecc..32a1366691a295152bf163901b82f66256748203 100644 --- a/go.sum +++ b/go.sum @@ -165,6 +165,10 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0 h1:CyUsunZHlWuD1s9GVz+XqAIZVpRDxJBspb4DheJVknw= github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc= +github.com/iotaledger/hive.go v0.0.0-20200427200628-284e7291d770 h1:h9ujlJpBcqcVT3fOHebHCOhtqalbgXEKF0Mn5tmTjEc= +github.com/iotaledger/hive.go v0.0.0-20200427200628-284e7291d770/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc= +github.com/iotaledger/hive.go v0.0.0-20200428004254-2aad9483e71c h1:9UFU5/nwLCcMlx8W/7ztQjobnDq08hnB5k7kBYIAW2I= +github.com/iotaledger/hive.go v0.0.0-20200428004254-2aad9483e71c/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc= 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/issues.txt b/issues.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/packages/binary/drng/payload/header/header.go b/packages/binary/drng/payload/header/header.go index 426c1ee769056337099731b0d5b1bee33e91faaf..e3afed632e154e843fb22d1f2cfb09bbc1ec3e49 100644 --- a/packages/binary/drng/payload/header/header.go +++ b/packages/binary/drng/payload/header/header.go @@ -31,7 +31,7 @@ func New(payloadType Type, instanceID uint32) Header { // Parse is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package. func Parse(marshalUtil *marshalutil.MarshalUtil) (Header, error) { - header, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }) + header, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return FromBytes(data) }) if err != nil { return Header{}, err } @@ -40,7 +40,7 @@ func Parse(marshalUtil *marshalutil.MarshalUtil) (Header, error) { // FromBytes unmarshals a header from a sequence of bytes. // It either creates a new header or fills the optionally provided object with the parsed information. -func FromBytes(bytes []byte, optionalTargetObject ...*Header) (result Header, err error, consumedBytes int) { +func FromBytes(bytes []byte, optionalTargetObject ...*Header) (result Header, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information var targetObject *Header switch len(optionalTargetObject) { diff --git a/packages/binary/drng/payload/payload.go b/packages/binary/drng/payload/payload.go index fc21d403520b03de1d4171f02e549fa503fd591e..bbbdaafdf5515373418acbfe71cf51927b3dc0fb 100644 --- a/packages/binary/drng/payload/payload.go +++ b/packages/binary/drng/payload/payload.go @@ -28,7 +28,7 @@ func New(header header.Header, data []byte) *Payload { // 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 { + if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return FromBytes(data) }); err != nil { return &Payload{}, err } else { return payload.(*Payload), nil @@ -37,7 +37,7 @@ func Parse(marshalUtil *marshalutil.MarshalUtil) (*Payload, error) { // 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) { +func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -134,7 +134,7 @@ func (payload *Payload) Marshal() (bytes []byte, err error) { } func (payload *Payload) Unmarshal(data []byte) (err error) { - _, err, _ = FromBytes(data, payload) + _, _, err = FromBytes(data, payload) return } diff --git a/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go b/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go index 731ab0a30a703fdbab002c509069a2f518d88645..2c41c2c8d710406aab97aac21fa4c3c9f43ea630 100644 --- a/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go +++ b/packages/binary/drng/subtypes/collectiveBeacon/payload/payload.go @@ -41,7 +41,7 @@ func New(instanceID uint32, round uint64, prevSignature, signature, dpk []byte) // 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 { + if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return FromBytes(data) }); err != nil { return &Payload{}, err } else { return payload.(*Payload), nil @@ -50,7 +50,7 @@ func Parse(marshalUtil *marshalutil.MarshalUtil) (*Payload, error) { // 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) { +func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -167,7 +167,7 @@ func (payload *Payload) Marshal() (bytes []byte, err error) { } func (payload *Payload) Unmarshal(data []byte) (err error) { - _, err, _ = FromBytes(data, payload) + _, _, err = FromBytes(data, payload) return } diff --git a/packages/binary/messagelayer/message/id.go b/packages/binary/messagelayer/message/id.go index 754ddeec18908ff70167472778d2d4e49946154e..2dfd4f2856498d5dae24551288aa82b2d3936815 100644 --- a/packages/binary/messagelayer/message/id.go +++ b/packages/binary/messagelayer/message/id.go @@ -10,7 +10,7 @@ import ( // ContentId identifies the content of a message without its trunk/branch ids. type ContentId = Id -// Id identifies a message in its entirety. Unlike the sole content id, it also incorporates +// ID identifies a message in its entirety. Unlike the sole content id, it also incorporates // the trunk and branch ids. type Id [IdLength]byte @@ -33,7 +33,7 @@ func NewId(base58EncodedString string) (result Id, err error) { } // IdFromBytes unmarshals a message id from a sequence of bytes. -func IdFromBytes(bytes []byte) (result Id, err error, consumedBytes int) { +func IdFromBytes(bytes []byte) (result Id, consumedBytes int, err error) { // check arguments if len(bytes) < IdLength { err = fmt.Errorf("bytes not long enough to encode a valid message id") @@ -50,7 +50,7 @@ func IdFromBytes(bytes []byte) (result Id, err error, consumedBytes int) { // 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 { + if id, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return IdFromBytes(data) }); err != nil { return Id{}, err } else { return id.(Id), nil diff --git a/packages/binary/messagelayer/message/message.go b/packages/binary/messagelayer/message/message.go index 0bc75be347fab43837ab700b98ea2e2682982ed5..c9074f3f1a477869823b8796881da3625f001f3a 100644 --- a/packages/binary/messagelayer/message/message.go +++ b/packages/binary/messagelayer/message/message.go @@ -75,8 +75,8 @@ func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Messag panic("too many arguments in call to Parse") } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -88,7 +88,7 @@ func Parse(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Messag // StorableObjectFromKey gets called when we restore a message from storage. // The bytes and the content will be unmarshaled by an external caller (the objectStorage factory). -func StorableObjectFromKey(key []byte, optionalTargetObject ...*Message) (result objectstorage.StorableObject, err error, consumedBytes int) { +func StorableObjectFromKey(key []byte, optionalTargetObject ...*Message) (result objectstorage.StorableObject, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -121,7 +121,7 @@ func (message *Message) VerifySignature() bool { return valid } -// Id returns the id of the message which is made up of the content id and trunk/branch ids. +// ID returns the id of the message which is made up of the content id and trunk/branch ids. // This id can be used for merkle proofs. func (message *Message) Id() (result Id) { message.idMutex.RLock() @@ -145,12 +145,12 @@ func (message *Message) Id() (result Id) { return } -// TrunkId returns the id of the trunk message. +// TrunkID returns the id of the trunk message. func (message *Message) TrunkId() Id { return message.trunkId } -// BranchId returns the id of the branch message. +// BranchID returns the id of the branch message. func (message *Message) BranchId() Id { return message.branchId } @@ -267,7 +267,7 @@ func (message *Message) Bytes() []byte { return message.bytes } -func (message *Message) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (message *Message) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { // initialize helper marshalUtil := marshalutil.New(data) diff --git a/packages/binary/messagelayer/payload/id.go b/packages/binary/messagelayer/payload/id.go index b794cd0869f6ce27ecc949e771606494eb0caa2a..1320572d1822cd2cd1af25f7628f22519b6ad5e8 100644 --- a/packages/binary/messagelayer/payload/id.go +++ b/packages/binary/messagelayer/payload/id.go @@ -2,7 +2,7 @@ package payload import "github.com/mr-tron/base58" -// Id represents the id of a data payload. +// ID represents the id of a data payload. type Id [IdLength]byte // Bytes returns the id as a byte slice backed by the original array, diff --git a/packages/binary/messagelayer/payload/payload.go b/packages/binary/messagelayer/payload/payload.go index 7b90fb8f8da05130a325e848a2a273ee0f2a997f..a918ed1b7e6e6b5aa1fa7876ec836ecf1feb0825 100644 --- a/packages/binary/messagelayer/payload/payload.go +++ b/packages/binary/messagelayer/payload/payload.go @@ -25,7 +25,7 @@ type Payload interface { } // FromBytes unmarshals bytes into a payload. -func FromBytes(bytes []byte) (result Payload, err error, consumedBytes int) { +func FromBytes(bytes []byte) (result Payload, consumedBytes int, err error) { // initialize helper marshalUtil := marshalutil.New(bytes) @@ -58,7 +58,7 @@ func FromBytes(bytes []byte) (result Payload, err error, consumedBytes int) { // Parse parses a payload by using the given marshal util. func Parse(marshalUtil *marshalutil.MarshalUtil) (Payload, error) { - if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return FromBytes(data) }); err != nil { + if payload, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return FromBytes(data) }); err != nil { return nil, err } else { return payload.(Payload), nil diff --git a/packages/binary/messagelayer/tangle/approver.go b/packages/binary/messagelayer/tangle/approver.go index f2d6601ece9995a9c1670149a2e5343833e433d1..5526a104b2bb2a39595c2ddff22665164fd984b3 100644 --- a/packages/binary/messagelayer/tangle/approver.go +++ b/packages/binary/messagelayer/tangle/approver.go @@ -36,7 +36,7 @@ func ApproverFromBytes(bytes []byte, optionalTargetObject ...*Approver) (result // ParseApprover parses a new approver from the given marshal util. func ParseApprover(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Approver) (result *Approver, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ApproverFromStorageKey(data, optionalTargetObject...) }); parseErr != nil { err = parseErr @@ -45,8 +45,9 @@ func ParseApprover(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject .. result = parsedObject.(*Approver) } - _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) + return }) @@ -54,7 +55,7 @@ func ParseApprover(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject .. } // ApproverFromStorageKey returns an approver for the given key. -func ApproverFromStorageKey(key []byte, optionalTargetObject ...*Approver) (result objectstorage.StorableObject, err error, consumedBytes int) { +func ApproverFromStorageKey(key []byte, optionalTargetObject ...*Approver) (result objectstorage.StorableObject, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -110,7 +111,7 @@ func (approver *Approver) ObjectStorageValue() (result []byte) { return } -func (approver *Approver) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (approver *Approver) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { return } diff --git a/packages/binary/messagelayer/tangle/messagemetadata.go b/packages/binary/messagelayer/tangle/messagemetadata.go index 7f39c4fa2870b142b447a58a06ca712bdfb0696a..60b2d92aac0d608d324902ce8f4c20ae9fe9d531 100644 --- a/packages/binary/messagelayer/tangle/messagemetadata.go +++ b/packages/binary/messagelayer/tangle/messagemetadata.go @@ -38,7 +38,7 @@ func MessageMetadataFromBytes(bytes []byte) (result *MessageMetadata, err error, } func ParseMessageMetadata(marshalUtil *marshalutil.MarshalUtil) (result *MessageMetadata, err error) { - if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { + if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return MessageMetadataFromStorageKey(data) }); parseErr != nil { err = parseErr @@ -48,8 +48,8 @@ func ParseMessageMetadata(marshalUtil *marshalutil.MarshalUtil) (result *Message result = parsedObject.(*MessageMetadata) } - if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) { - parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data) + if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { + parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }); err != nil { @@ -59,7 +59,7 @@ func ParseMessageMetadata(marshalUtil *marshalutil.MarshalUtil) (result *Message return } -func MessageMetadataFromStorageKey(key []byte) (result objectstorage.StorableObject, err error, consumedBytes int) { +func MessageMetadataFromStorageKey(key []byte) (result objectstorage.StorableObject, consumedBytes int, err error) { result = &MessageMetadata{} marshalUtil := marshalutil.New(key) @@ -126,7 +126,7 @@ func (messageMetadata *MessageMetadata) ObjectStorageValue() []byte { Bytes() } -func (messageMetadata *MessageMetadata) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (messageMetadata *MessageMetadata) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) if messageMetadata.receivedTime, err = marshalUtil.ReadTime(); err != nil { diff --git a/packages/binary/messagelayer/tangle/missingmessage.go b/packages/binary/messagelayer/tangle/missingmessage.go index 2bf35b2833f1174d9892ce7f497a04365e9bc04b..1fb9e4b2f01532c77a40b9963c5d0e27502b9861 100644 --- a/packages/binary/messagelayer/tangle/missingmessage.go +++ b/packages/binary/messagelayer/tangle/missingmessage.go @@ -23,7 +23,7 @@ func NewMissingMessage(messageId message.Id) *MissingMessage { } } -func MissingMessageFromStorageKey(key []byte, optionalTargetObject ...*MissingMessage) (result objectstorage.StorableObject, err error, consumedBytes int) { +func MissingMessageFromStorageKey(key []byte, optionalTargetObject ...*MissingMessage) (result objectstorage.StorableObject, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: @@ -72,7 +72,7 @@ func (missingMessage *MissingMessage) ObjectStorageValue() (result []byte) { return } -func (missingMessage *MissingMessage) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) { +func (missingMessage *MissingMessage) UnmarshalObjectStorageValue(data []byte) (consumedBytes int, err error) { marshalUtil := marshalutil.New(data) missingMessage.missingSince, err = marshalUtil.ReadTime() if err != nil { diff --git a/packages/binary/messagelayer/tangle/tangle.go b/packages/binary/messagelayer/tangle/tangle.go index 3b67914a1f57edb8032acf0efceb71edd97541b4..8d3f056af3adc01cfebd2429e90a55a13d691929 100644 --- a/packages/binary/messagelayer/tangle/tangle.go +++ b/packages/binary/messagelayer/tangle/tangle.go @@ -37,15 +37,15 @@ type Tangle struct { cleanupWorkerPool async.WorkerPool } -func messageFactory(key []byte) (objectstorage.StorableObject, error, int) { +func messageFactory(key []byte) (objectstorage.StorableObject, int, error) { return message.StorableObjectFromKey(key) } -func approverFactory(key []byte) (objectstorage.StorableObject, error, int) { +func approverFactory(key []byte) (objectstorage.StorableObject, int, error) { return ApproverFromStorageKey(key) } -func missingMessageFactory(key []byte) (objectstorage.StorableObject, error, int) { +func missingMessageFactory(key []byte) (objectstorage.StorableObject, int, error) { return MissingMessageFromStorageKey(key) } diff --git a/packages/binary/messagelayer/test/message_test.go b/packages/binary/messagelayer/test/message_test.go index 13e65502e8945b90cf729a4d35e3e30567c2ecd8..70684aa307f921b7223413296b5e06710aba2b66 100644 --- a/packages/binary/messagelayer/test/message_test.go +++ b/packages/binary/messagelayer/test/message_test.go @@ -18,7 +18,7 @@ func TestMessage_StorableObjectFromKey(t *testing.T) { panic(err) } - messageFromKey, err, consumedBytes := message.StorableObjectFromKey(key.Bytes()) + messageFromKey, consumedBytes, err := message.StorableObjectFromKey(key.Bytes()) if err != nil { panic(err) } diff --git a/packages/gossip/manager.go b/packages/gossip/manager.go index eddc0ff4e9e70347945fc1e82d5a15192872caf1..128a323d6168cc13db850f0c9b05416d1abd78f0 100644 --- a/packages/gossip/manager.go +++ b/packages/gossip/manager.go @@ -241,7 +241,7 @@ func (m *Manager) handlePacket(data []byte, p *peer.Peer) error { } m.log.Debugw("received packet", "type", protoMsgReq.Type(), "peer-id", p.ID()) - msgId, err, _ := message.IdFromBytes(protoMsgReq.GetId()) + msgId, _, err := message.IdFromBytes(protoMsgReq.GetId()) if err != nil { m.log.Debugw("couldn't compute message id from bytes", "peer-id", p.ID(), "err", err) return nil diff --git a/packages/vote/voter.go b/packages/vote/voter.go index 12f904a10ab8deb594ef0662d371ff634227fd95..af77cbe1d876bdaf85423e0ad94a1ce1e03fc96d 100644 --- a/packages/vote/voter.go +++ b/packages/vote/voter.go @@ -57,7 +57,7 @@ type RoundStats struct { QueriedOpinions []QueriedOpinions `json:"queried_opinions"` } -// OpinionCaller calls the given handler with an Opinion and its associated Id. +// OpinionCaller calls the given handler with an Opinion and its associated ID. func OpinionCaller(handler interface{}, params ...interface{}) { handler.(func(id string, opinion Opinion))(params[0].(string), params[1].(Opinion)) } diff --git a/plugins/autopeering/autopeering.go b/plugins/autopeering/autopeering.go index 37614373d6318c25f968e747b97a9f054742f9e6..8e948bed2900330a85abfe8dc864b2204f4522eb 100644 --- a/plugins/autopeering/autopeering.go +++ b/plugins/autopeering/autopeering.go @@ -159,7 +159,7 @@ func parseEntryNodes() (result []*peer.Peer, err error) { if err != nil { return nil, fmt.Errorf("%w: host cannot be resolved: %s", ErrParsingMasterNode, err) } - publicKey, err, _ := ed25519.PublicKeyFromBytes(pubKey) + publicKey, _, err := ed25519.PublicKeyFromBytes(pubKey) if err != nil { return nil, err } diff --git a/plugins/drng/drng.go b/plugins/drng/drng.go index ec1c7e371b4824588e66b0e19f83c256c6c4d449..0d377b27a08b0f0cf2297cbae52fd5333f387758 100644 --- a/plugins/drng/drng.go +++ b/plugins/drng/drng.go @@ -67,7 +67,7 @@ func parseCommitteeMembers() (result []ed25519.PublicKey, err error) { if err != nil { return nil, fmt.Errorf("%w: invalid public key: %s", ErrParsingCommitteeMember, err) } - publicKey, err, _ := ed25519.PublicKeyFromBytes(pubKey) + publicKey, _, err := ed25519.PublicKeyFromBytes(pubKey) if err != nil { return nil, err } diff --git a/plugins/webapi/message/plugin.go b/plugins/webapi/message/plugin.go index 6cf870fb7c9a8898d660b7f4ba63fd64672cfa37..1ebbf8b7fb31be52efa6c59984a81e56c8218ca2 100644 --- a/plugins/webapi/message/plugin.go +++ b/plugins/webapi/message/plugin.go @@ -95,7 +95,7 @@ type Request struct { // Message contains information about a given message. type Message struct { Metadata `json:"metadata,omitempty"` - ID string `json:"Id,omitempty"` + ID string `json:"ID,omitempty"` TrunkID string `json:"trunkId,omitempty"` BranchID string `json:"branchId,omitempty"` IssuerPublicKey string `json:"issuerPublicKey,omitempty"` diff --git a/tools/integration-tests/tester/go.mod b/tools/integration-tests/tester/go.mod index e0be4d0463e4737e878ee9d88c216938cce1d11c..e6bb0bf5102aba8bc8f38297670e11c2ee352c7b 100644 --- a/tools/integration-tests/tester/go.mod +++ b/tools/integration-tests/tester/go.mod @@ -9,7 +9,7 @@ require ( github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 // indirect github.com/iotaledger/goshimmer v0.1.3 - github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0 + github.com/iotaledger/hive.go v0.0.0-20200428004254-2aad9483e71c github.com/opencontainers/go-digest v1.0.0-rc1 // indirect github.com/stretchr/testify v1.5.1 ) diff --git a/tools/integration-tests/tester/go.sum b/tools/integration-tests/tester/go.sum index d9500e0373b12770f308e6040ac96917199f7822..02b47b3ba756528ea131cfd696f96b2c127b9265 100644 --- a/tools/integration-tests/tester/go.sum +++ b/tools/integration-tests/tester/go.sum @@ -157,8 +157,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 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-20200403132600-4c10556e08a0 h1:CyUsunZHlWuD1s9GVz+XqAIZVpRDxJBspb4DheJVknw= -github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc= +github.com/iotaledger/hive.go v0.0.0-20200428004254-2aad9483e71c h1:9UFU5/nwLCcMlx8W/7ztQjobnDq08hnB5k7kBYIAW2I= +github.com/iotaledger/hive.go v0.0.0-20200428004254-2aad9483e71c/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc= github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8= github.com/iotaledger/iota.go v1.0.0-beta.14/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=