diff --git a/pkg/core/account/accounts.go b/pkg/core/account/accounts.go index 45fdc7f3c..8d16c5047 100644 --- a/pkg/core/account/accounts.go +++ b/pkg/core/account/accounts.go @@ -9,7 +9,8 @@ import ( "github.com/iotaledger/hive.go/ds/shrinkingmap" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/syncutils" - "github.com/iotaledger/hive.go/serializer/v2/marshalutil" + "github.com/iotaledger/hive.go/serializer/v2" + "github.com/iotaledger/hive.go/serializer/v2/stream" iotago "github.com/iotaledger/iota.go/v4" ) @@ -134,6 +135,7 @@ func AccountsFromReader(readSeeker io.ReadSeeker) (*Accounts, int, error) { } func (a *Accounts) readFromReadSeeker(reader io.ReadSeeker) (n int, err error) { + // TODO: improve this a.mutex.Lock() defer a.mutex.Unlock() @@ -181,31 +183,39 @@ func (a *Accounts) readFromReadSeeker(reader io.ReadSeeker) (n int, err error) { return n, nil } -func (a *Accounts) Bytes() (bytes []byte, err error) { +func (a *Accounts) Bytes() ([]byte, error) { a.mutex.RLock() defer a.mutex.RUnlock() - m := marshalutil.New() - - m.WriteUint32(uint32(a.accountPools.Size())) - var innerErr error - a.ForEach(func(id iotago.AccountID, pool *Pool) bool { - m.WriteBytes(id[:]) - poolBytes, err := pool.Bytes() - if err != nil { - innerErr = err - return false + byteBuffer := stream.NewByteBuffer() + + if err := stream.WriteCollection(byteBuffer, serializer.SeriLengthPrefixTypeAsUint32, func() (elementsCount int, err error) { + var innerErr error + a.ForEach(func(id iotago.AccountID, pool *Pool) bool { + if innerErr = stream.Write(byteBuffer, id); innerErr != nil { + return false + } + + if innerErr = stream.WriteFixedSizeObject(byteBuffer, pool, poolBytesLength, func(pool *Pool) ([]byte, error) { + return pool.Bytes() + }); innerErr != nil { + return false + } + + return true + }) + if innerErr != nil { + return 0, innerErr } - m.WriteBytes(poolBytes) - - return true - }) - m.WriteBool(a.reused.Load()) + return a.accountPools.Size(), nil + }); err != nil { + return nil, ierrors.Wrap(err, "failed to write accounts") + } - if innerErr != nil { - return nil, innerErr + if err := stream.Write(byteBuffer, a.reused.Load()); err != nil { + return nil, ierrors.Wrap(err, "failed to write reused flag") } - return m.Bytes(), nil + return byteBuffer.Bytes() } diff --git a/pkg/core/account/pool.go b/pkg/core/account/pool.go index 5815420db..44827eb11 100644 --- a/pkg/core/account/pool.go +++ b/pkg/core/account/pool.go @@ -2,11 +2,12 @@ package account import ( "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/hive.go/serializer/v2/marshalutil" + "github.com/iotaledger/hive.go/serializer/v2" + "github.com/iotaledger/hive.go/serializer/v2/stream" iotago "github.com/iotaledger/iota.go/v4" ) -const poolBytesLength = 3 * marshalutil.Uint64Size +const poolBytesLength = 3 * serializer.UInt64ByteSize // Pool represents all the data we need for a given validator and epoch to calculate its rewards data. type Pool struct { @@ -19,33 +20,35 @@ type Pool struct { func PoolFromBytes(bytes []byte) (*Pool, int, error) { p := new(Pool) - m := marshalutil.New(bytes) - poolStake, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse pool stake") - } - p.PoolStake = iotago.BaseToken(poolStake) - validatorStake, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse validator stake") - } - p.ValidatorStake = iotago.BaseToken(validatorStake) + var err error + byteReader := stream.NewByteReader(bytes) - fixedCost, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse fixed cost") + if p.PoolStake, err = stream.Read[iotago.BaseToken](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read PoolStake") + } + if p.ValidatorStake, err = stream.Read[iotago.BaseToken](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read ValidatorStake") + } + if p.FixedCost, err = stream.Read[iotago.Mana](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read FixedCost") } - p.FixedCost = iotago.Mana(fixedCost) - return p, m.ReadOffset(), nil + return p, byteReader.BytesRead(), nil } -func (p *Pool) Bytes() (bytes []byte, err error) { - m := marshalutil.New() - m.WriteUint64(uint64(p.PoolStake)) - m.WriteUint64(uint64(p.ValidatorStake)) - m.WriteUint64(uint64(p.FixedCost)) +func (p *Pool) Bytes() ([]byte, error) { + byteBuffer := stream.NewByteBuffer(poolBytesLength) + + if err := stream.Write(byteBuffer, p.PoolStake); err != nil { + return nil, ierrors.Wrap(err, "failed to write PoolStake") + } + if err := stream.Write(byteBuffer, p.ValidatorStake); err != nil { + return nil, ierrors.Wrap(err, "failed to write ValidatorStake") + } + if err := stream.Write(byteBuffer, p.FixedCost); err != nil { + return nil, ierrors.Wrap(err, "failed to write FixedCost") + } - return m.Bytes(), nil + return byteBuffer.Bytes() } diff --git a/pkg/model/account_diff.go b/pkg/model/account_diff.go index fadef8c74..f90259da4 100644 --- a/pkg/model/account_diff.go +++ b/pkg/model/account_diff.go @@ -9,7 +9,6 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/serializer/v2" - "github.com/iotaledger/hive.go/serializer/v2/marshalutil" "github.com/iotaledger/hive.go/serializer/v2/stream" iotago "github.com/iotaledger/iota.go/v4" ) @@ -18,7 +17,7 @@ import ( type AccountDiff struct { BICChange iotago.BlockIssuanceCredits - PreviousUpdatedTime iotago.SlotIndex + PreviousUpdatedSlot iotago.SlotIndex NewExpirySlot iotago.SlotIndex PreviousExpirySlot iotago.SlotIndex @@ -44,7 +43,7 @@ type AccountDiff struct { func NewAccountDiff() *AccountDiff { return &AccountDiff{ BICChange: 0, - PreviousUpdatedTime: 0, + PreviousUpdatedSlot: 0, NewExpirySlot: 0, PreviousExpirySlot: 0, NewOutputID: iotago.EmptyOutputID, @@ -61,36 +60,60 @@ func NewAccountDiff() *AccountDiff { } func (d AccountDiff) Bytes() ([]byte, error) { - m := marshalutil.New() + byteBuffer := stream.NewByteBuffer() - m.WriteInt64(int64(d.BICChange)) - m.WriteUint32(uint32(d.PreviousUpdatedTime)) - m.WriteUint32(uint32(d.NewExpirySlot)) - m.WriteUint32(uint32(d.PreviousExpirySlot)) - m.WriteBytes(lo.PanicOnErr(d.NewOutputID.Bytes())) - m.WriteBytes(lo.PanicOnErr(d.PreviousOutputID.Bytes())) + if err := stream.Write(byteBuffer, d.BICChange); err != nil { + return nil, ierrors.Wrap(err, "unable to write BICChange value in the diff") + } + if err := stream.Write(byteBuffer, d.PreviousUpdatedSlot); err != nil { + return nil, ierrors.Wrap(err, "unable to write PreviousUpdatedSlot in the diff") + } + if err := stream.Write(byteBuffer, d.NewExpirySlot); err != nil { + return nil, ierrors.Wrap(err, "unable to write NewExpirySlot in the diff") + } + if err := stream.Write(byteBuffer, d.PreviousExpirySlot); err != nil { + return nil, ierrors.Wrap(err, "unable to write PreviousExpirySlot in the diff") + } + if err := stream.Write(byteBuffer, d.NewOutputID); err != nil { + return nil, ierrors.Wrap(err, "unable to write NewOutputID in the diff") + } + if err := stream.Write(byteBuffer, d.PreviousOutputID); err != nil { + return nil, ierrors.Wrap(err, "unable to write PreviousOutputID in the diff") + } - if err := writeBlockIssuerKeys(m, d.BlockIssuerKeysAdded); err != nil { + if err := writeBlockIssuerKeys(byteBuffer, d.BlockIssuerKeysAdded); err != nil { return nil, err } - if err := writeBlockIssuerKeys(m, d.BlockIssuerKeysRemoved); err != nil { + if err := writeBlockIssuerKeys(byteBuffer, d.BlockIssuerKeysRemoved); err != nil { return nil, err } - m.WriteInt64(d.ValidatorStakeChange) - m.WriteInt64(d.DelegationStakeChange) - m.WriteInt64(d.FixedCostChange) - m.WriteUint64(uint64(d.StakeEndEpochChange)) - m.WriteBytes(lo.PanicOnErr(d.NewLatestSupportedVersionAndHash.Bytes())) - m.WriteBytes(lo.PanicOnErr(d.PrevLatestSupportedVersionAndHash.Bytes())) + if err := stream.Write(byteBuffer, d.ValidatorStakeChange); err != nil { + return nil, ierrors.Wrap(err, "unable to write ValidatorStakeChange in the diff") + } + if err := stream.Write(byteBuffer, d.DelegationStakeChange); err != nil { + return nil, ierrors.Wrap(err, "unable to write DelegationStakeChange in the diff") + } + if err := stream.Write(byteBuffer, d.FixedCostChange); err != nil { + return nil, ierrors.Wrap(err, "unable to write FixedCostChange in the diff") + } + if err := stream.Write(byteBuffer, d.StakeEndEpochChange); err != nil { + return nil, ierrors.Wrap(err, "unable to write StakeEndEpochChange in the diff") + } + if err := stream.WriteFixedSizeObject(byteBuffer, d.NewLatestSupportedVersionAndHash, VersionAndHashSize, VersionAndHash.Bytes); err != nil { + return nil, ierrors.Wrap(err, "unable to write NewLatestSupportedVersionAndHash in the diff") + } + if err := stream.WriteFixedSizeObject(byteBuffer, d.PrevLatestSupportedVersionAndHash, VersionAndHashSize, VersionAndHash.Bytes); err != nil { + return nil, ierrors.Wrap(err, "unable to write PrevLatestSupportedVersionAndHash in the diff") + } - return m.Bytes(), nil + return byteBuffer.Bytes() } func (d *AccountDiff) Clone() *AccountDiff { return &AccountDiff{ BICChange: d.BICChange, - PreviousUpdatedTime: d.PreviousUpdatedTime, + PreviousUpdatedSlot: d.PreviousUpdatedSlot, NewExpirySlot: d.NewExpirySlot, PreviousExpirySlot: d.PreviousExpirySlot, NewOutputID: d.NewOutputID, @@ -107,20 +130,23 @@ func (d *AccountDiff) Clone() *AccountDiff { } func (d *AccountDiff) FromBytes(b []byte) (int, error) { + // TODO: remove return d.readFromReadSeeker(bytes.NewReader(b)) } func (d *AccountDiff) FromReader(readSeeker io.ReadSeeker) error { + // TODO: remove return lo.Return2(d.readFromReadSeeker(readSeeker)) } func (d *AccountDiff) readFromReadSeeker(reader io.ReadSeeker) (offset int, err error) { + // TODO: adjust to new stream API if err = binary.Read(reader, binary.LittleEndian, &d.BICChange); err != nil { return offset, ierrors.Wrap(err, "unable to read account BIC balance value in the diff") } offset += 8 - if err = binary.Read(reader, binary.LittleEndian, &d.PreviousUpdatedTime); err != nil { + if err = binary.Read(reader, binary.LittleEndian, &d.PreviousUpdatedSlot); err != nil { return offset, ierrors.Wrap(err, "unable to read previous updated time in the diff") } offset += iotago.SlotIndexLength @@ -204,22 +230,26 @@ func (d *AccountDiff) readFromReadSeeker(reader io.ReadSeeker) (offset int, err return offset, nil } -func writeBlockIssuerKeys(m *marshalutil.MarshalUtil, blockIssuerKeys iotago.BlockIssuerKeys) error { +func writeBlockIssuerKeys(byteBuffer *stream.ByteBuffer, blockIssuerKeys iotago.BlockIssuerKeys) error { + // TODO: improve this + blockIssuerKeysBytes, err := iotago.CommonSerixAPI().Encode(context.TODO(), blockIssuerKeys) if err != nil { return ierrors.Wrap(err, "unable to encode blockIssuerKeys in the diff") } - m.WriteUint64(uint64(len(blockIssuerKeysBytes))) - m.WriteBytes(blockIssuerKeysBytes) + if err := stream.WriteByteSlice(byteBuffer, blockIssuerKeysBytes, serializer.SeriLengthPrefixTypeAsUint64); err != nil { + return ierrors.Wrap(err, "unable to write blockIssuerKeysBytes in the diff") + } return nil } func readBlockIssuerKeys(reader io.ReadSeeker) (iotago.BlockIssuerKeys, int, error) { + // TODO: improve this var bytesConsumed int - blockIssuerKeysBytes, err := stream.ReadBlob(reader) + blockIssuerKeysBytes, err := stream.ReadByteSlice(reader, serializer.SeriLengthPrefixTypeAsUint64) if err != nil { return nil, bytesConsumed, ierrors.Wrap(err, "unable to read blockIssuerKeysBytes in the diff") } diff --git a/pkg/model/poolstats.go b/pkg/model/poolstats.go index b8ce0a5c0..54dd23857 100644 --- a/pkg/model/poolstats.go +++ b/pkg/model/poolstats.go @@ -2,7 +2,7 @@ package model import ( "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/hive.go/serializer/v2/marshalutil" + "github.com/iotaledger/hive.go/serializer/v2/stream" iotago "github.com/iotaledger/iota.go/v4" ) @@ -15,34 +15,37 @@ type PoolsStats struct { func PoolsStatsFromBytes(bytes []byte) (*PoolsStats, int, error) { p := new(PoolsStats) - m := marshalutil.New(bytes) - totalStake, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse total stake") - } - p.TotalStake = iotago.BaseToken(totalStake) - totalValidatorStake, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse total validator stake") - } - p.TotalValidatorStake = iotago.BaseToken(totalValidatorStake) + var err error + byteReader := stream.NewByteReader(bytes) - p.ProfitMargin, err = m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse profit margin") + if p.TotalStake, err = stream.Read[iotago.BaseToken](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read TotalStake") + } + if p.TotalValidatorStake, err = stream.Read[iotago.BaseToken](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read TotalValidatorStake") + } + if p.ProfitMargin, err = stream.Read[uint64](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read ProfitMargin") } - return p, m.ReadOffset(), nil + return p, byteReader.BytesRead(), nil } func (p *PoolsStats) Bytes() ([]byte, error) { - m := marshalutil.New() - m.WriteUint64(uint64(p.TotalStake)) - m.WriteUint64(uint64(p.TotalValidatorStake)) - m.WriteUint64(p.ProfitMargin) + byteBuffer := stream.NewByteBuffer() + + if err := stream.Write(byteBuffer, p.TotalStake); err != nil { + return nil, ierrors.Wrap(err, "failed to write TotalStake") + } + if err := stream.Write(byteBuffer, p.TotalValidatorStake); err != nil { + return nil, ierrors.Wrap(err, "failed to write TotalValidatorStake") + } + if err := stream.Write(byteBuffer, p.ProfitMargin); err != nil { + return nil, ierrors.Wrap(err, "failed to write ProfitMargin") + } - return m.Bytes(), nil + return byteBuffer.Bytes() } type PoolRewards struct { @@ -56,34 +59,35 @@ type PoolRewards struct { func PoolRewardsFromBytes(bytes []byte) (*PoolRewards, int, error) { p := new(PoolRewards) - m := marshalutil.New(bytes) - poolStake, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse pool stake") - } - p.PoolStake = iotago.BaseToken(poolStake) + var err error + byteReader := stream.NewByteReader(bytes) - poolRewards, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse pool rewards") + if p.PoolStake, err = stream.Read[iotago.BaseToken](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read PoolStake") } - p.PoolRewards = iotago.Mana(poolRewards) - - fixedCost, err := m.ReadUint64() - if err != nil { - return nil, m.ReadOffset(), ierrors.Wrap(err, "failed to parse fixed cost") + if p.PoolRewards, err = stream.Read[iotago.Mana](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read PoolRewards") + } + if p.FixedCost, err = stream.Read[iotago.Mana](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read FixedCost") } - p.FixedCost = iotago.Mana(fixedCost) - return p, m.ReadOffset(), nil + return p, byteReader.BytesRead(), nil } func (p *PoolRewards) Bytes() ([]byte, error) { - m := marshalutil.New() - m.WriteUint64(uint64(p.PoolStake)) - m.WriteUint64(uint64(p.PoolRewards)) - m.WriteUint64(uint64(p.FixedCost)) + byteBuffer := stream.NewByteBuffer() + + if err := stream.Write(byteBuffer, p.PoolStake); err != nil { + return nil, ierrors.Wrap(err, "failed to write PoolStake") + } + if err := stream.Write(byteBuffer, p.PoolRewards); err != nil { + return nil, ierrors.Wrap(err, "failed to write PoolRewards") + } + if err := stream.Write(byteBuffer, p.FixedCost); err != nil { + return nil, ierrors.Wrap(err, "failed to write FixedCost") + } - return m.Bytes(), nil + return byteBuffer.Bytes() } diff --git a/pkg/protocol/engine/accounts/accounts.go b/pkg/protocol/engine/accounts/accounts.go index 403f569c0..8a30080e2 100644 --- a/pkg/protocol/engine/accounts/accounts.go +++ b/pkg/protocol/engine/accounts/accounts.go @@ -9,7 +9,8 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/options" - "github.com/iotaledger/hive.go/serializer/v2/marshalutil" + "github.com/iotaledger/hive.go/serializer/v2" + "github.com/iotaledger/hive.go/serializer/v2/stream" "github.com/iotaledger/iota-core/pkg/model" iotago "github.com/iotaledger/iota.go/v4" ) @@ -64,7 +65,7 @@ func (a *AccountData) Clone() *AccountData { ID: a.ID, Credits: &BlockIssuanceCredits{ Value: a.Credits.Value, - UpdateTime: a.Credits.UpdateTime, + UpdateSlot: a.Credits.UpdateSlot, }, ExpirySlot: a.ExpirySlot, OutputID: a.OutputID, @@ -87,6 +88,7 @@ func (a *AccountData) FromReader(readSeeker io.ReadSeeker) error { } func (a *AccountData) readFromReadSeeker(reader io.ReadSeeker) (int, error) { + // TODO: improve this var bytesConsumed int bytesRead, err := io.ReadFull(reader, a.ID[:]) @@ -103,7 +105,7 @@ func (a *AccountData) readFromReadSeeker(reader io.ReadSeeker) (int, error) { } bytesConsumed += 8 - if err := binary.Read(reader, binary.LittleEndian, &a.Credits.UpdateTime); err != nil { + if err := binary.Read(reader, binary.LittleEndian, &a.Credits.UpdateSlot); err != nil { return bytesConsumed, ierrors.Wrapf(err, "unable to read updatedTime for account balance for accountID %s", a.ID) } bytesConsumed += iotago.SlotIndexLength @@ -189,27 +191,55 @@ func (a *AccountData) readFromReadSeeker(reader io.ReadSeeker) (int, error) { } func (a AccountData) Bytes() ([]byte, error) { - idBytes, err := a.ID.Bytes() - if err != nil { - return nil, ierrors.Wrap(err, "failed to marshal account id") + byteBuffer := stream.NewByteBuffer() + + if err := stream.Write(byteBuffer, a.ID); err != nil { + return nil, ierrors.Wrap(err, "failed to write AccountID") + } + if err := stream.WriteFixedSizeObject(byteBuffer, a.Credits, BlockIssuanceCreditsBytesLength, func(credits *BlockIssuanceCredits) ([]byte, error) { + return credits.Bytes() + }); err != nil { + return nil, ierrors.Wrap(err, "failed to write Credits") + } + if err := stream.Write(byteBuffer, a.ExpirySlot); err != nil { + return nil, ierrors.Wrap(err, "failed to write ExpirySlot") } - m := marshalutil.New() - m.WriteBytes(idBytes) - m.WriteBytes(lo.PanicOnErr(a.Credits.Bytes())) - m.WriteUint32(uint32(a.ExpirySlot)) - m.WriteBytes(lo.PanicOnErr(a.OutputID.Bytes())) - m.WriteByte(byte(len(a.BlockIssuerKeys))) - for _, key := range a.BlockIssuerKeys { - m.WriteBytes(key.Bytes()) + if err := stream.Write(byteBuffer, a.OutputID); err != nil { + return nil, ierrors.Wrap(err, "failed to write OutputID") + } + + if err := stream.WriteCollection(byteBuffer, serializer.SeriLengthPrefixTypeAsByte, func() (elementsCount int, err error) { + // TODO: write this properly as object (depends on how we read it) + for _, key := range a.BlockIssuerKeys { + if _, err = byteBuffer.Write(key.Bytes()); err != nil { + return 0, ierrors.Wrap(err, "failed to write BlockIssuerKey") + } + } + + return len(a.BlockIssuerKeys), nil + }); err != nil { + return nil, ierrors.Wrap(err, "failed to write BlockIssuerKeys") } - m.WriteUint64(uint64(a.ValidatorStake)) - m.WriteUint64(uint64(a.DelegationStake)) - m.WriteUint64(uint64(a.FixedCost)) - m.WriteUint32(uint32(a.StakeEndEpoch)) - m.WriteBytes(lo.PanicOnErr(a.LatestSupportedProtocolVersionAndHash.Bytes())) + if err := stream.Write(byteBuffer, a.ValidatorStake); err != nil { + return nil, ierrors.Wrap(err, "failed to write ValidatorStake") + } + if err := stream.Write(byteBuffer, a.DelegationStake); err != nil { + return nil, ierrors.Wrap(err, "failed to write DelegationStake") + } + if err := stream.Write(byteBuffer, a.FixedCost); err != nil { + return nil, ierrors.Wrap(err, "failed to write FixedCost") + } + if err := stream.Write(byteBuffer, a.StakeEndEpoch); err != nil { + return nil, ierrors.Wrap(err, "failed to write StakeEndEpoch") + } + if err := stream.WriteFixedSizeObject(byteBuffer, a.LatestSupportedProtocolVersionAndHash, model.VersionAndHashSize, func(versionAndHash model.VersionAndHash) ([]byte, error) { + return versionAndHash.Bytes() + }); err != nil { + return nil, ierrors.Wrap(err, "failed to write LatestSupportedProtocolVersionAndHash") + } - return m.Bytes(), nil + return byteBuffer.Bytes() } func WithCredits(credits *BlockIssuanceCredits) options.Option[AccountData] { diff --git a/pkg/protocol/engine/accounts/accountsledger/manager.go b/pkg/protocol/engine/accounts/accountsledger/manager.go index 53459cb0c..01b48ce58 100644 --- a/pkg/protocol/engine/accounts/accountsledger/manager.go +++ b/pkg/protocol/engine/accounts/accountsledger/manager.go @@ -60,6 +60,8 @@ func New( blockBurns: shrinkingmap.New[iotago.SlotIndex, ds.Set[iotago.BlockID]](), latestSupportedVersionSignals: memstorage.NewIndexedStorage[iotago.SlotIndex, iotago.AccountID, *model.SignaledBlock](), accountsTree: ads.NewMap[iotago.Identifier](accountsStore, + iotago.Identifier.Bytes, + iotago.IdentifierFromBytes, iotago.AccountID.Bytes, iotago.AccountIDFromBytes, (*accounts.AccountData).Bytes, @@ -379,7 +381,7 @@ func (m *Manager) rollbackAccountTo(accountData *accounts.AccountData, targetSlo } // update the account data with the diff - accountData.Credits.Update(-diffChange.BICChange, diffChange.PreviousUpdatedTime) + accountData.Credits.Update(-diffChange.BICChange, diffChange.PreviousUpdatedSlot) // update the expiry slot of the account if it was changed if diffChange.PreviousExpirySlot != diffChange.NewExpirySlot { accountData.ExpirySlot = diffChange.PreviousExpirySlot @@ -444,7 +446,7 @@ func (m *Manager) preserveDestroyedAccountData(accountID iotago.AccountID) (acco slotDiff.PreviousExpirySlot = accountData.ExpirySlot slotDiff.NewOutputID = iotago.EmptyOutputID slotDiff.PreviousOutputID = accountData.OutputID - slotDiff.PreviousUpdatedTime = accountData.Credits.UpdateTime + slotDiff.PreviousUpdatedSlot = accountData.Credits.UpdateSlot slotDiff.BlockIssuerKeysRemoved = accountData.BlockIssuerKeys.Clone() slotDiff.ValidatorStakeChange = -int64(accountData.ValidatorStake) @@ -519,7 +521,7 @@ func (m *Manager) commitAccountTree(slot iotago.SlotIndex, accountDiffChanges ma if diffChange.BICChange != 0 || !exists { // decay the credits to the current slot if the account exists if exists { - decayedPreviousCredits, err := m.apiProvider.APIForSlot(slot).ManaDecayProvider().ManaWithDecay(iotago.Mana(accountData.Credits.Value), accountData.Credits.UpdateTime, slot) + decayedPreviousCredits, err := m.apiProvider.APIForSlot(slot).ManaDecayProvider().ManaWithDecay(iotago.Mana(accountData.Credits.Value), accountData.Credits.UpdateSlot, slot) if err != nil { return ierrors.Wrapf(err, "can't retrieve account, could not decay credits for account (%s) in slot (%d)", accountData.ID, slot) } diff --git a/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go b/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go index b090c64c5..d7b89baf6 100644 --- a/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go +++ b/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go @@ -131,7 +131,7 @@ func (t *TestSuite) ApplySlotActions(slot iotago.SlotIndex, rmc iotago.Mana, act BICChange: iotago.BlockIssuanceCredits(action.TotalAllotments), // manager takes AccountDiff only with allotments filled in when applyDiff is triggered BlockIssuerKeysAdded: t.BlockIssuerKeys(action.AddedKeys, true), BlockIssuerKeysRemoved: t.BlockIssuerKeys(action.RemovedKeys, true), - PreviousUpdatedTime: prevAccountFields.BICUpdatedAt, + PreviousUpdatedSlot: prevAccountFields.BICUpdatedAt, NewExpirySlot: prevAccountFields.ExpirySlot, DelegationStakeChange: action.DelegationStakeChange, @@ -265,7 +265,7 @@ func (t *TestSuite) assertDiff(slot iotago.SlotIndex, accountID iotago.AccountID expectedAccountDiff := accountsSlotBuildData.SlotDiff[accountID] require.Equal(t.T, expectedAccountDiff.PreviousOutputID, actualDiff.PreviousOutputID) - require.Equal(t.T, expectedAccountDiff.PreviousUpdatedTime, actualDiff.PreviousUpdatedTime) + require.Equal(t.T, expectedAccountDiff.PreviousUpdatedSlot, actualDiff.PreviousUpdatedSlot) require.Equal(t.T, expectedAccountDiff.NewExpirySlot, actualDiff.NewExpirySlot) require.Equal(t.T, expectedAccountDiff.PreviousExpirySlot, actualDiff.PreviousExpirySlot) diff --git a/pkg/protocol/engine/accounts/credits.go b/pkg/protocol/engine/accounts/credits.go index a4df3e5b8..39d4d1b54 100644 --- a/pkg/protocol/engine/accounts/credits.go +++ b/pkg/protocol/engine/accounts/credits.go @@ -1,49 +1,64 @@ package accounts import ( - "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/hive.go/serializer/v2/marshalutil" + "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/serializer/v2" + "github.com/iotaledger/hive.go/serializer/v2/stream" iotago "github.com/iotaledger/iota.go/v4" ) +const BlockIssuanceCreditsBytesLength = serializer.Int64ByteSize + serializer.UInt32ByteSize + // BlockIssuanceCredits is a weight annotated with the slot it was last updated in. type BlockIssuanceCredits struct { Value iotago.BlockIssuanceCredits - UpdateTime iotago.SlotIndex + UpdateSlot iotago.SlotIndex } // NewBlockIssuanceCredits creates a new Credits instance. func NewBlockIssuanceCredits(value iotago.BlockIssuanceCredits, updateTime iotago.SlotIndex) (newCredits *BlockIssuanceCredits) { return &BlockIssuanceCredits{ Value: value, - UpdateTime: updateTime, + UpdateSlot: updateTime, } } // Bytes returns a serialized version of the Credits. -func (c BlockIssuanceCredits) Bytes() ([]byte, error) { - m := marshalutil.New() +func (c *BlockIssuanceCredits) Bytes() ([]byte, error) { + byteBuffer := stream.NewByteBuffer() + + if err := stream.Write(byteBuffer, c.Value); err != nil { + return nil, ierrors.Wrap(err, "failed to write value") + } - m.WriteInt64(int64(c.Value)) - m.WriteUint32(uint32(c.UpdateTime)) + if err := stream.Write(byteBuffer, c.UpdateSlot); err != nil { + return nil, ierrors.Wrap(err, "failed to write updateTime") + } - return m.Bytes(), nil + return byteBuffer.Bytes() } -// FromBytes parses a serialized version of the Credits. -func (c *BlockIssuanceCredits) FromBytes(bytes []byte) (int, error) { - m := marshalutil.New(bytes) +func BlockIssuanceCreditsFromBytes(bytes []byte) (*BlockIssuanceCredits, int, error) { + c := new(BlockIssuanceCredits) - c.Value = iotago.BlockIssuanceCredits(lo.PanicOnErr(m.ReadInt64())) - c.UpdateTime = iotago.SlotIndex(lo.PanicOnErr(m.ReadUint32())) + var err error + byteReader := stream.NewByteReader(bytes) + + if c.Value, err = stream.Read[iotago.BlockIssuanceCredits](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read value") + } + + if c.UpdateSlot, err = stream.Read[iotago.SlotIndex](byteReader); err != nil { + return nil, 0, ierrors.Wrap(err, "failed to read updateTime") + } - return m.ReadOffset(), nil + return c, byteReader.BytesRead(), nil } // Update updates the Credits increasing Value and updateTime. -func (c *BlockIssuanceCredits) Update(change iotago.BlockIssuanceCredits, updateTime ...iotago.SlotIndex) { +func (c *BlockIssuanceCredits) Update(change iotago.BlockIssuanceCredits, updateSlot ...iotago.SlotIndex) { c.Value += change - if len(updateTime) > 0 { - c.UpdateTime = updateTime[0] + if len(updateSlot) > 0 { + c.UpdateSlot = updateSlot[0] } } diff --git a/pkg/protocol/engine/accounts/mana/manager.go b/pkg/protocol/engine/accounts/mana/manager.go index b53432329..d9c6ae32f 100644 --- a/pkg/protocol/engine/accounts/mana/manager.go +++ b/pkg/protocol/engine/accounts/mana/manager.go @@ -222,5 +222,5 @@ func (m *Manager) getBIC(accountID iotago.AccountID, slot iotago.SlotIndex) (bic return 0, 0, nil } - return iotago.Mana(accountBIC.Credits.Value), accountBIC.Credits.UpdateTime, nil + return iotago.Mana(accountBIC.Credits.Value), accountBIC.Credits.UpdateSlot, nil } diff --git a/pkg/protocol/engine/accounts/mana/manager_test.go b/pkg/protocol/engine/accounts/mana/manager_test.go index f4d58dd62..767367087 100644 --- a/pkg/protocol/engine/accounts/mana/manager_test.go +++ b/pkg/protocol/engine/accounts/mana/manager_test.go @@ -72,7 +72,7 @@ func TestManager_GetManaOnAccountOverflow(t *testing.T) { ID: id, Credits: &accounts.BlockIssuanceCredits{ Value: iotago.MaxBlockIssuanceCredits/2 + iotago.MaxBlockIssuanceCredits/4, - UpdateTime: 1, + UpdateSlot: 1, }, ExpirySlot: iotago.MaxSlotIndex, OutputID: iotago.OutputID{}, diff --git a/pkg/protocol/snapshotcreator/snapshotcreator.go b/pkg/protocol/snapshotcreator/snapshotcreator.go index 5223e0083..9f95c1520 100644 --- a/pkg/protocol/snapshotcreator/snapshotcreator.go +++ b/pkg/protocol/snapshotcreator/snapshotcreator.go @@ -82,7 +82,7 @@ func CreateSnapshot(opts ...options.Option[Options]) error { accountID := blake2b.Sum256(ed25519PubKey[:]) committeeAccountsData = append(committeeAccountsData, &accounts.AccountData{ ID: accountID, - Credits: &accounts.BlockIssuanceCredits{Value: snapshotAccountDetails.BlockIssuanceCredits, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: snapshotAccountDetails.BlockIssuanceCredits, UpdateSlot: 0}, ExpirySlot: snapshotAccountDetails.ExpirySlot, OutputID: iotago.OutputID{}, BlockIssuerKeys: iotago.BlockIssuerKeys{snapshotAccountDetails.IssuerKey}, diff --git a/pkg/tests/accounts_test.go b/pkg/tests/accounts_test.go index 1195eba30..d73d85ab1 100644 --- a/pkg/tests/accounts_test.go +++ b/pkg/tests/accounts_test.go @@ -109,7 +109,7 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountDiff(genesisAccountOutput.AccountID, block1Slot, &model.AccountDiff{ BICChange: 0, - PreviousUpdatedTime: 0, + PreviousUpdatedSlot: 0, PreviousExpirySlot: 1, NewExpirySlot: 1, NewOutputID: iotago.OutputIDFromTransactionIDAndIndex(ts.TransactionFramework.TransactionID("TX1"), 0), @@ -167,7 +167,7 @@ func Test_TransitionAccount(t *testing.T) { // assert diff of a destroyed account, to make sure we can correctly restore it ts.AssertAccountDiff(genesisAccountOutput.AccountID, block2Slot, &model.AccountDiff{ BICChange: -iotago.BlockIssuanceCredits(123), - PreviousUpdatedTime: 0, + PreviousUpdatedSlot: 0, NewExpirySlot: 0, PreviousExpirySlot: 1, NewOutputID: iotago.EmptyOutputID, @@ -185,7 +185,7 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountDiff(newAccountOutput.AccountID, block2Slot, &model.AccountDiff{ BICChange: 0, - PreviousUpdatedTime: 0, + PreviousUpdatedSlot: 0, NewExpirySlot: newAccountExpirySlot, PreviousExpirySlot: 0, NewOutputID: newAccount.OutputID(), @@ -237,7 +237,7 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountDiff(newAccountOutput.AccountID, block3Slot, &model.AccountDiff{ BICChange: 0, - PreviousUpdatedTime: 0, + PreviousUpdatedSlot: 0, NewOutputID: iotago.EmptyOutputID, PreviousOutputID: iotago.EmptyOutputID, BlockIssuerKeysAdded: iotago.NewBlockIssuerKeys(), @@ -283,7 +283,7 @@ func Test_TransitionAccount(t *testing.T) { // Transitioning to delayed claiming effectively removes the delegation, so we expect a negative delegation stake change. ts.AssertAccountDiff(newAccountOutput.AccountID, block4Slot, &model.AccountDiff{ BICChange: 0, - PreviousUpdatedTime: 0, + PreviousUpdatedSlot: 0, NewOutputID: iotago.EmptyOutputID, PreviousOutputID: iotago.EmptyOutputID, BlockIssuerKeysAdded: iotago.NewBlockIssuerKeys(), @@ -370,7 +370,7 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountDiff(implicitAccountID, slotIndexBlock6, &model.AccountDiff{ BICChange: 0, - PreviousUpdatedTime: 0, + PreviousUpdatedSlot: 0, NewOutputID: fullAccountOutputID, PreviousOutputID: implicitAccountOutputID, PreviousExpirySlot: iotago.MaxSlotIndex, diff --git a/pkg/tests/upgrade_signaling_test.go b/pkg/tests/upgrade_signaling_test.go index b5ce6336b..85961acfd 100644 --- a/pkg/tests/upgrade_signaling_test.go +++ b/pkg/tests/upgrade_signaling_test.go @@ -131,7 +131,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: ts.Node("nodeA").Validator.AccountID, - Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateSlot: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), @@ -144,7 +144,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: ts.DefaultBasicBlockIssuer().AccountID, - Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateSlot: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:5").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.DefaultBasicBlockIssuer().PublicKey))), @@ -165,7 +165,7 @@ func Test_Upgrade_Signaling(t *testing.T) { // check account data before all nodes set the current version ts.AssertAccountData(&accounts.AccountData{ ID: ts.Node("nodeA").Validator.AccountID, - Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateSlot: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), @@ -178,7 +178,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: ts.Node("nodeD").Validator.AccountID, - Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateSlot: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:4").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeD").Validator.PublicKey))), @@ -199,7 +199,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: ts.Node("nodeA").Validator.AccountID, - Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateSlot: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), @@ -364,7 +364,7 @@ func Test_Upgrade_Signaling(t *testing.T) { // check account data at the end of the test ts.AssertAccountData(&accounts.AccountData{ ID: ts.Node("nodeA").Validator.AccountID, - Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateSlot: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), @@ -377,7 +377,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: ts.Node("nodeD").Validator.AccountID, - Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, + Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateSlot: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:4").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeD").Validator.PublicKey))), diff --git a/pkg/testsuite/accounts.go b/pkg/testsuite/accounts.go index b3683761a..715276ef4 100644 --- a/pkg/testsuite/accounts.go +++ b/pkg/testsuite/accounts.go @@ -29,8 +29,8 @@ func (t *TestSuite) AssertAccountData(accountData *accounts.AccountData, nodes . return ierrors.Errorf("AssertAccountData: %s: accountID %s expected credits value %d, got %d", node.Name, accountData.ID, accountData.Credits.Value, actualAccountData.Credits.Value) } - if accountData.Credits.UpdateTime != actualAccountData.Credits.UpdateTime { - return ierrors.Errorf("AssertAccountData: %s: accountID %s expected credits update time %d, got %d", node.Name, accountData.ID, accountData.Credits.UpdateTime, actualAccountData.Credits.UpdateTime) + if accountData.Credits.UpdateSlot != actualAccountData.Credits.UpdateSlot { + return ierrors.Errorf("AssertAccountData: %s: accountID %s expected credits update time %d, got %d", node.Name, accountData.ID, accountData.Credits.UpdateSlot, actualAccountData.Credits.UpdateSlot) } if accountData.OutputID != actualAccountData.OutputID { @@ -98,8 +98,8 @@ func (t *TestSuite) AssertAccountDiff(accountID iotago.AccountID, index iotago.S return ierrors.Errorf("AssertAccountDiff: %s: expected change %d but actual %d for account %s at slot %d", node.Name, accountDiff.BICChange, actualAccountDiff.BICChange, accountID, index) } - if accountDiff.PreviousUpdatedTime != actualAccountDiff.PreviousUpdatedTime { - return ierrors.Errorf("AssertAccountDiff: %s: expected previous updated time %d but actual %d for account %s at slot %d", node.Name, accountDiff.PreviousUpdatedTime, actualAccountDiff.PreviousUpdatedTime, accountID, index) + if accountDiff.PreviousUpdatedSlot != actualAccountDiff.PreviousUpdatedSlot { + return ierrors.Errorf("AssertAccountDiff: %s: expected previous updated time %d but actual %d for account %s at slot %d", node.Name, accountDiff.PreviousUpdatedSlot, actualAccountDiff.PreviousUpdatedSlot, accountID, index) } if accountDiff.NewExpirySlot != actualAccountDiff.NewExpirySlot {