diff --git a/Dockerfile b/Dockerfile index 44a17fda1..ec10c0f75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,6 +35,8 @@ RUN cp ./peering.json /app/peering.json # using distroless cc "nonroot" image, which includes everything in the base image (glibc, libssl and openssl) FROM gcr.io/distroless/cc-debian12:nonroot +HEALTHCHECK --interval=10s --timeout=5s --retries=30 CMD ["/app/iota-core", "tools", "node-info"] + # Copy the app dir into distroless image COPY --chown=nonroot:nonroot --from=build /app /app diff --git a/Dockerfile.dev b/Dockerfile.dev index e9073b384..f91006d26 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -61,6 +61,8 @@ RUN mkdir -p /app/data/peerdb # using distroless cc "nonroot" image, which includes everything in the base image (glibc, libssl and openssl) FROM gcr.io/distroless/cc-debian12:nonroot +HEALTHCHECK --interval=10s --timeout=5s --retries=30 CMD ["/app/iota-core", "tools", "node-info"] + # Copy the app dir into distroless image COPY --chown=nonroot:nonroot --from=build /app /app diff --git a/components/app/app.go b/components/app/app.go index 4cb029500..5c4b42957 100644 --- a/components/app/app.go +++ b/components/app/app.go @@ -1,6 +1,9 @@ package app import ( + "fmt" + "os" + "github.com/iotaledger/hive.go/app" "github.com/iotaledger/hive.go/app/components/profiling" "github.com/iotaledger/hive.go/app/components/shutdown" @@ -15,6 +18,7 @@ import ( "github.com/iotaledger/iota-core/components/restapi" coreapi "github.com/iotaledger/iota-core/components/restapi/core" "github.com/iotaledger/iota-core/components/validator" + "github.com/iotaledger/iota-core/pkg/toolset" ) var ( @@ -28,6 +32,12 @@ var ( func App() *app.App { return app.New(Name, Version, // app.WithVersionCheck("iotaledger", "iota-core"), + app.WithUsageText(fmt.Sprintf(`Usage of %s (%s %s): + +Run '%s tools' to list all available tools. + +Command line flags: +`, os.Args[0], Name, Version, os.Args[0])), app.WithInitComponent(InitComponent), app.WithComponents( shutdown.Component, @@ -63,5 +73,15 @@ func init() { AdditionalConfigs: []*app.ConfigurationSet{ app.NewConfigurationSet("peering", "peering", "peeringConfigFilePath", "peeringConfig", false, true, false, "peering.json", "n"), }, + Init: initialize, + } +} + +func initialize(_ *app.App) error { + if toolset.ShouldHandleTools() { + toolset.HandleTools() + // HandleTools will call os.Exit } + + return nil } diff --git a/components/dashboard/explorer_routes.go b/components/dashboard/explorer_routes.go index ade3c3622..4918fc2f8 100644 --- a/components/dashboard/explorer_routes.go +++ b/components/dashboard/explorer_routes.go @@ -105,7 +105,7 @@ func createExplorerBlock(block *model.Block, cachedBlock *blocks.Block, metadata var payloadJSON []byte basicBlock, isBasic := block.BasicBlock() if isBasic { - payloadJSON, err = lo.PanicOnErr(deps.Protocol.APIForVersion(iotaBlk.ProtocolVersion)).JSONEncode(basicBlock.Payload) + payloadJSON, err = lo.PanicOnErr(deps.Protocol.APIForVersion(iotaBlk.Header.ProtocolVersion)).JSONEncode(basicBlock.Payload) if err != nil { return nil } @@ -113,16 +113,16 @@ func createExplorerBlock(block *model.Block, cachedBlock *blocks.Block, metadata t := &ExplorerBlock{ ID: block.ID().ToHex(), - NetworkID: iotaBlk.NetworkID, - ProtocolVersion: iotaBlk.ProtocolVersion, + NetworkID: iotaBlk.Header.NetworkID, + ProtocolVersion: iotaBlk.Header.ProtocolVersion, SolidificationTimestamp: 0, - IssuanceTimestamp: iotaBlk.IssuingTime.Unix(), + IssuanceTimestamp: iotaBlk.Header.IssuingTime.Unix(), SequenceNumber: 0, - IssuerID: iotaBlk.IssuerID.ToHex(), + IssuerID: iotaBlk.Header.IssuerID.ToHex(), Signature: hexutil.EncodeHex(sigBytes), - StrongParents: iotaBlk.Block.StrongParentIDs().ToHex(), - WeakParents: iotaBlk.Block.WeakParentIDs().ToHex(), - ShallowLikedParents: iotaBlk.Block.ShallowLikeParentIDs().ToHex(), + StrongParents: iotaBlk.Body.StrongParentIDs().ToHex(), + WeakParents: iotaBlk.Body.WeakParentIDs().ToHex(), + ShallowLikedParents: iotaBlk.Body.ShallowLikeParentIDs().ToHex(), PayloadType: func() iotago.PayloadType { if isBasic && basicBlock.Payload != nil { @@ -152,8 +152,8 @@ func createExplorerBlock(block *model.Block, cachedBlock *blocks.Block, metadata return "" }(), - CommitmentID: iotaBlk.SlotCommitmentID.ToHex(), - LatestConfirmedSlot: uint64(iotaBlk.LatestFinalizedSlot), + CommitmentID: iotaBlk.Header.SlotCommitmentID.ToHex(), + LatestConfirmedSlot: uint64(iotaBlk.Header.LatestFinalizedSlot), } if cachedBlock != nil { diff --git a/components/dashboard/visualizer.go b/components/dashboard/visualizer.go index 305348031..3788bbf76 100644 --- a/components/dashboard/visualizer.go +++ b/components/dashboard/visualizer.go @@ -48,9 +48,9 @@ func sendVertex(blk *blocks.Block, confirmed bool) { broadcastWsBlock(&wsblk{MsgTypeVertex, &vertex{ ID: blk.ID().ToHex(), - StrongParents: blk.ProtocolBlock().Block.StrongParentIDs().ToHex(), - WeakParents: blk.ProtocolBlock().Block.WeakParentIDs().ToHex(), - ShallowLikedParents: blk.ProtocolBlock().Block.ShallowLikeParentIDs().ToHex(), + StrongParents: blk.ProtocolBlock().Body.StrongParentIDs().ToHex(), + WeakParents: blk.ProtocolBlock().Body.WeakParentIDs().ToHex(), + ShallowLikedParents: blk.ProtocolBlock().Body.ShallowLikeParentIDs().ToHex(), IsConfirmed: confirmed, IsTx: isTx, IsTxAccepted: func() bool { diff --git a/components/debugapi/debug_models.go b/components/debugapi/debug_models.go index 3ec7eba94..8343b91af 100644 --- a/components/debugapi/debug_models.go +++ b/components/debugapi/debug_models.go @@ -72,8 +72,8 @@ func BlockMetadataResponseFromBlock(block *blocks.Block) *BlockMetadataResponse return &BlockMetadataResponse{ BlockID: block.ID().String(), StrongParents: lo.Map(block.StrongParents(), func(blockID iotago.BlockID) string { return blockID.String() }), - WeakParents: lo.Map(block.ProtocolBlock().Block.WeakParentIDs(), func(blockID iotago.BlockID) string { return blockID.String() }), - ShallowLikeParents: lo.Map(block.ProtocolBlock().Block.ShallowLikeParentIDs(), func(blockID iotago.BlockID) string { return blockID.String() }), + WeakParents: lo.Map(block.ProtocolBlock().Body.WeakParentIDs(), func(blockID iotago.BlockID) string { return blockID.String() }), + ShallowLikeParents: lo.Map(block.ProtocolBlock().Body.ShallowLikeParentIDs(), func(blockID iotago.BlockID) string { return blockID.String() }), Solid: block.IsSolid(), Invalid: block.IsInvalid(), Booked: block.IsBooked(), diff --git a/components/inx/server_blocks.go b/components/inx/server_blocks.go index 77a5e9b77..63b6b076e 100644 --- a/components/inx/server_blocks.go +++ b/components/inx/server_blocks.go @@ -126,7 +126,7 @@ func (s *Server) SubmitBlock(ctx context.Context, rawBlock *inx.RawBlock) (*inx. return s.attachBlock(ctx, block) } -func (s *Server) attachBlock(ctx context.Context, block *iotago.ProtocolBlock) (*inx.BlockId, error) { +func (s *Server) attachBlock(ctx context.Context, block *iotago.Block) (*inx.BlockId, error) { mergedCtx, mergedCtxCancel := contextutils.MergeContexts(ctx, Component.Daemon().ContextStopped()) defer mergedCtxCancel() diff --git a/components/metrics/metrics_accounts.go b/components/metrics/metrics_accounts.go index a6950ba5e..ec7f7e3e5 100644 --- a/components/metrics/metrics_accounts.go +++ b/components/metrics/metrics_accounts.go @@ -23,7 +23,7 @@ var AccountMetrics = collector.NewCollection(accountNamespace, collector.WithPruningDelay(10*time.Minute), collector.WithInitFunc(func() { deps.Protocol.Events.Engine.BlockGadget.BlockAccepted.Hook(func(block *blocks.Block) { - accountData, exists, _ := deps.Protocol.MainEngineInstance().Ledger.Account(block.ProtocolBlock().IssuerID, deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment().Slot()) + accountData, exists, _ := deps.Protocol.MainEngineInstance().Ledger.Account(block.ProtocolBlock().Header.IssuerID, deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment().Slot()) if exists { deps.Collector.Update(accountNamespace, credits, float64(accountData.Credits.Value), accountData.ID.String()) } diff --git a/components/metrics/metrics_scheduler.go b/components/metrics/metrics_scheduler.go index 2d2896584..f23b17221 100644 --- a/components/metrics/metrics_scheduler.go +++ b/components/metrics/metrics_scheduler.go @@ -38,22 +38,22 @@ var SchedulerMetrics = collector.NewCollection(schedulerNamespace, collector.WithHelp("Current size of each node's queue (in work units)."), collector.WithInitFunc(func() { deps.Protocol.Events.Engine.Scheduler.BlockEnqueued.Hook(func(block *blocks.Block) { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockSkipped.Hook(func(block *blocks.Block) { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockDropped.Hook(func(block *blocks.Block, _ error) { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockScheduled.Hook(func(block *blocks.Block) { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeWork, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueWork(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) }, event.WithWorkerPool(Component.WorkerPool)) }), @@ -66,25 +66,25 @@ var SchedulerMetrics = collector.NewCollection(schedulerNamespace, collector.WithInitFunc(func() { deps.Protocol.Events.Engine.Scheduler.BlockEnqueued.Hook(func(block *blocks.Block) { if _, isBasic := block.BasicBlock(); isBasic { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockSkipped.Hook(func(block *blocks.Block) { if _, isBasic := block.BasicBlock(); isBasic { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockDropped.Hook(func(block *blocks.Block, _ error) { if _, isBasic := block.BasicBlock(); isBasic { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockScheduled.Hook(func(block *blocks.Block) { if _, isBasic := block.BasicBlock(); isBasic { - deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, queueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.IssuerQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) }), @@ -97,25 +97,25 @@ var SchedulerMetrics = collector.NewCollection(schedulerNamespace, collector.WithInitFunc(func() { deps.Protocol.Events.Engine.Scheduler.BlockEnqueued.Hook(func(block *blocks.Block) { if _, isValidation := block.ValidationBlock(); isValidation { - deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockSkipped.Hook(func(block *blocks.Block) { if _, isValidation := block.ValidationBlock(); isValidation { - deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockDropped.Hook(func(block *blocks.Block, _ error) { if _, isValidation := block.ValidationBlock(); isValidation { - deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) deps.Protocol.Events.Engine.Scheduler.BlockScheduled.Hook(func(block *blocks.Block) { if _, isValidation := block.ValidationBlock(); isValidation { - deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().IssuerID)), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, validatorQueueSizePerNodeCount, float64(deps.Protocol.MainEngineInstance().Scheduler.ValidatorQueueBlockCount(block.ProtocolBlock().Header.IssuerID)), block.ProtocolBlock().Header.IssuerID.String()) } }, event.WithWorkerPool(Component.WorkerPool)) }), @@ -127,14 +127,14 @@ var SchedulerMetrics = collector.NewCollection(schedulerNamespace, collector.WithHelp("Current amount of mana of each issuer in the queue."), collector.WithInitFunc(func() { deps.Protocol.Events.Engine.Scheduler.BlockEnqueued.Hook(func(block *blocks.Block) { - mana, err := deps.Protocol.MainEngineInstance().Ledger.ManaManager().GetManaOnAccount(block.ProtocolBlock().IssuerID, block.SlotCommitmentID().Slot()) + mana, err := deps.Protocol.MainEngineInstance().Ledger.ManaManager().GetManaOnAccount(block.ProtocolBlock().Header.IssuerID, block.SlotCommitmentID().Slot()) if err != nil { - deps.Protocol.MainEngineInstance().ErrorHandler("metrics")(ierrors.Wrapf(err, "failed to retrieve mana on account %s for slot %d", block.ProtocolBlock().IssuerID, block.SlotCommitmentID().Slot())) + deps.Protocol.MainEngineInstance().ErrorHandler("metrics")(ierrors.Wrapf(err, "failed to retrieve mana on account %s for slot %d", block.ProtocolBlock().Header.IssuerID, block.SlotCommitmentID().Slot())) return } - deps.Collector.Update(schedulerNamespace, manaAmountPerNode, float64(mana), block.ProtocolBlock().IssuerID.String()) + deps.Collector.Update(schedulerNamespace, manaAmountPerNode, float64(mana), block.ProtocolBlock().Header.IssuerID.String()) }, event.WithWorkerPool(Component.WorkerPool)) }), )), diff --git a/components/p2p/component.go b/components/p2p/component.go index 9635df585..dff432bb7 100644 --- a/components/p2p/component.go +++ b/components/p2p/component.go @@ -230,7 +230,7 @@ func provide(c *dig.Container) error { if err := c.Provide(func(deps p2pDeps) p2pResult { res := p2pResult{} - privKeyFilePath := filepath.Join(deps.P2PDatabasePath, "identity.key") + privKeyFilePath := filepath.Join(deps.P2PDatabasePath, IdentityPrivateKeyFileName) // make sure nobody copies around the peer store since it contains the private key of the node Component.LogInfof(`WARNING: never share your "%s" folder as it contains your node's private key!`, deps.P2PDatabasePath) diff --git a/components/p2p/params.go b/components/p2p/params.go index 37f099d85..7b2cba4e7 100644 --- a/components/p2p/params.go +++ b/components/p2p/params.go @@ -6,7 +6,8 @@ import ( const ( // CfgPeers defines the static peers this node should retain a connection to (CLI). - CfgPeers = "peers" + CfgPeers = "peers" + IdentityPrivateKeyFileName = "identity.key" ) // ParametersP2P contains the definition of configuration parameters used by the p2p plugin. diff --git a/components/restapi/core/accounts.go b/components/restapi/core/accounts.go index 995e7db33..91c6211c3 100644 --- a/components/restapi/core/accounts.go +++ b/components/restapi/core/accounts.go @@ -26,10 +26,10 @@ func congestionForAccountID(c echo.Context) (*apimodels.CongestionResponse, erro acc, exists, err := deps.Protocol.MainEngineInstance().Ledger.Account(accountID, commitment.Slot()) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get account: %s form the Ledger", accountID.ToHex()) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get account %s from the Ledger: %s", accountID.ToHex(), err) } if !exists { - return nil, ierrors.Errorf("account not found: %s", accountID.ToHex()) + return nil, ierrors.Wrapf(echo.ErrNotFound, "account not found: %s", accountID.ToHex()) } return &apimodels.CongestionResponse{ @@ -46,7 +46,7 @@ func validators(c echo.Context) (*apimodels.ValidatorsResponse, error) { if len(c.QueryParam(restapipkg.QueryParameterPageSize)) > 0 { pageSize, err = httpserver.ParseUint32QueryParam(c, restapipkg.QueryParameterPageSize) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse the %s parameter", restapipkg.QueryParameterPageSize) + return nil, ierrors.Wrapf(err, "failed to parse page size %s", c.Param(restapipkg.QueryParameterPageSize)) } if pageSize > restapi.ParamsRestAPI.MaxPageSize { pageSize = restapi.ParamsRestAPI.MaxPageSize @@ -59,13 +59,13 @@ func validators(c echo.Context) (*apimodels.ValidatorsResponse, error) { if len(c.QueryParam(restapipkg.QueryParameterCursor)) != 0 { requestedSlot, cursorIndex, err = httpserver.ParseCursorQueryParam(c, restapipkg.QueryParameterCursor) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse the %s parameter", restapipkg.QueryParameterCursor) + return nil, ierrors.Wrapf(err, "failed to parse cursor %s", c.Param(restapipkg.QueryParameterCursor)) } } // do not respond to really old requests if requestedSlot+iotago.SlotIndex(restapi.ParamsRestAPI.MaxRequestedSlotAge) < latestCommittedSlot { - return nil, ierrors.Errorf("request is too old, request started at %d, latest committed slot index is %d", requestedSlot, latestCommittedSlot) + return nil, ierrors.Wrapf(echo.ErrBadRequest, "request is too old, request started at %d, latest committed slot index is %d", requestedSlot, latestCommittedSlot) } nextEpoch := deps.Protocol.APIForSlot(latestCommittedSlot).TimeProvider().EpochFromSlot(latestCommittedSlot) + 1 @@ -75,7 +75,7 @@ func validators(c echo.Context) (*apimodels.ValidatorsResponse, error) { if !exists { registeredValidators, err = deps.Protocol.MainEngineInstance().SybilProtection.OrderedRegisteredCandidateValidatorsList(nextEpoch) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get ordered registered validators list for epoch %d", nextEpoch) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get ordered registered validators list for epoch %d : %s", nextEpoch, err) } deps.Protocol.MainEngineInstance().Retainer.RetainRegisteredValidatorsCache(slotRange, registeredValidators) } @@ -98,16 +98,16 @@ func validators(c echo.Context) (*apimodels.ValidatorsResponse, error) { func validatorByAccountID(c echo.Context) (*apimodels.ValidatorResponse, error) { accountID, err := httpserver.ParseAccountIDParam(c, restapipkg.ParameterAccountID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse the %s parameter", restapipkg.ParameterAccountID) + return nil, ierrors.Wrapf(err, "failed to parse account ID %s", c.Param(restapipkg.ParameterAccountID)) } latestCommittedSlot := deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment().Slot() accountData, exists, err := deps.Protocol.MainEngineInstance().Ledger.Account(accountID, latestCommittedSlot) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get account: %s form the Ledger", accountID.ToHex()) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get account %s from the Ledger: %s", accountID.ToHex(), err) } if !exists { - return nil, ierrors.Errorf("account not found: %s for latest committedSlot %d", accountID.ToHex(), latestCommittedSlot) + return nil, ierrors.Wrapf(echo.ErrNotFound, "account %s not found for latest committedSlot %d", accountID.ToHex(), latestCommittedSlot) } nextEpoch := deps.Protocol.APIForSlot(latestCommittedSlot).TimeProvider().EpochFromSlot(latestCommittedSlot) + 1 @@ -131,12 +131,12 @@ func validatorByAccountID(c echo.Context) (*apimodels.ValidatorResponse, error) func rewardsByOutputID(c echo.Context) (*apimodels.ManaRewardsResponse, error) { outputID, err := httpserver.ParseOutputIDParam(c, restapipkg.ParameterOutputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse the %s parameter", restapipkg.ParameterOutputID) + return nil, ierrors.Wrapf(err, "failed to parse output ID %s", c.Param(restapipkg.ParameterOutputID)) } utxoOutput, err := deps.Protocol.MainEngineInstance().Ledger.Output(outputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get output %s from ledger", outputID.ToHex()) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get output %s from ledger: %s", outputID.ToHex(), err) } var reward iotago.Mana @@ -147,7 +147,7 @@ func rewardsByOutputID(c echo.Context) (*apimodels.ManaRewardsResponse, error) { accountOutput := utxoOutput.Output().(*iotago.AccountOutput) feature, exists := accountOutput.FeatureSet()[iotago.FeatureStaking] if !exists { - return nil, ierrors.Errorf("account %s is not a validator", outputID) + return nil, ierrors.Wrapf(echo.ErrBadRequest, "account %s is not a validator", outputID.ToHex()) } //nolint:forcetypeassert @@ -178,7 +178,7 @@ func rewardsByOutputID(c echo.Context) (*apimodels.ManaRewardsResponse, error) { ) } if err != nil { - return nil, ierrors.Wrapf(err, "failed to calculate reward for output %s", outputID) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to calculate reward for output %s: %s", outputID.ToHex(), err) } return &apimodels.ManaRewardsResponse{ diff --git a/components/restapi/core/blocks.go b/components/restapi/core/blocks.go index 03c3598d6..554fdfa08 100644 --- a/components/restapi/core/blocks.go +++ b/components/restapi/core/blocks.go @@ -15,12 +15,12 @@ import ( func blockByID(c echo.Context) (*model.Block, error) { blockID, err := httpserver.ParseBlockIDParam(c, restapi.ParameterBlockID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse block ID: %s", c.Param(restapi.ParameterBlockID)) + return nil, ierrors.Wrapf(err, "failed to parse block ID %s", c.Param(restapi.ParameterBlockID)) } block, exists := deps.Protocol.MainEngineInstance().Block(blockID) if !exists { - return nil, ierrors.Errorf("block not found: %s", blockID.ToHex()) + return nil, ierrors.Wrapf(echo.ErrNotFound, "block not found: %s", blockID.ToHex()) } return block, nil @@ -29,7 +29,7 @@ func blockByID(c echo.Context) (*model.Block, error) { func blockMetadataByBlockID(blockID iotago.BlockID) (*apimodels.BlockMetadataResponse, error) { blockMetadata, err := deps.Protocol.MainEngineInstance().Retainer.BlockMetadata(blockID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get block metadata: %s", blockID.ToHex()) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get block metadata %s: %s", blockID.ToHex(), err) } return blockMetadata.BlockMetadataResponse(), nil @@ -38,7 +38,7 @@ func blockMetadataByBlockID(blockID iotago.BlockID) (*apimodels.BlockMetadataRes func blockMetadataByID(c echo.Context) (*apimodels.BlockMetadataResponse, error) { blockID, err := httpserver.ParseBlockIDParam(c, restapi.ParameterBlockID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse block ID: %s", c.Param(restapi.ParameterBlockID)) + return nil, ierrors.Wrapf(err, "failed to parse block ID %s", c.Param(restapi.ParameterBlockID)) } return blockMetadataByBlockID(blockID) @@ -55,7 +55,7 @@ func blockIssuanceBySlot(slotIndex iotago.SlotIndex) (*apimodels.IssuanceBlockHe } else { slotCommitment, err = deps.Protocol.MainEngineInstance().Storage.Commitments().Load(slotIndex) if err != nil { - return nil, ierrors.Wrapf(err, "failed to load commitment for requested slot %d", slotIndex) + return nil, ierrors.Wrapf(echo.ErrNotFound, "failed to load commitment for requested slot %d: %s", slotIndex, err) } } @@ -75,9 +75,9 @@ func blockIssuanceBySlot(slotIndex iotago.SlotIndex) (*apimodels.IssuanceBlockHe } func sendBlock(c echo.Context) (*apimodels.BlockCreatedResponse, error) { - iotaBlock, err := httpserver.ParseRequestByHeader(c, deps.Protocol.CommittedAPI(), iotago.ProtocolBlockFromBytes(deps.Protocol)) + iotaBlock, err := httpserver.ParseRequestByHeader(c, deps.Protocol.CommittedAPI(), iotago.BlockFromBytes(deps.Protocol)) if err != nil { - return nil, err + return nil, ierrors.Wrapf(err, "failed to parse iotablock") } blockID, err := deps.BlockHandler.AttachBlock(c.Request().Context(), iotaBlock) diff --git a/components/restapi/core/commitment.go b/components/restapi/core/commitment.go index 99059825c..4ff0f581d 100644 --- a/components/restapi/core/commitment.go +++ b/components/restapi/core/commitment.go @@ -13,7 +13,7 @@ import ( func indexByCommitmentID(c echo.Context) (iotago.SlotIndex, error) { commitmentID, err := httpserver.ParseCommitmentIDParam(c, restapipkg.ParameterCommitmentID) if err != nil { - return iotago.SlotIndex(0), ierrors.Wrapf(err, "failed to parse commitment ID: %s", c.Param(restapipkg.ParameterCommitmentID)) + return iotago.SlotIndex(0), ierrors.Wrapf(err, "failed to parse commitment ID %s", c.Param(restapipkg.ParameterCommitmentID)) } return commitmentID.Slot(), nil @@ -22,7 +22,7 @@ func indexByCommitmentID(c echo.Context) (iotago.SlotIndex, error) { func getCommitmentDetails(index iotago.SlotIndex) (*iotago.Commitment, error) { commitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(index) if err != nil { - return nil, ierrors.Wrapf(err, "failed to load commitment: %d", index) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment %d: %s", index, err) } return commitment.Commitment(), nil @@ -31,7 +31,7 @@ func getCommitmentDetails(index iotago.SlotIndex) (*iotago.Commitment, error) { func getUTXOChanges(slot iotago.SlotIndex) (*apimodels.UTXOChangesResponse, error) { diffs, err := deps.Protocol.MainEngineInstance().Ledger.SlotDiffs(slot) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get slot diffs: %d", slot) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get slot diffs %d: %s", slot, err) } createdOutputs := make(iotago.OutputIDs, len(diffs.Outputs)) diff --git a/components/restapi/core/transaction.go b/components/restapi/core/transaction.go index 44575426a..93f660134 100644 --- a/components/restapi/core/transaction.go +++ b/components/restapi/core/transaction.go @@ -14,7 +14,7 @@ import ( func blockIDByTransactionID(c echo.Context) (iotago.BlockID, error) { txID, err := httpserver.ParseTransactionIDParam(c, restapipkg.ParameterTransactionID) if err != nil { - return iotago.EmptyBlockID, ierrors.Wrapf(err, "failed to parse transaction ID: %s", c.Param(restapipkg.ParameterTransactionID)) + return iotago.EmptyBlockID, ierrors.Wrapf(err, "failed to parse transaction ID %s", c.Param(restapipkg.ParameterTransactionID)) } return blockIDFromTransactionID(txID) @@ -26,7 +26,7 @@ func blockIDFromTransactionID(transactionID iotago.TransactionID) (iotago.BlockI output, spent, err := deps.Protocol.MainEngineInstance().Ledger.OutputOrSpent(outputID) if err != nil { - return iotago.EmptyBlockID, ierrors.Wrapf(err, "failed to get output: %s", outputID.ToHex()) + return iotago.EmptyBlockID, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get output %s: %s", outputID.ToHex(), err) } if output != nil { @@ -39,12 +39,12 @@ func blockIDFromTransactionID(transactionID iotago.TransactionID) (iotago.BlockI func blockByTransactionID(c echo.Context) (*model.Block, error) { blockID, err := blockIDByTransactionID(c) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get block ID by transaction ID") + return nil, ierrors.Wrapf(echo.ErrBadRequest, "failed to get block ID by transaction ID: %s", err) } block, exists := deps.Protocol.MainEngineInstance().Block(blockID) if !exists { - return nil, ierrors.Errorf("block not found: %s", blockID.String()) + return nil, ierrors.Wrapf(echo.ErrNotFound, "block not found: %s", blockID.ToHex()) } return block, nil @@ -53,7 +53,7 @@ func blockByTransactionID(c echo.Context) (*model.Block, error) { func blockMetadataFromTransactionID(c echo.Context) (*apimodels.BlockMetadataResponse, error) { blockID, err := blockIDByTransactionID(c) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get block ID by transaction ID") + return nil, ierrors.Wrapf(echo.ErrBadRequest, "failed to get block ID by transaction ID: %s", err) } return blockMetadataByBlockID(blockID) diff --git a/components/restapi/core/utxo.go b/components/restapi/core/utxo.go index 196b6c514..bdf62c89c 100644 --- a/components/restapi/core/utxo.go +++ b/components/restapi/core/utxo.go @@ -13,12 +13,12 @@ import ( func getOutput(c echo.Context) (*apimodels.OutputResponse, error) { outputID, err := httpserver.ParseOutputIDParam(c, restapipkg.ParameterOutputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse output ID param: %s", c.Param(restapipkg.ParameterOutputID)) + return nil, ierrors.Wrapf(err, "failed to parse output ID %s", c.Param(restapipkg.ParameterOutputID)) } output, err := deps.Protocol.MainEngineInstance().Ledger.Output(outputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get output: %s from the Ledger", outputID.String()) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get output %s from the Ledger: %s", outputID.ToHex(), err) } return &apimodels.OutputResponse{ @@ -30,12 +30,12 @@ func getOutput(c echo.Context) (*apimodels.OutputResponse, error) { func getOutputMetadata(c echo.Context) (*apimodels.OutputMetadata, error) { outputID, err := httpserver.ParseOutputIDParam(c, restapipkg.ParameterOutputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse output ID param: %s", c.Param(restapipkg.ParameterOutputID)) + return nil, ierrors.Wrapf(err, "failed to parse output ID %s", c.Param(restapipkg.ParameterOutputID)) } output, spent, err := deps.Protocol.MainEngineInstance().Ledger.OutputOrSpent(outputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get output: %s from the Ledger", outputID.String()) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get output %s from the Ledger: %s", outputID.ToHex(), err) } if spent != nil { @@ -48,18 +48,18 @@ func getOutputMetadata(c echo.Context) (*apimodels.OutputMetadata, error) { func getOutputWithMetadata(c echo.Context) (*apimodels.OutputWithMetadataResponse, error) { outputID, err := httpserver.ParseOutputIDParam(c, restapipkg.ParameterOutputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to parse output ID param: %s", c.Param(restapipkg.ParameterOutputID)) + return nil, ierrors.Wrapf(err, "failed to parse output ID %s", c.Param(restapipkg.ParameterOutputID)) } output, spent, err := deps.Protocol.MainEngineInstance().Ledger.OutputOrSpent(outputID) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get output: %s from the Ledger", outputID.String()) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get output %s from the Ledger: %s", outputID.ToHex(), err) } if spent != nil { metadata, err := newSpentMetadataResponse(spent) if err != nil { - return nil, err + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load spent output metadata: %s", err) } return &apimodels.OutputWithMetadataResponse{ @@ -96,7 +96,7 @@ func newOutputMetadataResponse(output *utxoledger.Output) (*apimodels.OutputMeta if includedSlotIndex <= latestCommitment.Slot() { includedCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(includedSlotIndex) if err != nil { - return nil, ierrors.Wrapf(err, "failed to load commitment with index: %d", includedSlotIndex) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment with index %d: %s", includedSlotIndex, err) } resp.IncludedCommitmentID = includedCommitment.ID() } @@ -120,7 +120,7 @@ func newSpentMetadataResponse(spent *utxoledger.Spent) (*apimodels.OutputMetadat if includedSlotIndex <= latestCommitment.Slot() { includedCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(includedSlotIndex) if err != nil { - return nil, ierrors.Wrapf(err, "failed to load commitment with index: %d", includedSlotIndex) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment with index %d: %s", includedSlotIndex, err) } resp.IncludedCommitmentID = includedCommitment.ID() } @@ -129,7 +129,7 @@ func newSpentMetadataResponse(spent *utxoledger.Spent) (*apimodels.OutputMetadat if spentSlotIndex <= latestCommitment.Slot() { spentCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(spentSlotIndex) if err != nil { - return nil, ierrors.Wrapf(err, "failed to load commitment with index: %d", spentSlotIndex) + return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment with index %d: %s", spentSlotIndex, err) } resp.CommitmentIDSpent = spentCommitment.ID() } diff --git a/components/restapi/params.go b/components/restapi/params.go index 440fdc102..121d07ae8 100644 --- a/components/restapi/params.go +++ b/components/restapi/params.go @@ -9,7 +9,7 @@ type ParametersRestAPI struct { // Enabled defines whether the REST API plugin is enabled. Enabled bool `default:"true" usage:"whether the REST API plugin is enabled"` // the bind address on which the REST API listens on - BindAddress string `default:"0.0.0.0:8080" usage:"the bind address on which the REST API listens on"` + BindAddress string `default:"0.0.0.0:14265" usage:"the bind address on which the REST API listens on"` // the HTTP REST routes which can be called without authorization. Wildcards using * are allowed PublicRoutes []string `usage:"the HTTP REST routes which can be called without authorization. Wildcards using * are allowed"` // the HTTP REST routes which need to be called with authorization. Wildcards using * are allowed diff --git a/components/validator/issuer.go b/components/validator/issuer.go index 8a748b58f..038fb9e78 100644 --- a/components/validator/issuer.go +++ b/components/validator/issuer.go @@ -101,7 +101,7 @@ func issueValidatorBlock(ctx context.Context) { return } - Component.LogDebugf("Issued validator block: %s - commitment %s %d - latest finalized slot %d", modelBlock.ID(), modelBlock.ProtocolBlock().SlotCommitmentID, modelBlock.ProtocolBlock().SlotCommitmentID.Slot(), modelBlock.ProtocolBlock().LatestFinalizedSlot) + Component.LogDebugf("Issued validator block: %s - commitment %s %d - latest finalized slot %d", modelBlock.ID(), modelBlock.ProtocolBlock().Header.SlotCommitmentID, modelBlock.ProtocolBlock().Header.SlotCommitmentID.Slot(), modelBlock.ProtocolBlock().Header.LatestFinalizedSlot) } func reviveChain(issuingTime time.Time) (*iotago.Commitment, iotago.BlockID, error) { diff --git a/config_defaults.json b/config_defaults.json index 53114f287..f24471e14 100644 --- a/config_defaults.json +++ b/config_defaults.json @@ -44,7 +44,7 @@ }, "restAPI": { "enabled": true, - "bindAddress": "0.0.0.0:8080", + "bindAddress": "0.0.0.0:14265", "publicRoutes": [ "/health", "/api/routes", diff --git a/deploy/ansible/roles/iota-core-node/templates/docker-compose-iota-core.yml.j2 b/deploy/ansible/roles/iota-core-node/templates/docker-compose-iota-core.yml.j2 index a5284d45b..d3bc9d82b 100644 --- a/deploy/ansible/roles/iota-core-node/templates/docker-compose-iota-core.yml.j2 +++ b/deploy/ansible/roles/iota-core-node/templates/docker-compose-iota-core.yml.j2 @@ -26,7 +26,7 @@ services: ports: - "14666:14666/tcp" # P2P - "6061:6061/tcp" # pprof - - "8080:8080/tcp" # REST-API + - "8080:14265/tcp" # REST-API - "8081:8081/tcp" # Dashboard - "9311:9311/tcp" # Prometheus - "9029:9029/tcp" # INX @@ -46,7 +46,7 @@ services: --p2p.db.path=/app/data/peerdb --profiling.enabled=true --profiling.bindAddress=0.0.0.0:6061 - --restAPI.bindAddress=0.0.0.0:8080 + --restAPI.bindAddress=0.0.0.0:14265 --database.path=/app/data/database --protocol.snapshot.path=/app/data/snapshot.bin {% if 'node-01' in inventory_hostname or 'node-02' in inventory_hostname or 'node-03' in inventory_hostname %} @@ -73,7 +73,7 @@ services: restart: unless-stopped depends_on: iota-core: - condition: service_started + condition: service_healthy ulimits: nofile: soft: 16384 @@ -93,7 +93,7 @@ services: restart: unless-stopped depends_on: iota-core: - condition: service_started + condition: service_healthy inx-indexer: condition: service_started environment: @@ -111,7 +111,7 @@ services: restart: unless-stopped depends_on: iota-core: - condition: service_started + condition: service_healthy inx-indexer: condition: service_started inx-blockissuer: diff --git a/documentation/docs/references/configuration.md b/documentation/docs/references/configuration.md index bbcd516e6..ba034fde1 100644 --- a/documentation/docs/references/configuration.md +++ b/documentation/docs/references/configuration.md @@ -175,7 +175,7 @@ Example: | Name | Description | Type | Default value | | ------------------------------ | ---------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enabled | Whether the REST API plugin is enabled | boolean | true | -| bindAddress | The bind address on which the REST API listens on | string | "0.0.0.0:8080" | +| bindAddress | The bind address on which the REST API listens on | string | "0.0.0.0:14265" | | publicRoutes | The HTTP REST routes which can be called without authorization. Wildcards using \* are allowed | array | /health
/api/routes
/api/core/v3/info
/api/core/v3/blocks\*
/api/core/v3/transactions\*
/api/core/v3/commitments\*
/api/core/v3/outputs\*
/api/core/v3/accounts\*
/api/core/v3/validators\*
/api/core/v3/rewards\*
/api/core/v3/committee
/api/debug/v2/\*
/api/indexer/v2/\*
/api/mqtt/v2 | | protectedRoutes | The HTTP REST routes which need to be called with authorization. Wildcards using \* are allowed | array | /api/\* | | debugRequestLoggerEnabled | Whether the debug logging for requests should be enabled | boolean | false | @@ -204,7 +204,7 @@ Example: { "restAPI": { "enabled": true, - "bindAddress": "0.0.0.0:8080", + "bindAddress": "0.0.0.0:14265", "publicRoutes": [ "/health", "/api/routes", diff --git a/go.mod b/go.mod index 3895dd8e8..ec5d2d7d5 100644 --- a/go.mod +++ b/go.mod @@ -12,29 +12,31 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/iotaledger/hive.go/ads v0.0.0-20231020115340-13da292c580b github.com/iotaledger/hive.go/app v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b + github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42 github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b - github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b + github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42 github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b + github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42 github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b + github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42 github.com/iotaledger/hive.go/logger v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b + github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42 github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b - github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231023191159-38919c4705e0 - github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231023190837-6e7b2cdfd4fd - github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1 + github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42 + github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231028104239-869296c43f26 + github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231028104044-69b02af0058d + github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a github.com/labstack/echo/v4 v4.11.2 github.com/labstack/gommon v0.4.0 github.com/libp2p/go-libp2p v0.31.0 github.com/libp2p/go-libp2p-kad-dht v0.25.1 + github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-multiaddr v0.12.0 github.com/multiformats/go-varint v0.0.7 github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e github.com/otiai10/copy v1.14.0 github.com/prometheus/client_golang v1.17.0 + github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 github.com/wollac/iota-crypto-demo v0.0.0-20221117162917-b10619eccb98 github.com/zyedidia/generic v1.2.1 @@ -126,7 +128,6 @@ require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect @@ -157,7 +158,6 @@ require ( github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/cast v1.5.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect diff --git a/go.sum b/go.sum index 40540cd56..4bf13faa4 100644 --- a/go.sum +++ b/go.sum @@ -281,36 +281,36 @@ github.com/iotaledger/hive.go/ads v0.0.0-20231020115340-13da292c580b h1:D68khiAF github.com/iotaledger/hive.go/ads v0.0.0-20231020115340-13da292c580b/go.mod h1:IFh0gDfeMgZtfCo+5afK59IDR4xXh+cTR9YtLnZPcbY= github.com/iotaledger/hive.go/app v0.0.0-20231020115340-13da292c580b h1:mX3NXaTMLEwZnEs4IlxEvXY0YZo8qbb8M1xM39FS6qY= github.com/iotaledger/hive.go/app v0.0.0-20231020115340-13da292c580b/go.mod h1:8ZbIKR84oQd/3iQ5eeT7xpudO9/ytzXP7veIYnk7Orc= -github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b h1:HF4e0wz0JMIT4m3saqdQ//T9nWHV9d5sLMtEwNDuykM= -github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= +github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42 h1:drmpgLlJy7kZ09Dt1qKSnbILU+27Qu2jp4VdPDNwbFk= +github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b h1:ZERXxhQBUBV1AqTE6cUI4vTxSx4JrnsMuLZFgj32xLM= github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b/go.mod h1:Mc+ACqBGPxrPMIPUBOm6/HL0J6m0iVMwjtIEKW3uow8= -github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b h1:ZUUqRRO6XnQmVcXlXyx07vqySn28+bln6jp9KagYCjY= -github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b/go.mod h1:h3o6okvMSEK3KOX6pOp3yq1h9ohTkTfo6X8MzEadeb0= +github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42 h1:r8TkdQJB7/bJd8cF8z5GQ+rX/7JpbPdPoN7wMoV1OCM= +github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42/go.mod h1:h3o6okvMSEK3KOX6pOp3yq1h9ohTkTfo6X8MzEadeb0= github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b h1:8b2sH+2Vf0y5BDYTMwKa09iQr3JF9JrzTI64DkXb+9U= github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b/go.mod h1:3XkUSKfHaVxGbT0XAvjNlVYqPzhfLTGhDtdNA5UBPco= -github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b h1:JJPnr231djUTgTnE4oGz847WE9VA7Py6E6fgZwT5TQo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= +github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42 h1:QMxd32Y/veVhTDPCiOFgetjUbG7sr9MryF29/rSPkMA= +github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b h1:LusmtjpfG/q8lc15Fp9W3kABbN3tArKx/zw2ibdY1DU= github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b/go.mod h1:O/U3jtiUDeqqM0MZQFu2UPqS9fUm0C5hNISxlmg/thE= -github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b h1:UvFWI8wQJS/XQOeWHpPsaFVeS2nxJ7nIGFr+IFjrnVw= -github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b/go.mod h1:s4kzx9QY1MVWHJralj+3q5kI0eARtrJhphYD/iBbPfo= +github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42 h1:AvNLzONVMspwx7nD/NyYUgb5Hi7/zgzIOegr1uRD/M8= +github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42/go.mod h1:s4kzx9QY1MVWHJralj+3q5kI0eARtrJhphYD/iBbPfo= github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b h1:IwhoeOeRu25mBdrimuOOvbbhHYX0QipibV69ubn8nX0= github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b/go.mod h1:JvokzmpmFZPDskMlUqqjgHtD8usVJU4nAY/TNMGge8M= github.com/iotaledger/hive.go/logger v0.0.0-20231020115340-13da292c580b h1:EhVgAU/f2J3VYZwP60dRdyfAeDU3c/gBzX9blKtQGKA= github.com/iotaledger/hive.go/logger v0.0.0-20231020115340-13da292c580b/go.mod h1:aBfAfIB2GO/IblhYt5ipCbyeL9bXSNeAwtYVA3hZaHg= -github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b h1:O68POYIqBLnoHN+HIszc58QwAI2qocYq0WKGfVrXmMg= -github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b/go.mod h1:jRw8yFipiPaqmTPHh7hTcxAP9u6pjRGpByS3REJKkbY= +github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42 h1:1QMJ39qXIx/IZVzus3+97IV7Pa++e+d340TvbMjhiBU= +github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42/go.mod h1:jRw8yFipiPaqmTPHh7hTcxAP9u6pjRGpByS3REJKkbY= github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b h1:zaXZn9yV/95SRDkgCZQeBbSbmcJTKSZbCB7oBd71Qwg= github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b/go.mod h1:SdK26z8/VhWtxaqCuQrufm80SELgowQPmu9T/8eUQ8g= -github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b h1:MDZhTZTVDiydXcW5j4TA7HixVCyAdToIMPhHfJee7cE= -github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= -github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231023191159-38919c4705e0 h1:/8pbFXhTSroJvjJMfJqfHjzoT9N8B4LUY3SbKruD5MM= -github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231023191159-38919c4705e0/go.mod h1:My1SB4vZj42EgTDNJ/dgW8lUpLNmvtzu8f89J5y2kP0= -github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231023190837-6e7b2cdfd4fd h1:hh5mAnnaZHOYAi4CIqR9K/mv786ex9AQgpisbJ4ZMow= -github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231023190837-6e7b2cdfd4fd/go.mod h1:MK0SHfNicBmcaZb3qS3tA8NEJIWKNbcNtNNKuSDKqXY= -github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1 h1:7ChiFHg4KsdS4mKjYpFUUNe9t9nsQzNtJ/XnUV2w5ZM= -github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1/go.mod h1:jqbLYq4a/FwuiPBqFfkAwwxU8vs3+kReRq2/tyX5qRA= +github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42 h1:OlDhgvJ48bZxcvTeebJ1b96xtNnJAddejd2Q4rlH1mU= +github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= +github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231028104239-869296c43f26 h1:ZZs7IzdxrogQWGF1HfUUfR3KW8WhfxE4hUbfwZCDXFY= +github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231028104239-869296c43f26/go.mod h1:aFS0dN6QgKGgZakGgEv57NOLw+pLGdEiGcfDZ3h9GL0= +github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231028104044-69b02af0058d h1:0SVvkN04C+Ylc2puM/c77HuvRMmHRl0BkNjlZx1YWeA= +github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231028104044-69b02af0058d/go.mod h1:WFa5hHen6fi3RBX4K6r4fzhGpoh+7KJVIyFztZHdM84= +github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a h1:WLW4iaJAx4N9Pujv+gzHklnnjCt5MPrtXyVcK3UXdNc= +github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a/go.mod h1:jqbLYq4a/FwuiPBqFfkAwwxU8vs3+kReRq2/tyX5qRA= github.com/ipfs/boxo v0.13.1 h1:nQ5oQzcMZR3oL41REJDcTbrvDvuZh3J9ckc9+ILeRQI= github.com/ipfs/boxo v0.13.1/go.mod h1:btrtHy0lmO1ODMECbbEY1pxNtrLilvKSYLoGQt1yYCk= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= diff --git a/pkg/blockhandler/blockissuer.go b/pkg/blockhandler/blockissuer.go index ed6c99f01..b712bab88 100644 --- a/pkg/blockhandler/blockissuer.go +++ b/pkg/blockhandler/blockissuer.go @@ -94,7 +94,7 @@ func (i *BlockHandler) SubmitBlockAndAwaitEvent(ctx context.Context, block *mode } } -func (i *BlockHandler) AttachBlock(ctx context.Context, iotaBlock *iotago.ProtocolBlock) (iotago.BlockID, error) { +func (i *BlockHandler) AttachBlock(ctx context.Context, iotaBlock *iotago.Block) (iotago.BlockID, error) { modelBlock, err := model.BlockFromBlock(iotaBlock) if err != nil { return iotago.EmptyBlockID, ierrors.Wrap(err, "error serializing block to model block") diff --git a/pkg/model/block.go b/pkg/model/block.go index d5c212153..a41c491c0 100644 --- a/pkg/model/block.go +++ b/pkg/model/block.go @@ -11,45 +11,45 @@ import ( type Block struct { blockID iotago.BlockID - data []byte - protocolBlock *iotago.ProtocolBlock + data []byte + block *iotago.Block } -func newBlock(blockID iotago.BlockID, iotaBlock *iotago.ProtocolBlock, data []byte) (*Block, error) { +func newBlock(blockID iotago.BlockID, iotaBlock *iotago.Block, data []byte) (*Block, error) { block := &Block{ - blockID: blockID, - data: data, - protocolBlock: iotaBlock, + blockID: blockID, + data: data, + block: iotaBlock, } return block, nil } -func BlockFromBlock(protocolBlock *iotago.ProtocolBlock, opts ...serix.Option) (*Block, error) { - data, err := protocolBlock.API.Encode(protocolBlock, opts...) +func BlockFromBlock(block *iotago.Block, opts ...serix.Option) (*Block, error) { + data, err := block.API.Encode(block, opts...) if err != nil { return nil, err } - blockID, err := protocolBlock.ID() + blockID, err := block.ID() if err != nil { return nil, err } - return newBlock(blockID, protocolBlock, data) + return newBlock(blockID, block, data) } func BlockFromIDAndBytes(blockID iotago.BlockID, data []byte, api iotago.API, opts ...serix.Option) (*Block, error) { - protocolBlock := new(iotago.ProtocolBlock) - if _, err := api.Decode(data, protocolBlock, opts...); err != nil { + block := new(iotago.Block) + if _, err := api.Decode(data, block, opts...); err != nil { return nil, err } - return newBlock(blockID, protocolBlock, data) + return newBlock(blockID, block, data) } func BlockFromBytes(data []byte, apiProvider iotago.APIProvider) (*Block, error) { - iotaBlock, _, err := iotago.ProtocolBlockFromBytes(apiProvider)(data) + iotaBlock, _, err := iotago.BlockFromBytes(apiProvider)(data) if err != nil { return nil, err } @@ -85,8 +85,8 @@ func (blk *Block) Bytes() ([]byte, error) { return blk.data, nil } -func (blk *Block) ProtocolBlock() *iotago.ProtocolBlock { - return blk.protocolBlock +func (blk *Block) ProtocolBlock() *iotago.Block { + return blk.block } func (blk *Block) Payload() iotago.Payload { @@ -109,18 +109,18 @@ func (blk *Block) SignedTransaction() (tx *iotago.SignedTransaction, isTransacti return tx, isTransaction } -func (blk *Block) BasicBlock() (basicBlock *iotago.BasicBlock, isBasicBlock bool) { - basicBlock, isBasicBlock = blk.ProtocolBlock().Block.(*iotago.BasicBlock) +func (blk *Block) BasicBlock() (basicBlock *iotago.BasicBlockBody, isBasicBlock bool) { + basicBlock, isBasicBlock = blk.ProtocolBlock().Body.(*iotago.BasicBlockBody) return basicBlock, isBasicBlock } -func (blk *Block) ValidationBlock() (validationBlock *iotago.ValidationBlock, isValidationBlock bool) { - validationBlock, isValidationBlock = blk.ProtocolBlock().Block.(*iotago.ValidationBlock) +func (blk *Block) ValidationBlock() (validationBlock *iotago.ValidationBlockBody, isValidationBlock bool) { + validationBlock, isValidationBlock = blk.ProtocolBlock().Body.(*iotago.ValidationBlockBody) return validationBlock, isValidationBlock } func (blk *Block) String() string { - encode, err := blk.protocolBlock.API.JSONEncode(blk.ProtocolBlock()) + encode, err := blk.block.API.JSONEncode(blk.ProtocolBlock()) if err != nil { panic(err) } diff --git a/pkg/model/signaled_block.go b/pkg/model/signaled_block.go index e620b243d..c4bf457d4 100644 --- a/pkg/model/signaled_block.go +++ b/pkg/model/signaled_block.go @@ -15,10 +15,10 @@ type SignaledBlock struct { ProtocolParametersHash iotago.Identifier `serix:"3"` } -func NewSignaledBlock(blockID iotago.BlockID, block *iotago.ProtocolBlock, validationBlock *iotago.ValidationBlock) *SignaledBlock { +func NewSignaledBlock(blockID iotago.BlockID, block *iotago.Block, validationBlock *iotago.ValidationBlockBody) *SignaledBlock { return &SignaledBlock{ ID: blockID, - IssuingTime: block.IssuingTime, + IssuingTime: block.Header.IssuingTime, HighestSupportedVersion: validationBlock.HighestSupportedVersion, ProtocolParametersHash: validationBlock.ProtocolParametersHash, } diff --git a/pkg/network/protocols/core/protocol.go b/pkg/network/protocols/core/protocol.go index d67ab7b06..0ced4c663 100644 --- a/pkg/network/protocols/core/protocol.go +++ b/pkg/network/protocols/core/protocol.go @@ -76,7 +76,7 @@ func (p *Protocol) SendAttestations(cm *model.Commitment, attestations []*iotago encodedAttestations := marshalutil.New() encodedAttestations.WriteUint32(uint32(len(attestations))) for _, att := range attestations { - iotagoAPI := lo.PanicOnErr(p.apiProvider.APIForVersion(att.ProtocolVersion)) + iotagoAPI := lo.PanicOnErr(p.apiProvider.APIForVersion(att.Header.ProtocolVersion)) encodedAttestations.WriteBytes(lo.PanicOnErr(iotagoAPI.Encode(att))) } diff --git a/pkg/protocol/block_dispatcher.go b/pkg/protocol/block_dispatcher.go index 4737fe5da..15b2fcfa3 100644 --- a/pkg/protocol/block_dispatcher.go +++ b/pkg/protocol/block_dispatcher.go @@ -67,7 +67,7 @@ func NewBlockDispatcher(protocol *Protocol, opts ...options.Option[BlockDispatch // Dispatch dispatches the given block to the correct engine instance. func (b *BlockDispatcher) Dispatch(block *model.Block, src peer.ID) error { - slotCommitment := b.protocol.ChainManager.LoadCommitmentOrRequestMissing(block.ProtocolBlock().SlotCommitmentID) + slotCommitment := b.protocol.ChainManager.LoadCommitmentOrRequestMissing(block.ProtocolBlock().Header.SlotCommitmentID) if !slotCommitment.SolidEvent().WasTriggered() { if !b.unsolidCommitmentBlocks.Add(slotCommitment.ID(), types.NewTuple(block, src)) { return ierrors.Errorf("failed to add block %s to unsolid commitment buffer", block.ID()) @@ -353,7 +353,7 @@ func (b *BlockDispatcher) inSyncWindow(engine *engine.Engine, block *model.Block return true } - slotCommitmentID := block.ProtocolBlock().SlotCommitmentID + slotCommitmentID := block.ProtocolBlock().Header.SlotCommitmentID latestCommitmentSlot := engine.Storage.Settings().LatestCommitment().Slot() maxCommittableAge := engine.APIForSlot(slotCommitmentID.Slot()).ProtocolParameters().MaxCommittableAge() diff --git a/pkg/protocol/commitment_verifier.go b/pkg/protocol/commitment_verifier.go index 85e715d89..1315071e3 100644 --- a/pkg/protocol/commitment_verifier.go +++ b/pkg/protocol/commitment_verifier.go @@ -39,9 +39,9 @@ func (c *CommitmentVerifier) verifyCommitment(commitment *model.Commitment, atte iotago.AccountID.Bytes, iotago.AccountIDFromBytes, func(attestation *iotago.Attestation) ([]byte, error) { - apiForVersion, err := c.engine.APIForVersion(attestation.ProtocolVersion) + apiForVersion, err := c.engine.APIForVersion(attestation.Header.ProtocolVersion) if err != nil { - return nil, ierrors.Wrapf(err, "failed to get API for version %d", attestation.ProtocolVersion) + return nil, ierrors.Wrapf(err, "failed to get API for version %d", attestation.Header.ProtocolVersion) } return apiForVersion.Encode(attestation) @@ -64,8 +64,8 @@ func (c *CommitmentVerifier) verifyCommitment(commitment *model.Commitment, atte ) for _, att := range attestations { - if err := tree.Set(att.IssuerID, att); err != nil { - return nil, 0, ierrors.Wrapf(err, "failed to set attestation for issuerID %s", att.IssuerID) + if err := tree.Set(att.Header.IssuerID, att); err != nil { + return nil, 0, ierrors.Wrapf(err, "failed to set attestation for issuerID %s", att.Header.IssuerID) } } if !iotago.VerifyProof(merkleProof, tree.Root(), commitment.RootsID()) { @@ -119,11 +119,11 @@ func (c *CommitmentVerifier) verifyAttestations(attestations []*iotago.Attestati // 1. The attestation might be fake. // 2. The issuer might have added a new public key in the meantime, but we don't know about it yet // since we only have the ledger state at the forking point. - accountData, exists := c.validatorAccountsAtFork[att.IssuerID] + accountData, exists := c.validatorAccountsAtFork[att.Header.IssuerID] // We always need to have the accountData for a validator. if !exists { - return nil, 0, ierrors.Errorf("accountData for issuerID %s does not exist", att.IssuerID) + return nil, 0, ierrors.Errorf("accountData for issuerID %s does not exist", att.Header.IssuerID) } switch signature := att.Signature.(type) { @@ -147,8 +147,8 @@ func (c *CommitmentVerifier) verifyAttestations(attestations []*iotago.Attestati } // 3. A valid set of attestations can't contain multiple attestations from the same issuerID. - if visitedIdentities.Has(att.IssuerID) { - return nil, 0, ierrors.Errorf("issuerID %s contained in multiple attestations", att.IssuerID) + if visitedIdentities.Has(att.Header.IssuerID) { + return nil, 0, ierrors.Errorf("issuerID %s contained in multiple attestations", att.Header.IssuerID) } // TODO: this might differ if we have a Accounts with changing weights depending on the Slot/epoch @@ -162,11 +162,11 @@ func (c *CommitmentVerifier) verifyAttestations(attestations []*iotago.Attestati return nil, 0, ierrors.Errorf("committee for slot %d does not exist", attestationBlockID.Slot()) } - if _, seatExists := committee.GetSeat(att.IssuerID); seatExists { + if _, seatExists := committee.GetSeat(att.Header.IssuerID); seatExists { seatCount++ } - visitedIdentities.Add(att.IssuerID) + visitedIdentities.Add(att.Header.IssuerID) blockID, err := att.BlockID() if err != nil { diff --git a/pkg/protocol/engine/accounts/accountsledger/manager.go b/pkg/protocol/engine/accounts/accountsledger/manager.go index 53459cb0c..0d47ec95a 100644 --- a/pkg/protocol/engine/accounts/accountsledger/manager.go +++ b/pkg/protocol/engine/accounts/accountsledger/manager.go @@ -98,7 +98,7 @@ func (m *Manager) TrackBlock(block *blocks.Block) { if validationBlock, isValidationBlock := block.ValidationBlock(); isValidationBlock { newSignaledBlock := model.NewSignaledBlock(block.ID(), block.ProtocolBlock(), validationBlock) - m.latestSupportedVersionSignals.Get(block.ID().Slot(), true).Compute(block.ProtocolBlock().IssuerID, func(currentValue *model.SignaledBlock, exists bool) *model.SignaledBlock { + m.latestSupportedVersionSignals.Get(block.ID().Slot(), true).Compute(block.ProtocolBlock().Header.IssuerID, func(currentValue *model.SignaledBlock, exists bool) *model.SignaledBlock { if !exists { return newSignaledBlock } @@ -469,9 +469,9 @@ func (m *Manager) computeBlockBurnsForSlot(slot iotago.SlotIndex, rmc iotago.Man return nil, ierrors.Errorf("cannot apply the new diff, block %s not found in the block cache", blockID) } if _, isBasicBlock := block.BasicBlock(); isBasicBlock { - burns[block.ProtocolBlock().IssuerID] += iotago.Mana(block.WorkScore()) * rmc + burns[block.ProtocolBlock().Header.IssuerID] += iotago.Mana(block.WorkScore()) * rmc } else if _, isValidationBlock := block.ValidationBlock(); isValidationBlock { - validationBlockCount[block.ProtocolBlock().IssuerID]++ + validationBlockCount[block.ProtocolBlock().Header.IssuerID]++ } } validationBlocksPerSlot := int(apiForSlot.ProtocolParameters().ValidationBlocksPerSlot()) diff --git a/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go b/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go index b090c64c5..64d7f8152 100644 --- a/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go +++ b/pkg/protocol/engine/accounts/accountsledger/testsuite_test.go @@ -190,7 +190,7 @@ func (t *TestSuite) ApplySlotActions(slot iotago.SlotIndex, rmc iotago.Mana, act func (t *TestSuite) createBlockWithRMC(accountID iotago.AccountID, slot iotago.SlotIndex, rmc iotago.Mana) *blocks.Block { innerBlock := tpkg.RandBasicBlockWithIssuerAndRMC(tpkg.TestAPI, accountID, rmc) - innerBlock.IssuingTime = tpkg.TestAPI.TimeProvider().SlotStartTime(slot) + innerBlock.Header.IssuingTime = tpkg.TestAPI.TimeProvider().SlotStartTime(slot) modelBlock, err := model.BlockFromBlock(innerBlock) require.NoError(t.T, err) diff --git a/pkg/protocol/engine/attestation/slotattestation/manager.go b/pkg/protocol/engine/attestation/slotattestation/manager.go index 6b27b5b2d..437a00631 100644 --- a/pkg/protocol/engine/attestation/slotattestation/manager.go +++ b/pkg/protocol/engine/attestation/slotattestation/manager.go @@ -156,7 +156,7 @@ func (m *Manager) AddAttestationFromValidationBlock(block *blocks.Block) error { return ierrors.Errorf("committee for slot %d does not exist", block.ID().Slot()) } // Only track attestations of active committee members. - if _, exists := committee.GetSeat(block.ProtocolBlock().IssuerID); !exists { + if _, exists := committee.GetSeat(block.ProtocolBlock().Header.IssuerID); !exists { return nil } @@ -171,7 +171,7 @@ func (m *Manager) AddAttestationFromValidationBlock(block *blocks.Block) error { newAttestation := iotago.NewAttestation(m.apiProvider.APIForSlot(block.ID().Slot()), block.ProtocolBlock()) // We keep only the latest attestation for each committee member. - m.futureAttestations.Get(block.ID().Slot(), true).Compute(block.ProtocolBlock().IssuerID, func(currentValue *iotago.Attestation, exists bool) *iotago.Attestation { + m.futureAttestations.Get(block.ID().Slot(), true).Compute(block.ProtocolBlock().Header.IssuerID, func(currentValue *iotago.Attestation, exists bool) *iotago.Attestation { if !exists { return newAttestation } @@ -188,13 +188,13 @@ func (m *Manager) AddAttestationFromValidationBlock(block *blocks.Block) error { } func (m *Manager) applyToPendingAttestations(attestation *iotago.Attestation, cutoffSlot iotago.SlotIndex) { - if attestation.SlotCommitmentID.Slot() < cutoffSlot { + if attestation.Header.SlotCommitmentID.Slot() < cutoffSlot { return } updated := true - updatedAttestation := m.pendingAttestations.Get(cutoffSlot, true).Compute(attestation.IssuerID, func(currentValue *iotago.Attestation, exists bool) *iotago.Attestation { + updatedAttestation := m.pendingAttestations.Get(cutoffSlot, true).Compute(attestation.Header.IssuerID, func(currentValue *iotago.Attestation, exists bool) *iotago.Attestation { if !exists { return attestation } @@ -214,8 +214,8 @@ func (m *Manager) applyToPendingAttestations(attestation *iotago.Attestation, cu return } - for i := cutoffSlot; i <= updatedAttestation.SlotCommitmentID.Slot(); i++ { - m.pendingAttestations.Get(i, true).Set(attestation.IssuerID, updatedAttestation) + for i := cutoffSlot; i <= updatedAttestation.Header.SlotCommitmentID.Slot(); i++ { + m.pendingAttestations.Get(i, true).Set(attestation.Header.IssuerID, updatedAttestation) } } @@ -267,9 +267,9 @@ func (m *Manager) Commit(slot iotago.SlotIndex) (newCW uint64, attestationsRoot for _, a := range attestations { // TODO: which weight are we using here? The current one? Or the one of the slot of the attestation/commitmentID? - if _, exists := committee.GetSeat(a.IssuerID); exists { - if err := tree.Set(a.IssuerID, a); err != nil { - return 0, iotago.Identifier{}, ierrors.Wrapf(err, "failed to set attestation %s in tree", a.IssuerID) + if _, exists := committee.GetSeat(a.Header.IssuerID); exists { + if err := tree.Set(a.Header.IssuerID, a); err != nil { + return 0, iotago.Identifier{}, ierrors.Wrapf(err, "failed to set attestation %s in tree", a.Header.IssuerID) } m.lastCumulativeWeight++ diff --git a/pkg/protocol/engine/attestation/slotattestation/snapshot.go b/pkg/protocol/engine/attestation/slotattestation/snapshot.go index 12f70bd4a..ec2ae69fd 100644 --- a/pkg/protocol/engine/attestation/slotattestation/snapshot.go +++ b/pkg/protocol/engine/attestation/slotattestation/snapshot.go @@ -90,9 +90,9 @@ func (m *Manager) Export(writer io.WriteSeeker, targetSlot iotago.SlotIndex) err if err = stream.WriteCollection(writer, func() (uint64, error) { for _, a := range attestations { - apiForVersion, err := m.apiProvider.APIForVersion(a.ProtocolVersion) + apiForVersion, err := m.apiProvider.APIForVersion(a.Header.ProtocolVersion) if err != nil { - return 0, ierrors.Wrapf(err, "failed to get API for version %d", a.ProtocolVersion) + return 0, ierrors.Wrapf(err, "failed to get API for version %d", a.Header.ProtocolVersion) } bytes, err := apiForVersion.Encode(a) if err != nil { diff --git a/pkg/protocol/engine/attestation/slotattestation/storage.go b/pkg/protocol/engine/attestation/slotattestation/storage.go index b5c198e30..6f74e60c0 100644 --- a/pkg/protocol/engine/attestation/slotattestation/storage.go +++ b/pkg/protocol/engine/attestation/slotattestation/storage.go @@ -53,7 +53,7 @@ func (m *Manager) writeToDisk() error { attestations := m.determineAttestationsFromWindow(i) for _, a := range attestations { - if err := storage.Set(a.IssuerID, a); err != nil { + if err := storage.Set(a.Header.IssuerID, a); err != nil { return ierrors.Wrapf(err, "failed to set attestation %v", a) } } diff --git a/pkg/protocol/engine/blockdag/inmemoryblockdag/blockdag.go b/pkg/protocol/engine/blockdag/inmemoryblockdag/blockdag.go index b368f1278..6fe5944b0 100644 --- a/pkg/protocol/engine/blockdag/inmemoryblockdag/blockdag.go +++ b/pkg/protocol/engine/blockdag/inmemoryblockdag/blockdag.go @@ -48,7 +48,7 @@ func NewProvider(opts ...options.Option[BlockDAG]) module.Provider[*engine.Engin e.Events.Filter.BlockPreAllowed.Hook(func(block *model.Block) { if _, _, err := b.Attach(block); err != nil { - b.errorHandler(ierrors.Wrapf(err, "failed to attach block with %s (issuerID: %s)", block.ID(), block.ProtocolBlock().IssuerID)) + b.errorHandler(ierrors.Wrapf(err, "failed to attach block with %s (issuerID: %s)", block.ID(), block.ProtocolBlock().Header.IssuerID)) } }, event.WithWorkerPool(wp)) @@ -188,7 +188,7 @@ func (b *BlockDAG) attach(data *model.Block) (block *blocks.Block, wasAttached b func (b *BlockDAG) shouldAttach(data *model.Block) (shouldAttach bool, err error) { if b.evictionState.InRootBlockSlot(data.ID()) && !b.evictionState.IsRootBlock(data.ID()) { b.retainBlockFailure(data.ID(), apimodels.BlockFailureIsTooOld) - return false, ierrors.Errorf("block data with %s is too old (issued at: %s)", data.ID(), data.ProtocolBlock().IssuingTime) + return false, ierrors.Errorf("block data with %s is too old (issued at: %s)", data.ID(), data.ProtocolBlock().Header.IssuingTime) } storedBlock, storedBlockExists := b.blockCache.Block(data.ID()) diff --git a/pkg/protocol/engine/blocks/block.go b/pkg/protocol/engine/blocks/block.go index 33de43b2e..10df6cbb5 100644 --- a/pkg/protocol/engine/blocks/block.go +++ b/pkg/protocol/engine/blocks/block.go @@ -139,7 +139,7 @@ func NewMissingBlock(blockID iotago.BlockID) *Block { } } -func (b *Block) ProtocolBlock() *iotago.ProtocolBlock { +func (b *Block) ProtocolBlock() *iotago.Block { if b.modelBlock == nil { return nil } @@ -152,7 +152,7 @@ func (b *Block) Parents() (parents []iotago.BlockID) { } func (b *Block) StrongParents() (parents []iotago.BlockID) { - return b.modelBlock.ProtocolBlock().Block.StrongParentIDs() + return b.modelBlock.ProtocolBlock().Body.StrongParentIDs() } // ParentsWithType returns the parents of the block with their type. @@ -185,7 +185,7 @@ func (b *Block) SignedTransaction() (tx *iotago.SignedTransaction, hasTransactio return b.modelBlock.SignedTransaction() } -func (b *Block) BasicBlock() (basicBlock *iotago.BasicBlock, isBasicBlock bool) { +func (b *Block) BasicBlock() (basicBlock *iotago.BasicBlockBody, isBasicBlock bool) { if b.modelBlock == nil { return nil, false } @@ -193,7 +193,7 @@ func (b *Block) BasicBlock() (basicBlock *iotago.BasicBlock, isBasicBlock bool) return b.modelBlock.BasicBlock() } -func (b *Block) ValidationBlock() (validationBlock *iotago.ValidationBlock, isValidationBlock bool) { +func (b *Block) ValidationBlock() (validationBlock *iotago.ValidationBlockBody, isValidationBlock bool) { if b.modelBlock == nil { return nil, false } @@ -232,7 +232,7 @@ func (b *Block) IssuingTime() time.Time { return b.rootBlock.issuingTime } - return b.modelBlock.ProtocolBlock().IssuingTime + return b.modelBlock.ProtocolBlock().Header.IssuingTime } func (b *Block) SlotCommitmentID() iotago.CommitmentID { @@ -247,7 +247,7 @@ func (b *Block) SlotCommitmentID() iotago.CommitmentID { return b.rootBlock.commitmentID } - return b.modelBlock.ProtocolBlock().SlotCommitmentID + return b.modelBlock.ProtocolBlock().Header.SlotCommitmentID } // IsMissing returns a flag that indicates if the underlying Block data hasn't been stored, yet. diff --git a/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter.go b/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter.go index 2b0f878c9..a088c3d88 100644 --- a/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter.go +++ b/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter.go @@ -65,11 +65,11 @@ func (c *CommitmentFilter) ProcessPreFilteredBlock(block *blocks.Block) { func (c *CommitmentFilter) evaluateBlock(block *blocks.Block) { // check if the account exists in the specified slot. - accountData, exists, err := c.accountRetrieveFunc(block.ProtocolBlock().IssuerID, block.SlotCommitmentID().Slot()) + accountData, exists, err := c.accountRetrieveFunc(block.ProtocolBlock().Header.IssuerID, block.SlotCommitmentID().Slot()) if err != nil { c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{ Block: block, - Reason: ierrors.Join(iotago.ErrIssuerAccountNotFound, ierrors.Wrapf(err, "could not retrieve account information for block issuer %s", block.ProtocolBlock().IssuerID)), + Reason: ierrors.Join(iotago.ErrIssuerAccountNotFound, ierrors.Wrapf(err, "could not retrieve account information for block issuer %s", block.ProtocolBlock().Header.IssuerID)), }) return @@ -77,22 +77,22 @@ func (c *CommitmentFilter) evaluateBlock(block *blocks.Block) { if !exists { c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{ Block: block, - Reason: ierrors.Join(iotago.ErrIssuerAccountNotFound, ierrors.Errorf("block issuer account %s does not exist in slot commitment %s", block.ProtocolBlock().IssuerID, block.ProtocolBlock().SlotCommitmentID.Slot())), + Reason: ierrors.Join(iotago.ErrIssuerAccountNotFound, ierrors.Errorf("block issuer account %s does not exist in slot commitment %s", block.ProtocolBlock().Header.IssuerID, block.ProtocolBlock().Header.SlotCommitmentID.Slot())), }) return } // get the api for the block - blockAPI, err := c.apiProvider.APIForVersion(block.ProtocolBlock().BlockHeader.ProtocolVersion) + blockAPI, err := c.apiProvider.APIForVersion(block.ProtocolBlock().Header.ProtocolVersion) if err != nil { c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{ Block: block, - Reason: ierrors.Join(iotago.ErrBlockVersionInvalid, ierrors.Wrapf(err, "could not retrieve API for block version %d", block.ProtocolBlock().BlockHeader.ProtocolVersion)), + Reason: ierrors.Join(iotago.ErrBlockVersionInvalid, ierrors.Wrapf(err, "could not retrieve API for block version %d", block.ProtocolBlock().Header.ProtocolVersion)), }) } // check that the block burns sufficient Mana, use slot index of the commitment - rmcSlot := block.ProtocolBlock().SlotCommitmentID.Slot() + rmcSlot := block.ProtocolBlock().Header.SlotCommitmentID.Slot() rmc, err := c.rmcRetrieveFunc(rmcSlot) if err != nil { @@ -114,7 +114,7 @@ func (c *CommitmentFilter) evaluateBlock(block *blocks.Block) { if basicBlock.MaxBurnedMana < manaCost { c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{ Block: block, - Reason: ierrors.Join(iotago.ErrBurnedInsufficientMana, ierrors.Errorf("block issuer account %s burned insufficient Mana, required %d, burned %d", block.ProtocolBlock().IssuerID, manaCost, basicBlock.MaxBurnedMana)), + Reason: ierrors.Join(iotago.ErrBurnedInsufficientMana, ierrors.Errorf("block issuer account %s burned insufficient Mana, required %d, burned %d", block.ProtocolBlock().Header.IssuerID, manaCost, basicBlock.MaxBurnedMana)), }) return @@ -125,17 +125,17 @@ func (c *CommitmentFilter) evaluateBlock(block *blocks.Block) { if accountData.Credits.Value < 0 { c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{ Block: block, - Reason: ierrors.Wrapf(iotago.ErrNegativeBIC, "block issuer account %s is locked due to negative BIC", block.ProtocolBlock().IssuerID), + Reason: ierrors.Wrapf(iotago.ErrNegativeBIC, "block issuer account %s is locked due to negative BIC", block.ProtocolBlock().Header.IssuerID), }) return } // Check that the account is not expired - if accountData.ExpirySlot < block.ProtocolBlock().SlotCommitmentID.Slot() { + if accountData.ExpirySlot < block.ProtocolBlock().Header.SlotCommitmentID.Slot() { c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{ Block: block, - Reason: ierrors.Wrapf(iotago.ErrAccountExpired, "block issuer account %s is expired, expiry slot %d in commitment %d", block.ProtocolBlock().IssuerID, accountData.ExpirySlot, block.ProtocolBlock().SlotCommitmentID.Slot()), + Reason: ierrors.Wrapf(iotago.ErrAccountExpired, "block issuer account %s is expired, expiry slot %d in commitment %d", block.ProtocolBlock().Header.IssuerID, accountData.ExpirySlot, block.ProtocolBlock().Header.SlotCommitmentID.Slot()), }) return @@ -155,7 +155,7 @@ func (c *CommitmentFilter) evaluateBlock(block *blocks.Block) { if !isBikPubKeyHash || bikPubKeyHash.PublicKeyHash != iotago.Ed25519PublicKeyHashBlockIssuerKeyFromPublicKey(signature.PublicKey[:]).PublicKeyHash { c.events.BlockFiltered.Trigger(&commitmentfilter.BlockFilteredEvent{ Block: block, - Reason: ierrors.Wrapf(iotago.ErrInvalidSignature, "block issuer account %s does not have block issuer key corresponding to public key %s in slot %d", block.ProtocolBlock().IssuerID, signature.PublicKey, block.ProtocolBlock().SlotCommitmentID.Index()), + Reason: ierrors.Wrapf(iotago.ErrInvalidSignature, "block issuer account %s does not have block issuer key corresponding to public key %s in slot %d", block.ProtocolBlock().Header.IssuerID, signature.PublicKey, block.ProtocolBlock().Header.SlotCommitmentID.Index()), }) return diff --git a/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter_test.go b/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter_test.go index dfb7c02a6..127c5fb1c 100644 --- a/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter_test.go +++ b/pkg/protocol/engine/commitmentfilter/accountsfilter/commitmentfilter_test.go @@ -85,7 +85,7 @@ func (t *TestFramework) AddRMCData(slot iotago.SlotIndex, rmcData iotago.Mana) { // q: how to get an engine block.Block from protocol block -func (t *TestFramework) processBlock(alias string, block *iotago.ProtocolBlock) { +func (t *TestFramework) processBlock(alias string, block *iotago.Block) { modelBlock, err := model.BlockFromBlock(block) require.NoError(t.Test, err) diff --git a/pkg/protocol/engine/congestioncontrol/scheduler/drr/drrbuffer.go b/pkg/protocol/engine/congestioncontrol/scheduler/drr/drrbuffer.go index 3ae38379a..86dc0dac6 100644 --- a/pkg/protocol/engine/congestioncontrol/scheduler/drr/drrbuffer.go +++ b/pkg/protocol/engine/congestioncontrol/scheduler/drr/drrbuffer.go @@ -156,7 +156,7 @@ func (b *BufferQueue) Submit(blk *blocks.Block, issuerQueue *IssuerQueue, quantu // Unsubmit removes a block from the submitted blocks. // If that block is already marked as ready, Unsubmit has no effect. func (b *BufferQueue) Unsubmit(block *blocks.Block) bool { - issuerID := block.ProtocolBlock().IssuerID + issuerID := block.ProtocolBlock().Header.IssuerID issuerQueue := b.IssuerQueue(issuerID) if issuerQueue == nil { @@ -174,7 +174,7 @@ func (b *BufferQueue) Unsubmit(block *blocks.Block) bool { // Ready marks a previously submitted block as ready to be scheduled. func (b *BufferQueue) Ready(block *blocks.Block) bool { - issuerQueue := b.IssuerQueue(block.ProtocolBlock().IssuerID) + issuerQueue := b.IssuerQueue(block.ProtocolBlock().Header.IssuerID) if issuerQueue == nil { return false } diff --git a/pkg/protocol/engine/congestioncontrol/scheduler/drr/issuerqueue.go b/pkg/protocol/engine/congestioncontrol/scheduler/drr/issuerqueue.go index 6b26acbc5..80fc750b9 100644 --- a/pkg/protocol/engine/congestioncontrol/scheduler/drr/issuerqueue.go +++ b/pkg/protocol/engine/congestioncontrol/scheduler/drr/issuerqueue.go @@ -61,7 +61,7 @@ func (q *IssuerQueue) IssuerID() iotago.AccountID { // Submit submits a block for the queue. func (q *IssuerQueue) Submit(element *blocks.Block) bool { // this is just a debugging check, it will never happen in practice - if blkIssuerID := element.ProtocolBlock().IssuerID; q.issuerID != blkIssuerID { + if blkIssuerID := element.ProtocolBlock().Header.IssuerID; q.issuerID != blkIssuerID { panic(fmt.Sprintf("issuerqueue: queue issuer ID(%x) and issuer ID(%x) does not match.", q.issuerID, blkIssuerID)) } diff --git a/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go b/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go index 37ba9de2a..917787009 100644 --- a/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go +++ b/pkg/protocol/engine/congestioncontrol/scheduler/drr/scheduler.go @@ -250,7 +250,7 @@ func (s *Scheduler) enqueueBasicBlock(block *blocks.Block) { slot := s.latestCommittedSlot() - issuerID := block.ProtocolBlock().IssuerID + issuerID := block.ProtocolBlock().Header.IssuerID issuerQueue := s.getOrCreateIssuer(issuerID) droppedBlocks, submitted := s.basicBuffer.Submit( @@ -286,9 +286,9 @@ func (s *Scheduler) enqueueValidationBlock(block *blocks.Block) { s.bufferMutex.Lock() defer s.bufferMutex.Unlock() - _, exists := s.validatorBuffer.Get(block.ProtocolBlock().IssuerID) + _, exists := s.validatorBuffer.Get(block.ProtocolBlock().Header.IssuerID) if !exists { - s.addValidator(block.ProtocolBlock().IssuerID) + s.addValidator(block.ProtocolBlock().Header.IssuerID) } droppedBlock, submitted := s.validatorBuffer.Submit(block, int(s.apiProvider.CommittedAPI().ProtocolParameters().CongestionControlParameters().MaxValidationBufferSize)) if !submitted { @@ -468,7 +468,7 @@ func (s *Scheduler) selectBasicBlockWithoutLocking() { // remove the block from the buffer and adjust issuer's deficit block := s.basicBuffer.PopFront() - issuerID := block.ProtocolBlock().IssuerID + issuerID := block.ProtocolBlock().Header.IssuerID if _, err := s.updateDeficit(issuerID, -s.deficitFromWork(block.WorkScore())); err != nil { // if something goes wrong with deficit update, drop the block instead of scheduling it. block.SetDropped() @@ -502,7 +502,7 @@ func (s *Scheduler) selectIssuer(start *IssuerQueue, slot iotago.SlotIndex) (Def continue } - issuerID := block.ProtocolBlock().IssuerID + issuerID := block.ProtocolBlock().Header.IssuerID // compute how often the deficit needs to be incremented until the block can be scheduled deficit, exists := s.deficits.Get(issuerID) @@ -672,7 +672,7 @@ func (s *Scheduler) ready(block *blocks.Block) { } func (s *Scheduler) readyValidationBlock(block *blocks.Block) { - if validatorQueue, exists := s.validatorBuffer.Get(block.ProtocolBlock().IssuerID); exists { + if validatorQueue, exists := s.validatorBuffer.Get(block.ProtocolBlock().Header.IssuerID); exists { validatorQueue.Ready(block) } } diff --git a/pkg/protocol/engine/congestioncontrol/scheduler/drr/validatorqueue.go b/pkg/protocol/engine/congestioncontrol/scheduler/drr/validatorqueue.go index 8d2fd0aaf..900262b82 100644 --- a/pkg/protocol/engine/congestioncontrol/scheduler/drr/validatorqueue.go +++ b/pkg/protocol/engine/congestioncontrol/scheduler/drr/validatorqueue.go @@ -53,7 +53,7 @@ func (q *ValidatorQueue) AccountID() iotago.AccountID { } func (q *ValidatorQueue) Submit(block *blocks.Block, maxBuffer int) (*blocks.Block, bool) { - if blkAccountID := block.ProtocolBlock().IssuerID; q.accountID != blkAccountID { + if blkAccountID := block.ProtocolBlock().Header.IssuerID; q.accountID != blkAccountID { panic(fmt.Sprintf("issuerqueue: queue issuer ID(%x) and issuer ID(%x) does not match.", q.accountID, blkAccountID)) } @@ -202,7 +202,7 @@ func (b *ValidatorBuffer) Set(accountID iotago.AccountID, validatorQueue *Valida } func (b *ValidatorBuffer) Submit(block *blocks.Block, maxBuffer int) (*blocks.Block, bool) { - validatorQueue, exists := b.buffer.Get(block.ProtocolBlock().IssuerID) + validatorQueue, exists := b.buffer.Get(block.ProtocolBlock().Header.IssuerID) if !exists { return nil, false } diff --git a/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go b/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go index 9ee2becde..3e973f7c6 100644 --- a/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go +++ b/pkg/protocol/engine/consensus/blockgadget/thresholdblockgadget/gadget.go @@ -109,7 +109,7 @@ func (g *Gadget) isCommitteeValidationBlock(block *blocks.Block) (seat account.S } // Only accept blocks for issuers that are part of the committee. - return committee.GetSeat(block.ProtocolBlock().IssuerID) + return committee.GetSeat(block.ProtocolBlock().Header.IssuerID) } func anyChildInSet(block *blocks.Block, set ds.Set[iotago.BlockID]) bool { diff --git a/pkg/protocol/engine/consensus/slotgadget/totalweightslotgadget/gadget.go b/pkg/protocol/engine/consensus/slotgadget/totalweightslotgadget/gadget.go index ed1e4fae8..9dd33e104 100644 --- a/pkg/protocol/engine/consensus/slotgadget/totalweightslotgadget/gadget.go +++ b/pkg/protocol/engine/consensus/slotgadget/totalweightslotgadget/gadget.go @@ -99,7 +99,7 @@ func (g *Gadget) trackVotes(block *blocks.Block) { return slottracker.NewSlotTracker() }) - prevLatestSlot, latestSlot, updated := tracker.TrackVotes(block.SlotCommitmentID().Slot(), block.ProtocolBlock().IssuerID, g.lastFinalizedSlot) + prevLatestSlot, latestSlot, updated := tracker.TrackVotes(block.SlotCommitmentID().Slot(), block.ProtocolBlock().Header.IssuerID, g.lastFinalizedSlot) if !updated { return nil } diff --git a/pkg/protocol/engine/engine.go b/pkg/protocol/engine/engine.go index 1bb299aa8..1cee3527b 100644 --- a/pkg/protocol/engine/engine.go +++ b/pkg/protocol/engine/engine.go @@ -443,7 +443,7 @@ func (e *Engine) setupEvictionState() { e.errorHandler(ierrors.Errorf("cannot store root block (%s) because it is missing", parent.ID)) return } - e.EvictionState.AddRootBlock(parentBlock.ID(), parentBlock.ProtocolBlock().SlotCommitmentID) + e.EvictionState.AddRootBlock(parentBlock.ID(), parentBlock.ProtocolBlock().Header.SlotCommitmentID) } }) }, event.WithWorkerPool(wp)) diff --git a/pkg/protocol/engine/filter/blockfilter/filter.go b/pkg/protocol/engine/filter/blockfilter/filter.go index 0ed6900ec..77950c5c3 100644 --- a/pkg/protocol/engine/filter/blockfilter/filter.go +++ b/pkg/protocol/engine/filter/blockfilter/filter.go @@ -68,10 +68,10 @@ func New(apiProvider iotago.APIProvider, opts ...options.Option[Filter]) *Filter func (f *Filter) ProcessReceivedBlock(block *model.Block, source peer.ID) { // Verify the block's version corresponds to the protocol version for the slot. apiForSlot := f.apiProvider.APIForSlot(block.ID().Slot()) - if apiForSlot.Version() != block.ProtocolBlock().ProtocolVersion { + if apiForSlot.Version() != block.ProtocolBlock().Header.ProtocolVersion { f.events.BlockPreFiltered.Trigger(&filter.BlockPreFilteredEvent{ Block: block, - Reason: ierrors.Wrapf(ErrInvalidBlockVersion, "invalid protocol version %d (expected %d) for epoch %d", block.ProtocolBlock().ProtocolVersion, apiForSlot.Version(), apiForSlot.TimeProvider().EpochFromSlot(block.ID().Slot())), + Reason: ierrors.Wrapf(ErrInvalidBlockVersion, "invalid protocol version %d (expected %d) for epoch %d", block.ProtocolBlock().Header.ProtocolVersion, apiForSlot.Version(), apiForSlot.TimeProvider().EpochFromSlot(block.ID().Slot())), Source: source, }) @@ -79,7 +79,7 @@ func (f *Filter) ProcessReceivedBlock(block *model.Block, source peer.ID) { } // Verify the timestamp is not too far in the future. - timeDelta := time.Since(block.ProtocolBlock().IssuingTime) + timeDelta := time.Since(block.ProtocolBlock().Header.IssuingTime) if timeDelta < -f.optsMaxAllowedWallClockDrift { f.events.BlockPreFiltered.Trigger(&filter.BlockPreFilteredEvent{ Block: block, @@ -91,7 +91,7 @@ func (f *Filter) ProcessReceivedBlock(block *model.Block, source peer.ID) { } if _, isValidation := block.ValidationBlock(); isValidation { - blockSlot := block.ProtocolBlock().API.TimeProvider().SlotFromTime(block.ProtocolBlock().IssuingTime) + blockSlot := block.ProtocolBlock().API.TimeProvider().SlotFromTime(block.ProtocolBlock().Header.IssuingTime) committee, exists := f.committeeFunc(blockSlot) if !exists { f.events.BlockPreFiltered.Trigger(&filter.BlockPreFilteredEvent{ @@ -103,10 +103,10 @@ func (f *Filter) ProcessReceivedBlock(block *model.Block, source peer.ID) { return } - if !committee.HasAccount(block.ProtocolBlock().IssuerID) { + if !committee.HasAccount(block.ProtocolBlock().Header.IssuerID) { f.events.BlockPreFiltered.Trigger(&filter.BlockPreFilteredEvent{ Block: block, - Reason: ierrors.Wrapf(ErrValidatorNotInCommittee, "validation block issuer %s is not part of the committee for slot %d", block.ProtocolBlock().IssuerID, blockSlot), + Reason: ierrors.Wrapf(ErrValidatorNotInCommittee, "validation block issuer %s is not part of the committee for slot %d", block.ProtocolBlock().Header.IssuerID, blockSlot), Source: source, }) diff --git a/pkg/protocol/engine/filter/blockfilter/filter_test.go b/pkg/protocol/engine/filter/blockfilter/filter_test.go index 02646bb56..6f1b4bdc4 100644 --- a/pkg/protocol/engine/filter/blockfilter/filter_test.go +++ b/pkg/protocol/engine/filter/blockfilter/filter_test.go @@ -44,7 +44,7 @@ func NewTestFramework(t *testing.T, apiProvider iotago.APIProvider, optsFilter . return tf } -func (t *TestFramework) processBlock(alias string, block *iotago.ProtocolBlock) error { +func (t *TestFramework) processBlock(alias string, block *iotago.Block) error { modelBlock, err := model.BlockFromBlock(block, serix.WithValidation()) if err != nil { return err diff --git a/pkg/protocol/engine/ledger/ledger/ledger.go b/pkg/protocol/engine/ledger/ledger/ledger.go index a6c177204..31632f082 100644 --- a/pkg/protocol/engine/ledger/ledger/ledger.go +++ b/pkg/protocol/engine/ledger/ledger/ledger.go @@ -746,14 +746,14 @@ func (l *Ledger) resolveState(stateRef mempool.StateReference) *promise.Promise[ } func (l *Ledger) blockPreAccepted(block *blocks.Block) { - voteRank := ledger.NewBlockVoteRank(block.ID(), block.ProtocolBlock().IssuingTime) + voteRank := ledger.NewBlockVoteRank(block.ID(), block.ProtocolBlock().Header.IssuingTime) committee, exists := l.sybilProtection.SeatManager().CommitteeInSlot(block.ID().Slot()) if !exists { panic("committee should exist because we pre-accepted the block") } - seat, exists := committee.GetSeat(block.ProtocolBlock().IssuerID) + seat, exists := committee.GetSeat(block.ProtocolBlock().Header.IssuerID) if !exists { return } diff --git a/pkg/protocol/engine/upgrade/signalingupgradeorchestrator/orchestrator.go b/pkg/protocol/engine/upgrade/signalingupgradeorchestrator/orchestrator.go index 4e5ee6026..bca67f268 100644 --- a/pkg/protocol/engine/upgrade/signalingupgradeorchestrator/orchestrator.go +++ b/pkg/protocol/engine/upgrade/signalingupgradeorchestrator/orchestrator.go @@ -151,7 +151,7 @@ func (o *Orchestrator) TrackValidationBlock(block *blocks.Block) { return } - seat, exists := committee.GetSeat(block.ProtocolBlock().IssuerID) + seat, exists := committee.GetSeat(block.ProtocolBlock().Header.IssuerID) if !exists { return } diff --git a/pkg/protocol/sybilprotection/seatmanager/poa/poa.go b/pkg/protocol/sybilprotection/seatmanager/poa/poa.go index 8a0256e61..d73ce7191 100644 --- a/pkg/protocol/sybilprotection/seatmanager/poa/poa.go +++ b/pkg/protocol/sybilprotection/seatmanager/poa/poa.go @@ -66,9 +66,9 @@ func NewProvider(opts ...options.Option[SeatManager]) module.Provider[*engine.En panic(ierrors.Errorf("committee not selected for slot %d, but received block in that slot", block.ID().Slot())) } - seat, exists := committee.GetSeat(block.ProtocolBlock().IssuerID) + seat, exists := committee.GetSeat(block.ProtocolBlock().Header.IssuerID) if exists { - s.activityTracker.MarkSeatActive(seat, block.ProtocolBlock().IssuerID, block.IssuingTime()) + s.activityTracker.MarkSeatActive(seat, block.ProtocolBlock().Header.IssuerID, block.IssuingTime()) } s.events.BlockProcessed.Trigger(block) diff --git a/pkg/protocol/sybilprotection/seatmanager/topstakers/topstakers.go b/pkg/protocol/sybilprotection/seatmanager/topstakers/topstakers.go index 5d85f85bf..4d572c888 100644 --- a/pkg/protocol/sybilprotection/seatmanager/topstakers/topstakers.go +++ b/pkg/protocol/sybilprotection/seatmanager/topstakers/topstakers.go @@ -67,9 +67,9 @@ func NewProvider(opts ...options.Option[SeatManager]) module.Provider[*engine.En panic(ierrors.Errorf("committee not selected for slot %d, but received block in that slot", block.ID().Slot())) } - seat, exists := committee.GetSeat(block.ProtocolBlock().IssuerID) + seat, exists := committee.GetSeat(block.ProtocolBlock().Header.IssuerID) if exists { - s.activityTracker.MarkSeatActive(seat, block.ProtocolBlock().IssuerID, block.IssuingTime()) + s.activityTracker.MarkSeatActive(seat, block.ProtocolBlock().Header.IssuerID, block.IssuingTime()) } s.events.BlockProcessed.Trigger(block) diff --git a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/performance.go b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/performance.go index 37f061d5d..a798ff647 100644 --- a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/performance.go +++ b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/performance.go @@ -64,9 +64,9 @@ func (t *Tracker) TrackValidationBlock(block *blocks.Block) { t.performanceFactorsMutex.Lock() defer t.performanceFactorsMutex.Unlock() - isCommitteeMember, err := t.isCommitteeMember(block.ID().Slot(), block.ProtocolBlock().IssuerID) + isCommitteeMember, err := t.isCommitteeMember(block.ID().Slot(), block.ProtocolBlock().Header.IssuerID) if err != nil { - t.errHandler(ierrors.Wrapf(err, "error while checking if account %s is a committee member in slot %d", block.ProtocolBlock().IssuerID, block.ID().Slot())) + t.errHandler(ierrors.Wrapf(err, "error while checking if account %s is a committee member in slot %d", block.ProtocolBlock().Header.IssuerID, block.ID().Slot())) return } @@ -87,7 +87,7 @@ func (t *Tracker) TrackCandidateBlock(block *blocks.Block) { } var rollback bool - t.nextEpochCommitteeCandidates.Compute(block.ProtocolBlock().IssuerID, func(currentValue iotago.SlotIndex, exists bool) iotago.SlotIndex { + t.nextEpochCommitteeCandidates.Compute(block.ProtocolBlock().Header.IssuerID, func(currentValue iotago.SlotIndex, exists bool) iotago.SlotIndex { if !exists || currentValue > block.ID().Slot() { committeeCandidatesStore, err := t.committeeCandidatesInEpochFunc(blockEpoch) if err != nil { @@ -100,7 +100,7 @@ func (t *Tracker) TrackCandidateBlock(block *blocks.Block) { return currentValue } - err = committeeCandidatesStore.Set(block.ProtocolBlock().IssuerID[:], block.ID().Slot().MustBytes()) + err = committeeCandidatesStore.Set(block.ProtocolBlock().Header.IssuerID[:], block.ID().Slot().MustBytes()) if err != nil { // if there is an error, and we don't register a candidate, then we might eventually create a different commitment t.errHandler(ierrors.Wrapf(err, "error while updating candidate activity for epoch %d", blockEpoch)) @@ -120,7 +120,7 @@ func (t *Tracker) TrackCandidateBlock(block *blocks.Block) { // if there was an error when computing the value, // and it was the first entry for the given issuer, then remove the entry if rollback { - t.nextEpochCommitteeCandidates.Delete(block.ProtocolBlock().IssuerID) + t.nextEpochCommitteeCandidates.Delete(block.ProtocolBlock().Header.IssuerID) } } @@ -313,7 +313,7 @@ func (t *Tracker) isCommitteeMember(slot iotago.SlotIndex, accountID iotago.Acco return committee.Has(accountID), nil } -func (t *Tracker) trackCommitteeMemberPerformance(validationBlock *iotago.ValidationBlock, block *blocks.Block) { +func (t *Tracker) trackCommitteeMemberPerformance(validationBlock *iotago.ValidationBlockBody, block *blocks.Block) { validatorPerformances, err := t.validatorPerformancesFunc(block.ID().Slot()) if err != nil { t.errHandler(ierrors.Errorf("failed to load performance factor for slot %s", block.ID().Slot())) @@ -321,9 +321,9 @@ func (t *Tracker) trackCommitteeMemberPerformance(validationBlock *iotago.Valida return } - validatorPerformance, err := validatorPerformances.Load(block.ProtocolBlock().IssuerID) + validatorPerformance, err := validatorPerformances.Load(block.ProtocolBlock().Header.IssuerID) if err != nil { - t.errHandler(ierrors.Errorf("failed to load performance factor for account %s", block.ProtocolBlock().IssuerID)) + t.errHandler(ierrors.Errorf("failed to load performance factor for account %s", block.ProtocolBlock().Header.IssuerID)) return } @@ -334,7 +334,7 @@ func (t *Tracker) trackCommitteeMemberPerformance(validationBlock *iotago.Valida } // set a bit at subslotIndex to 1 to indicate activity in that subslot - validatorPerformance.SlotActivityVector = validatorPerformance.SlotActivityVector | (1 << t.subslotIndex(block.ID().Slot(), block.ProtocolBlock().IssuingTime)) + validatorPerformance.SlotActivityVector = validatorPerformance.SlotActivityVector | (1 << t.subslotIndex(block.ID().Slot(), block.ProtocolBlock().Header.IssuingTime)) apiForSlot := t.apiProvider.APIForSlot(block.ID().Slot()) @@ -349,8 +349,8 @@ func (t *Tracker) trackCommitteeMemberPerformance(validationBlock *iotago.Valida Hash: validationBlock.ProtocolParametersHash, } - if err = validatorPerformances.Store(block.ProtocolBlock().IssuerID, validatorPerformance); err != nil { - t.errHandler(ierrors.Errorf("failed to store performance factor for account %s", block.ProtocolBlock().IssuerID)) + if err = validatorPerformances.Store(block.ProtocolBlock().Header.IssuerID, validatorPerformance); err != nil { + t.errHandler(ierrors.Errorf("failed to store performance factor for account %s", block.ProtocolBlock().Header.IssuerID)) } } diff --git a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/testsuite_test.go b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/testsuite_test.go index 6615023d4..684e21916 100644 --- a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/testsuite_test.go +++ b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/testsuite_test.go @@ -289,14 +289,14 @@ func (t *TestSuite) applyPerformanceFactor(accountID iotago.AccountID, epoch iot for i := uint64(0); i < validationBlocksSentPerSlot; i++ { valBlock := tpkg.RandValidationBlock(t.api) - block := tpkg.RandProtocolBlock(valBlock, t.api, 10) - block.IssuerID = accountID + block := tpkg.RandBlock(valBlock, t.api, 10) + block.Header.IssuerID = accountID subslotIndex := i // issued more than one block in the same slot to reduce performance factor if i >= slotPerformanceFactor { subslotIndex = 0 } - block.IssuingTime = t.api.TimeProvider().SlotStartTime(slot).Add(time.Duration(subslotIndex)*subslotDur + 1*time.Nanosecond) + block.Header.IssuingTime = t.api.TimeProvider().SlotStartTime(slot).Add(time.Duration(subslotIndex)*subslotDur + 1*time.Nanosecond) modelBlock, err := model.BlockFromBlock(block) t.Instance.TrackValidationBlock(blocks.NewBlock(modelBlock)) require.NoError(t.T, err) diff --git a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/tracker_test.go b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/tracker_test.go index 49a1a95bf..1eddb125d 100644 --- a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/tracker_test.go +++ b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/tracker_test.go @@ -96,20 +96,20 @@ func TestManager_Candidates(t *testing.T) { issuer2 := tpkg.RandAccountID() issuer3 := tpkg.RandAccountID() { - block1 := tpkg.RandProtocolBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) + block1 := tpkg.RandBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) - block1.IssuingTime = ts.api.TimeProvider().SlotStartTime(1) - block1.IssuerID = issuer1 + block1.Header.IssuingTime = ts.api.TimeProvider().SlotStartTime(1) + block1.Header.IssuerID = issuer1 - block2 := tpkg.RandProtocolBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) + block2 := tpkg.RandBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) - block2.IssuingTime = ts.api.TimeProvider().SlotStartTime(2) - block2.IssuerID = issuer2 + block2.Header.IssuingTime = ts.api.TimeProvider().SlotStartTime(2) + block2.Header.IssuerID = issuer2 - block3 := tpkg.RandProtocolBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) + block3 := tpkg.RandBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) - block3.IssuingTime = ts.api.TimeProvider().SlotStartTime(3) - block3.IssuerID = issuer3 + block3.Header.IssuingTime = ts.api.TimeProvider().SlotStartTime(3) + block3.Header.IssuerID = issuer3 ts.Instance.TrackCandidateBlock(blocks.NewBlock(lo.PanicOnErr(model.BlockFromBlock(block1)))) ts.Instance.TrackCandidateBlock(blocks.NewBlock(lo.PanicOnErr(model.BlockFromBlock(block2)))) @@ -117,19 +117,19 @@ func TestManager_Candidates(t *testing.T) { } { - block4 := tpkg.RandProtocolBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) - block4.IssuingTime = ts.api.TimeProvider().SlotStartTime(4) - block4.IssuerID = issuer1 + block4 := tpkg.RandBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) + block4.Header.IssuingTime = ts.api.TimeProvider().SlotStartTime(4) + block4.Header.IssuerID = issuer1 - block5 := tpkg.RandProtocolBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) + block5 := tpkg.RandBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) - block5.IssuingTime = ts.api.TimeProvider().SlotStartTime(5) - block5.IssuerID = issuer2 + block5.Header.IssuingTime = ts.api.TimeProvider().SlotStartTime(5) + block5.Header.IssuerID = issuer2 - block6 := tpkg.RandProtocolBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) + block6 := tpkg.RandBlock(tpkg.RandBasicBlock(ts.api, iotago.PayloadCandidacyAnnouncement), ts.api, 0) - block6.IssuingTime = ts.api.TimeProvider().SlotStartTime(6) - block6.IssuerID = issuer3 + block6.Header.IssuingTime = ts.api.TimeProvider().SlotStartTime(6) + block6.Header.IssuerID = issuer3 ts.Instance.TrackCandidateBlock(blocks.NewBlock(lo.PanicOnErr(model.BlockFromBlock(block4)))) ts.Instance.TrackCandidateBlock(blocks.NewBlock(lo.PanicOnErr(model.BlockFromBlock(block5)))) diff --git a/pkg/protocol/sybilprotection/sybilprotectionv1/sybilprotection.go b/pkg/protocol/sybilprotection/sybilprotectionv1/sybilprotection.go index 1e15ec4e2..2ebd75b0c 100644 --- a/pkg/protocol/sybilprotection/sybilprotectionv1/sybilprotection.go +++ b/pkg/protocol/sybilprotection/sybilprotectionv1/sybilprotection.go @@ -106,9 +106,9 @@ func (o *SybilProtection) TrackBlock(block *blocks.Block) { return } - accountData, exists, err := o.ledger.Account(block.ProtocolBlock().IssuerID, block.SlotCommitmentID().Slot()) + accountData, exists, err := o.ledger.Account(block.ProtocolBlock().Header.IssuerID, block.SlotCommitmentID().Slot()) if err != nil { - o.errHandler(ierrors.Wrapf(err, "error while retrieving account from account %s in slot %d from accounts ledger", block.ProtocolBlock().IssuerID, block.SlotCommitmentID().Slot())) + o.errHandler(ierrors.Wrapf(err, "error while retrieving account from account %s in slot %d from accounts ledger", block.ProtocolBlock().Header.IssuerID, block.SlotCommitmentID().Slot())) return } diff --git a/pkg/retainer/retainer/errors.go b/pkg/retainer/retainer/errors.go index 9ef4908a0..88d9594f6 100644 --- a/pkg/retainer/retainer/errors.go +++ b/pkg/retainer/retainer/errors.go @@ -62,6 +62,14 @@ var txErrorsFailureReasonMap = map[error]apimodels.TransactionFailureReason{ iotago.ErrInputOutputManaMismatch: apimodels.TxFailureManaAmountInvalid, iotago.ErrManaAmountInvalid: apimodels.TxFailureManaAmountInvalid, iotago.ErrInputCreationAfterTxCreation: apimodels.TxFailureInputCreationAfterTxCreation, + + // tx capabilities errors + iotago.ErrTxCapabilitiesNativeTokenBurningNotAllowed: apimodels.TxFailureCapabilitiesNativeTokenBurningNotAllowed, + iotago.ErrTxCapabilitiesManaBurningNotAllowed: apimodels.TxFailureCapabilitiesManaBurningNotAllowed, + iotago.ErrTxCapabilitiesAccountDestructionNotAllowed: apimodels.TxFailureCapabilitiesAccountDestructionNotAllowed, + iotago.ErrTxCapabilitiesAnchorDestructionNotAllowed: apimodels.TxFailureCapabilitiesAnchorDestructionNotAllowed, + iotago.ErrTxCapabilitiesFoundryDestructionNotAllowed: apimodels.TxFailureCapabilitiesFoundryDestructionNotAllowed, + iotago.ErrTxCapabilitiesNFTDestructionNotAllowed: apimodels.TxFailureCapabilitiesNFTDestructionNotAllowed, } func determineTxFailureReason(err error) apimodels.TransactionFailureReason { diff --git a/pkg/storage/testframework_test.go b/pkg/storage/testframework_test.go index c88a32ff2..290f180dd 100644 --- a/pkg/storage/testframework_test.go +++ b/pkg/storage/testframework_test.go @@ -90,7 +90,7 @@ func (t *TestFramework) GeneratePrunableData(epoch iotago.EpochIndex, size int64 endSlot := apiForEpoch.TimeProvider().EpochEnd(epoch) var createdBytes int64 for createdBytes < size { - block := tpkg.RandProtocolBlock(&iotago.BasicBlock{ + block := tpkg.RandBlock(&iotago.BasicBlockBody{ StrongParents: tpkg.SortedRandBlockIDs(1 + rand.Intn(iotago.BlockMaxParents)), Payload: &iotago.TaggedData{Data: make([]byte, 8192)}, MaxBurnedMana: 1000, diff --git a/pkg/tests/accounts_test.go b/pkg/tests/accounts_test.go index 1195eba30..99886583d 100644 --- a/pkg/tests/accounts_test.go +++ b/pkg/tests/accounts_test.go @@ -3,40 +3,34 @@ package tests import ( "testing" - "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/model" - "github.com/iotaledger/iota-core/pkg/protocol" "github.com/iotaledger/iota-core/pkg/protocol/engine/accounts" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" "github.com/iotaledger/iota-core/pkg/testsuite" "github.com/iotaledger/iota-core/pkg/testsuite/mock" + "github.com/iotaledger/iota-core/pkg/testsuite/snapshotcreator" "github.com/iotaledger/iota-core/pkg/utils" iotago "github.com/iotaledger/iota.go/v4" ) -// TODO: implement tests for staking and delegation transitions that cover edge cases - part of hardening phase. -func Test_TransitionAccount(t *testing.T) { +func Test_TransitionAndDestroyAccount(t *testing.T) { oldGenesisOutputKey := utils.RandBlockIssuerKey() + ts := testsuite.NewTestSuite(t, testsuite.WithAccounts(snapshotcreator.AccountDetails{ // Nil address will be replaced with the address generated from genesis seed. - // A single key may unlock multiple accounts; that's why it can't be used as a source for AccountID derivation. Address: nil, - // Set an amount enough to cover the rent and to cover an additional key that is added in the test. - // If it's too little, then the test will fail. - Amount: testsuite.MinIssuerAccountAmount * 10, + // Set an amount enough to cover storage deposit and more issuer keys. + Amount: mock.MinIssuerAccountAmount * 10, Mana: 0, // AccountID is derived from this field, so this must be set uniquely for each account. IssuerKey: oldGenesisOutputKey, // Expiry Slot is the slot index at which the account expires. - ExpirySlot: 1, + ExpirySlot: iotago.MaxSlotIndex, // BlockIssuanceCredits on this account is custom because it never needs to issue. - // On Validator nodes it's unlimited (MaxInt64). BlockIssuanceCredits: iotago.BlockIssuanceCredits(123), }), testsuite.WithProtocolParametersOptions( iotago.WithTimeProviderOptions( - testsuite.GenesisTimeWithOffsetBySlots(100, testsuite.DefaultSlotDurationInSeconds), + testsuite.GenesisTimeWithOffsetBySlots(200, testsuite.DefaultSlotDurationInSeconds), testsuite.DefaultSlotDurationInSeconds, 8, ), @@ -51,68 +45,73 @@ func Test_TransitionAccount(t *testing.T) { ) defer ts.Shutdown() + // add a validator node to the network. This will add a validator account to the snapshot. node1 := ts.AddValidatorNode("node1") + // add a non-validator node to the network. This will not add any accounts to the snapshot. _ = ts.AddNode("node2") - blockIssuer := ts.AddBasicBlockIssuer("default", iotago.MaxBlockIssuanceCredits/2) + // add a default block issuer to the network. This will add another block issuer account to the snapshot. + wallet := ts.AddGenesisWallet("default", node1, iotago.MaxBlockIssuanceCredits/2) - ts.Run(true, map[string][]options.Option[protocol.Protocol]{}) + ts.Run(true) + // check that the accounts added in the genesis snapshot were added to account manager correctly. + // genesis account. genesisAccount := ts.AccountOutput("Genesis:1") genesisAccountOutput := genesisAccount.Output().(*iotago.AccountOutput) - ts.AssertAccountData(&accounts.AccountData{ ID: genesisAccountOutput.AccountID, Credits: accounts.NewBlockIssuanceCredits(iotago.BlockIssuanceCredits(123), 0), OutputID: genesisAccount.OutputID(), - ExpirySlot: 1, + ExpirySlot: iotago.MaxSlotIndex, BlockIssuerKeys: iotago.NewBlockIssuerKeys(oldGenesisOutputKey), }, ts.Nodes()...) + // validator node account. + validatorAccountOutput := ts.AccountOutput("Genesis:2") + ts.AssertAccountData(&accounts.AccountData{ + ID: node1.Validator.AccountID, + Credits: accounts.NewBlockIssuanceCredits(iotago.MaxBlockIssuanceCredits/2, 0), + OutputID: validatorAccountOutput.OutputID(), + ExpirySlot: iotago.MaxSlotIndex, + BlockIssuerKeys: node1.Validator.BlockIssuerKeys(), + StakeEndEpoch: iotago.MaxEpochIndex, + ValidatorStake: mock.MinValidatorAccountAmount, + }, ts.Nodes()...) + // default wallet block issuer account. + blockIssuerAccountOutput := ts.AccountOutput("Genesis:3") + ts.AssertAccountData(&accounts.AccountData{ + ID: wallet.BlockIssuer.AccountID, + Credits: accounts.NewBlockIssuanceCredits(iotago.MaxBlockIssuanceCredits/2, 0), + OutputID: blockIssuerAccountOutput.OutputID(), + ExpirySlot: iotago.MaxSlotIndex, + BlockIssuerKeys: wallet.BlockIssuer.BlockIssuerKeys(), + }, ts.Nodes()...) - // MODIFY EXISTING GENESIS ACCOUNT AND PREPARE SOME BASIC OUTPUTS - + // MODIFY EXISTING GENESIS ACCOUNT newGenesisOutputKey := utils.RandBlockIssuerKey() - newAccountBlockIssuerKey := utils.RandBlockIssuerKey() - latestCommitmentID := node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID() + var block1Slot iotago.SlotIndex = 1 + // set the expiry of the genesis account to be the block slot + max committable age. + newExpirySlot := block1Slot + ts.API.ProtocolParameters().MaxCommittableAge() - accountInput, accountOutputs, accountWallets := ts.TransactionFramework.TransitionAccount( + tx1 := ts.DefaultWallet().TransitionAccount( + "TX1", "Genesis:1", - testsuite.WithAddBlockIssuerKey(newGenesisOutputKey), - testsuite.WithBlockIssuerExpirySlot(1), + mock.WithAddBlockIssuerKey(newGenesisOutputKey), + mock.WithBlockIssuerExpirySlot(newExpirySlot), ) - consumedInputs, equalOutputs, equalWallets := ts.TransactionFramework.CreateBasicOutputsEqually(4, "Genesis:0") - - tx1 := lo.PanicOnErr(ts.TransactionFramework.CreateSignedTransactionWithOptions("TX1", append(accountWallets, equalWallets...), - testsuite.WithAccountInput(accountInput, true), - testsuite.WithInputs(consumedInputs), - testsuite.WithContextInputs(iotago.TxEssenceContextInputs{ - &iotago.BlockIssuanceCreditInput{ - AccountID: genesisAccountOutput.AccountID, - }, - &iotago.CommitmentInput{ - CommitmentID: latestCommitmentID, - }, - }), - testsuite.WithOutputs(append(accountOutputs, equalOutputs...)), - testsuite.WithAllotments(iotago.Allotments{&iotago.Allotment{ - AccountID: genesisAccountOutput.AccountID, - Mana: 0, - }}), - )) - var block1Slot iotago.SlotIndex = 1 + // default block issuer issues a block containing the transaction in slot 1. genesisCommitment := iotago.NewEmptyCommitment(ts.API.ProtocolParameters().Version()) genesisCommitment.ReferenceManaCost = ts.API.ProtocolParameters().CongestionControlParameters().MinReferenceManaCost - - block1 := ts.IssueBasicBlockAtSlotWithOptions("block1", block1Slot, genesisCommitment, blockIssuer, node1, tx1) - + block1 := ts.IssueBasicBlockAtSlotWithOptions("block1", block1Slot, ts.DefaultWallet(), tx1, mock.WithSlotCommitment(genesisCommitment)) latestParent := ts.CommitUntilSlot(ts.BlockID("block1").Slot(), block1) + // assert diff of the genesis account, it should have a new output ID, new expiry slot and a new block issuer key. ts.AssertAccountDiff(genesisAccountOutput.AccountID, block1Slot, &model.AccountDiff{ BICChange: 0, PreviousUpdatedTime: 0, - PreviousExpirySlot: 1, - NewExpirySlot: 1, - NewOutputID: iotago.OutputIDFromTransactionIDAndIndex(ts.TransactionFramework.TransactionID("TX1"), 0), + PreviousExpirySlot: iotago.MaxSlotIndex, + NewExpirySlot: newExpirySlot, + NewOutputID: ts.DefaultWallet().Output("TX1:0").OutputID(), PreviousOutputID: genesisAccount.OutputID(), BlockIssuerKeysRemoved: iotago.NewBlockIssuerKeys(), BlockIssuerKeysAdded: iotago.NewBlockIssuerKeys(newGenesisOutputKey), @@ -121,57 +120,30 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: genesisAccountOutput.AccountID, Credits: accounts.NewBlockIssuanceCredits(iotago.BlockIssuanceCredits(123), 0), - OutputID: iotago.OutputIDFromTransactionIDAndIndex(ts.TransactionFramework.TransactionID("TX1"), 0), + OutputID: ts.DefaultWallet().Output("TX1:0").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(oldGenesisOutputKey, newGenesisOutputKey), - ExpirySlot: 1, + ExpirySlot: newExpirySlot, }, ts.Nodes()...) - // DESTROY GENESIS ACCOUNT, CREATE NEW ACCOUNT WITH BLOCK ISSUER AND STAKING FEATURES FROM BASIC UTXO - - // commit until the expiry slot of the transitioned genesis account plus one - latestParent = ts.CommitUntilSlot(accountOutputs[0].FeatureSet().BlockIssuer().ExpirySlot+1, latestParent) - // set the expiry slof of the transitioned genesis account to the latest committed + MaxCommittableAge - newAccountExpirySlot := node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Slot() + ts.API.ProtocolParameters().MaxCommittableAge() - inputForNewAccount, newAccountOutputs, newAccountWallets := ts.TransactionFramework.CreateAccountFromInput("TX1:1", - testsuite.WithAccountConditions(iotago.AccountOutputUnlockConditions{ - &iotago.StateControllerAddressUnlockCondition{Address: ts.TransactionFramework.DefaultAddress()}, - &iotago.GovernorAddressUnlockCondition{Address: ts.TransactionFramework.DefaultAddress()}, - }), - testsuite.WithBlockIssuerFeature(iotago.BlockIssuerKeys{newAccountBlockIssuerKey}, newAccountExpirySlot), - testsuite.WithStakingFeature(10000, 421, 0, 10), - ) - - destroyedAccountInput, destructionOutputs, destroyWallets := ts.TransactionFramework.DestroyAccount("TX1:0") + // DESTROY GENESIS ACCOUNT + // commit until the expiry slot of the transitioned genesis account plus one. + latestParent = ts.CommitUntilSlot(newExpirySlot+1, latestParent) + // issue the block containing the transaction in the same slot as the latest parent block. block2Slot := latestParent.ID().Slot() - - tx2 := lo.PanicOnErr(ts.TransactionFramework.CreateSignedTransactionWithOptions("TX2", append(newAccountWallets, destroyWallets...), - testsuite.WithContextInputs(iotago.TxEssenceContextInputs{ - &iotago.BlockIssuanceCreditInput{ - AccountID: genesisAccountOutput.AccountID, - }, - &iotago.CommitmentInput{ - CommitmentID: node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), - }, - }), - testsuite.WithInputs(inputForNewAccount), - testsuite.WithAccountInput(destroyedAccountInput, true), - testsuite.WithOutputs(append(newAccountOutputs, destructionOutputs...)), - testsuite.WithSlotCreated(block2Slot), - )) - - block2 := ts.IssueBasicBlockAtSlotWithOptions("block2", block2Slot, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), blockIssuer, node1, tx2, mock.WithStrongParents(latestParent.ID())) - + // create a transaction which destroys the genesis account. + tx2 := ts.DefaultWallet().DestroyAccount("TX2", "TX1:0", block2Slot) + block2 := ts.IssueBasicBlockAtSlotWithOptions("block2", block2Slot, ts.DefaultWallet(), tx2, mock.WithStrongParents(latestParent.ID())) latestParent = ts.CommitUntilSlot(block2Slot, block2) - // assert diff of a destroyed account, to make sure we can correctly restore it + // assert diff of the destroyed account. ts.AssertAccountDiff(genesisAccountOutput.AccountID, block2Slot, &model.AccountDiff{ BICChange: -iotago.BlockIssuanceCredits(123), PreviousUpdatedTime: 0, NewExpirySlot: 0, - PreviousExpirySlot: 1, + PreviousExpirySlot: newExpirySlot, NewOutputID: iotago.EmptyOutputID, - PreviousOutputID: iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(ts.TransactionFramework.Transaction("TX1").ID()), 0), + PreviousOutputID: ts.DefaultWallet().Output("TX1:0").OutputID(), BlockIssuerKeysAdded: iotago.NewBlockIssuerKeys(), BlockIssuerKeysRemoved: iotago.NewBlockIssuerKeys(oldGenesisOutputKey, newGenesisOutputKey), ValidatorStakeChange: 0, @@ -179,11 +151,83 @@ func Test_TransitionAccount(t *testing.T) { FixedCostChange: 0, DelegationStakeChange: 0, }, true, ts.Nodes()...) +} + +func Test_StakeDelegateAndDelayedClaim(t *testing.T) { + ts := testsuite.NewTestSuite(t, + testsuite.WithProtocolParametersOptions( + iotago.WithTimeProviderOptions( + testsuite.GenesisTimeWithOffsetBySlots(100, testsuite.DefaultSlotDurationInSeconds), + testsuite.DefaultSlotDurationInSeconds, + 8, + ), + iotago.WithLivenessOptions( + testsuite.DefaultLivenessThresholdLowerBoundInSeconds, + testsuite.DefaultLivenessThresholdUpperBoundInSeconds, + testsuite.DefaultMinCommittableAge, + 100, + testsuite.DefaultEpochNearingThreshold, + ), + ), + ) + defer ts.Shutdown() + + // add a validator node to the network. This will add a validator account to the snapshot. + node1 := ts.AddValidatorNode("node1") + // add a non-validator node to the network. This will not add any accounts to the snapshot. + _ = ts.AddNode("node2") + // add a default block issuer to the network. This will add another block issuer account to the snapshot. + wallet := ts.AddGenesisWallet("default", node1, iotago.MaxBlockIssuanceCredits/2) + + ts.Run(true) + + // assert validator and block issuer accounts in genesis snapshot. + // validator node account. + validatorAccountOutput := ts.AccountOutput("Genesis:1") + ts.AssertAccountData(&accounts.AccountData{ + ID: node1.Validator.AccountID, + Credits: accounts.NewBlockIssuanceCredits(iotago.MaxBlockIssuanceCredits/2, 0), + OutputID: validatorAccountOutput.OutputID(), + ExpirySlot: iotago.MaxSlotIndex, + BlockIssuerKeys: node1.Validator.BlockIssuerKeys(), + StakeEndEpoch: iotago.MaxEpochIndex, + ValidatorStake: mock.MinValidatorAccountAmount, + }, ts.Nodes()...) + // default wallet block issuer account. + blockIssuerAccountOutput := ts.AccountOutput("Genesis:2") + ts.AssertAccountData(&accounts.AccountData{ + ID: wallet.BlockIssuer.AccountID, + Credits: accounts.NewBlockIssuanceCredits(iotago.MaxBlockIssuanceCredits/2, 0), + OutputID: blockIssuerAccountOutput.OutputID(), + ExpirySlot: iotago.MaxSlotIndex, + BlockIssuerKeys: wallet.BlockIssuer.BlockIssuerKeys(), + }, ts.Nodes()...) + + //CREATE NEW ACCOUNT WITH BLOCK ISSUER AND STAKING FEATURES FROM BASIC UTXO + newAccountBlockIssuerKey := utils.RandBlockIssuerKey() + // set the expiry slot of the transitioned genesis account to the latest committed + MaxCommittableAge + newAccountExpirySlot := node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Slot() + ts.API.ProtocolParameters().MaxCommittableAge() + + var block1Slot iotago.SlotIndex = 1 + tx1 := ts.DefaultWallet().CreateAccountFromInput( + "TX1", + "Genesis:0", + ts.DefaultWallet(), + block1Slot, + mock.WithBlockIssuerFeature(iotago.BlockIssuerKeys{newAccountBlockIssuerKey}, newAccountExpirySlot), + mock.WithStakingFeature(10000, 421, 0, 10), + mock.WithAccountAmount(mock.MinIssuerAccountAmount), + ) + + genesisCommitment := iotago.NewEmptyCommitment(ts.API.ProtocolParameters().Version()) + genesisCommitment.ReferenceManaCost = ts.API.ProtocolParameters().CongestionControlParameters().MinReferenceManaCost + block1 := ts.IssueBasicBlockAtSlotWithOptions("block1", block1Slot, ts.DefaultWallet(), tx1) + latestParent := ts.CommitUntilSlot(block1Slot, block1) - newAccount := ts.AccountOutput("TX2:0") + newAccount := ts.DefaultWallet().AccountOutput("TX1:0") newAccountOutput := newAccount.Output().(*iotago.AccountOutput) - ts.AssertAccountDiff(newAccountOutput.AccountID, block2Slot, &model.AccountDiff{ + ts.AssertAccountDiff(newAccountOutput.AccountID, block1Slot, &model.AccountDiff{ BICChange: 0, PreviousUpdatedTime: 0, NewExpirySlot: newAccountExpirySlot, @@ -200,7 +244,7 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: newAccountOutput.AccountID, - Credits: accounts.NewBlockIssuanceCredits(0, block2Slot), + Credits: accounts.NewBlockIssuanceCredits(0, block1Slot), ExpirySlot: newAccountExpirySlot, OutputID: newAccount.OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(newAccountBlockIssuerKey), @@ -210,32 +254,22 @@ func Test_TransitionAccount(t *testing.T) { ValidatorStake: 10000, }, ts.Nodes()...) + // CREATE DELEGATION TO NEW ACCOUNT FROM BASIC UTXO accountAddress := iotago.AccountAddress(newAccountOutput.AccountID) - // create a delegation output delegating to the newly created account - inputForNewDelegation, newDelegationOutputs, newDelegationWallets := ts.TransactionFramework.CreateDelegationFromInput("TX1:2", - testsuite.WithDelegatedValidatorAddress(&accountAddress), - testsuite.WithDelegationStartEpoch(1), + block2Slot := latestParent.ID().Slot() + tx2 := ts.DefaultWallet().CreateDelegationFromInput( + "TX2", + "TX1:1", + block2Slot, + mock.WithDelegatedValidatorAddress(&accountAddress), + mock.WithDelegationStartEpoch(1), ) + block2 := ts.IssueBasicBlockAtSlotWithOptions("block2", block2Slot, ts.DefaultWallet(), tx2, mock.WithStrongParents(latestParent.ID())) - block3Slot := latestParent.ID().Slot() - - tx3 := lo.PanicOnErr(ts.TransactionFramework.CreateSignedTransactionWithOptions("TX3", newDelegationWallets, - testsuite.WithContextInputs(iotago.TxEssenceContextInputs{ - &iotago.CommitmentInput{ - CommitmentID: node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), - }, - }), - testsuite.WithInputs(inputForNewDelegation), - testsuite.WithOutputs(newDelegationOutputs), - testsuite.WithSlotCreated(block3Slot), - )) - - block3 := ts.IssueBasicBlockAtSlotWithOptions("block3", block3Slot, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), blockIssuer, node1, tx3, mock.WithStrongParents(latestParent.ID())) - - latestParent = ts.CommitUntilSlot(block3Slot, block3) - delegatedAmount := inputForNewDelegation[0].BaseTokenAmount() + latestParent = ts.CommitUntilSlot(block2Slot, block2) + delegatedAmount := ts.DefaultWallet().Output("TX1:1").BaseTokenAmount() - ts.AssertAccountDiff(newAccountOutput.AccountID, block3Slot, &model.AccountDiff{ + ts.AssertAccountDiff(newAccountOutput.AccountID, block2Slot, &model.AccountDiff{ BICChange: 0, PreviousUpdatedTime: 0, NewOutputID: iotago.EmptyOutputID, @@ -250,7 +284,7 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: newAccountOutput.AccountID, - Credits: accounts.NewBlockIssuanceCredits(0, block2Slot), + Credits: accounts.NewBlockIssuanceCredits(0, block1Slot), ExpirySlot: newAccountExpirySlot, OutputID: newAccount.OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(newAccountBlockIssuerKey), @@ -261,27 +295,14 @@ func Test_TransitionAccount(t *testing.T) { }, ts.Nodes()...) // transition a delegation output to a delayed claiming state - inputForDelegationTransition, delegationTransitionOutputs, delegationTransitionWallets := ts.TransactionFramework.DelayedClaimingTransition("TX3:0", 0) - - tx4 := lo.PanicOnErr(ts.TransactionFramework.CreateSignedTransactionWithOptions("TX4", delegationTransitionWallets, - testsuite.WithContextInputs(iotago.TxEssenceContextInputs{ - &iotago.CommitmentInput{ - CommitmentID: node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), - }, - }), - testsuite.WithInputs(inputForDelegationTransition), - testsuite.WithOutputs(delegationTransitionOutputs), - testsuite.WithSlotCreated(block3Slot), - )) - - block4Slot := latestParent.ID().Slot() - - block4 := ts.IssueBasicBlockAtSlotWithOptions("block4", block4Slot, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), blockIssuer, node1, tx4, mock.WithStrongParents(latestParent.ID())) + block3Slot := latestParent.ID().Slot() + tx3 := ts.DefaultWallet().DelayedClaimingTransition("TX3", "TX2:0", block3Slot, 0) + block3 := ts.IssueBasicBlockAtSlotWithOptions("block3", block3Slot, ts.DefaultWallet(), tx3, mock.WithStrongParents(latestParent.ID())) - latestParent = ts.CommitUntilSlot(block4Slot, block4) + latestParent = ts.CommitUntilSlot(block3Slot, block3) // Transitioning to delayed claiming effectively removes the delegation, so we expect a negative delegation stake change. - ts.AssertAccountDiff(newAccountOutput.AccountID, block4Slot, &model.AccountDiff{ + ts.AssertAccountDiff(newAccountOutput.AccountID, block3Slot, &model.AccountDiff{ BICChange: 0, PreviousUpdatedTime: 0, NewOutputID: iotago.EmptyOutputID, @@ -296,7 +317,7 @@ func Test_TransitionAccount(t *testing.T) { ts.AssertAccountData(&accounts.AccountData{ ID: newAccountOutput.AccountID, - Credits: accounts.NewBlockIssuanceCredits(0, block2Slot), + Credits: accounts.NewBlockIssuanceCredits(0, block1Slot), ExpirySlot: newAccountExpirySlot, OutputID: newAccount.OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(newAccountBlockIssuerKey), @@ -305,72 +326,110 @@ func Test_TransitionAccount(t *testing.T) { DelegationStake: iotago.BaseToken(0), ValidatorStake: 10000, }, ts.Nodes()...) +} - // CREATE IMPLICIT ACCOUNT FROM BASIC UTXO - inputForImplicitAccount, outputsForImplicitAccount, implicitAccountAddress, implicitWallet := ts.TransactionFramework.CreateImplicitAccountFromInput("TX1:3") - - tx5 := lo.PanicOnErr(ts.TransactionFramework.CreateSignedTransactionWithOptions("TX5", implicitWallet, - testsuite.WithInputs(inputForImplicitAccount), - testsuite.WithOutputs(outputsForImplicitAccount), - )) - - implicitAccountOutput := ts.TransactionFramework.Output("TX5:0") - implicitAccountOutputID := implicitAccountOutput.OutputID() - implicitAccountID := iotago.AccountIDFromOutputID(implicitAccountOutputID) +func Test_ImplicitAccounts(t *testing.T) { + ts := testsuite.NewTestSuite(t, + testsuite.WithProtocolParametersOptions( + iotago.WithTimeProviderOptions( + testsuite.GenesisTimeWithOffsetBySlots(100, testsuite.DefaultSlotDurationInSeconds), + testsuite.DefaultSlotDurationInSeconds, + 8, + ), + iotago.WithLivenessOptions( + testsuite.DefaultLivenessThresholdLowerBoundInSeconds, + testsuite.DefaultLivenessThresholdUpperBoundInSeconds, + testsuite.DefaultMinCommittableAge, + 100, + testsuite.DefaultEpochNearingThreshold, + ), + ), + ) + defer ts.Shutdown() - slotIndexBlock5 := latestParent.ID().Index() + // add a validator node to the network. This will add a validator account to the snapshot. + node1 := ts.AddValidatorNode("node1") + // add a non-validator node to the network. This will not add any accounts to the snapshot. + _ = ts.AddNode("node2") + // add a default block issuer to the network. This will add another block issuer account to the snapshot. + wallet := ts.AddGenesisWallet("default", node1, iotago.MaxBlockIssuanceCredits/2) - block5 := ts.IssueBasicBlockAtSlotWithOptions("block5", slotIndexBlock5, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), blockIssuer, node1, tx5, mock.WithStrongParents(latestParent.ID())) + ts.Run(true) - latestParent = ts.CommitUntilSlot(slotIndexBlock5, block5) + // assert validator and block issuer accounts in genesis snapshot. + // validator node account. + validatorAccountOutput := ts.AccountOutput("Genesis:1") + ts.AssertAccountData(&accounts.AccountData{ + ID: node1.Validator.AccountID, + Credits: accounts.NewBlockIssuanceCredits(iotago.MaxBlockIssuanceCredits/2, 0), + OutputID: validatorAccountOutput.OutputID(), + ExpirySlot: iotago.MaxSlotIndex, + BlockIssuerKeys: node1.Validator.BlockIssuerKeys(), + StakeEndEpoch: iotago.MaxEpochIndex, + ValidatorStake: mock.MinValidatorAccountAmount, + }, ts.Nodes()...) + // default wallet block issuer account. + blockIssuerAccountOutput := ts.AccountOutput("Genesis:2") + ts.AssertAccountData(&accounts.AccountData{ + ID: wallet.BlockIssuer.AccountID, + Credits: accounts.NewBlockIssuanceCredits(iotago.MaxBlockIssuanceCredits/2, 0), + OutputID: blockIssuerAccountOutput.OutputID(), + ExpirySlot: iotago.MaxSlotIndex, + BlockIssuerKeys: wallet.BlockIssuer.BlockIssuerKeys(), + }, ts.Nodes()...) - var implicitBlockIssuerKey iotago.BlockIssuerKey = iotago.Ed25519PublicKeyHashBlockIssuerKeyFromImplicitAccountCreationAddress(implicitAccountAddress) + // CREATE IMPLICIT ACCOUNT FROM GENESIS BASIC UTXO, SENT TO A NEW USER WALLET. + // this wallet is not registered in the ledger yet. + newUserWallet := mock.NewWallet(ts.Testing, "newUser", node1) + // a default wallet, already registered in the ledger, will issue the transaction and block. + tx1 := ts.DefaultWallet().CreateImplicitAccountFromInput( + "TX1", + "Genesis:0", + newUserWallet, + ) + var block1Slot iotago.SlotIndex = 1 + block1 := ts.IssueBasicBlockAtSlotWithOptions("block1", block1Slot, ts.DefaultWallet(), tx1) + latestParent := ts.CommitUntilSlot(block1Slot, block1) + implicitAccountOutput := newUserWallet.Output("TX1:0") + implicitAccountOutputID := implicitAccountOutput.OutputID() + implicitAccountID := iotago.AccountIDFromOutputID(implicitAccountOutputID) + var implicitBlockIssuerKey iotago.BlockIssuerKey = iotago.Ed25519PublicKeyHashBlockIssuerKeyFromImplicitAccountCreationAddress(newUserWallet.ImplicitAccountCreationAddress()) + // the new implicit account should now be registered in the accounts ledger. ts.AssertAccountData(&accounts.AccountData{ ID: implicitAccountID, - Credits: accounts.NewBlockIssuanceCredits(0, slotIndexBlock5), + Credits: accounts.NewBlockIssuanceCredits(0, block1Slot), ExpirySlot: iotago.MaxSlotIndex, OutputID: implicitAccountOutputID, BlockIssuerKeys: iotago.NewBlockIssuerKeys(implicitBlockIssuerKey), }, ts.Nodes()...) - // TRANSITION IMPLICIT ACCOUNT TO ACCOUNT OUTPUT - + // TRANSITION IMPLICIT ACCOUNT TO ACCOUNT OUTPUT. + // USE IMPLICIT ACCOUNT AS BLOCK ISSUER. fullAccountBlockIssuerKey := utils.RandBlockIssuerKey() - inputForImplicitAccountTransition, outputsForImplicitAccountTransition, fullAccountWallet := ts.TransactionFramework.TransitionImplicitAccountToAccountOutput( - "TX5:0", - testsuite.WithBlockIssuerFeature( + block2Slot := latestParent.ID().Index() + tx2 := newUserWallet.TransitionImplicitAccountToAccountOutput( + "TX2", + "TX1:0", + block2Slot, + mock.WithBlockIssuerFeature( iotago.BlockIssuerKeys{fullAccountBlockIssuerKey}, iotago.MaxSlotIndex, ), + mock.WithAccountAmount(mock.MinIssuerAccountAmount), ) + block2Commitment := node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment() + block2 := ts.IssueBasicBlockAtSlotWithOptions("block2", block2Slot, newUserWallet, tx2, mock.WithStrongParents(latestParent.ID())) + latestParent = ts.CommitUntilSlot(block2Slot, block2) - tx6 := lo.PanicOnErr(ts.TransactionFramework.CreateSignedTransactionWithOptions("TX6", fullAccountWallet, - testsuite.WithContextInputs(iotago.TxEssenceContextInputs{ - &iotago.BlockIssuanceCreditInput{ - AccountID: implicitAccountID, - }, - &iotago.CommitmentInput{ - CommitmentID: node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), - }, - }), - testsuite.WithInputs(inputForImplicitAccountTransition), - testsuite.WithOutputs(outputsForImplicitAccountTransition), - testsuite.WithSlotCreated(slotIndexBlock5), - )) - - slotIndexBlock6 := latestParent.ID().Index() - - block6 := ts.IssueBasicBlockAtSlotWithOptions("block6", slotIndexBlock6, node1.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), blockIssuer, node1, tx6, mock.WithStrongParents(latestParent.ID())) - - latestParent = ts.CommitUntilSlot(slotIndexBlock6, block6) - - fullAccountOutputID := ts.TransactionFramework.Output("TX6:0").OutputID() - - ts.AssertAccountDiff(implicitAccountID, slotIndexBlock6, &model.AccountDiff{ - BICChange: 0, - PreviousUpdatedTime: 0, + fullAccountOutputID := newUserWallet.Output("TX2:0").OutputID() + allotted := iotago.BlockIssuanceCredits(tx2.Transaction.Allotments.Get(implicitAccountID)) + burned := iotago.BlockIssuanceCredits(block2.WorkScore()) * iotago.BlockIssuanceCredits(block2Commitment.ReferenceManaCost) + // the implicit account should now have been transitioned to a full account in the accounts ledger. + ts.AssertAccountDiff(implicitAccountID, block2Slot, &model.AccountDiff{ + BICChange: allotted - burned, + PreviousUpdatedTime: block1Slot, NewOutputID: fullAccountOutputID, PreviousOutputID: implicitAccountOutputID, PreviousExpirySlot: iotago.MaxSlotIndex, @@ -382,10 +441,9 @@ func Test_TransitionAccount(t *testing.T) { FixedCostChange: 0, DelegationStakeChange: 0, }, false, ts.Nodes()...) - ts.AssertAccountData(&accounts.AccountData{ ID: implicitAccountID, - Credits: accounts.NewBlockIssuanceCredits(0, slotIndexBlock5), + Credits: accounts.NewBlockIssuanceCredits(allotted-burned, block2Slot), ExpirySlot: iotago.MaxSlotIndex, OutputID: fullAccountOutputID, BlockIssuerKeys: iotago.NewBlockIssuerKeys(fullAccountBlockIssuerKey), diff --git a/pkg/tests/booker_test.go b/pkg/tests/booker_test.go index e667664e3..8a9e2e576 100644 --- a/pkg/tests/booker_test.go +++ b/pkg/tests/booker_test.go @@ -18,33 +18,33 @@ func Test_IssuingTransactionsOutOfOrder(t *testing.T) { defer ts.Shutdown() node1 := ts.AddValidatorNode("node1") - blockIssuer := ts.AddBasicBlockIssuer("default") + wallet := ts.AddGenesisWallet("default", node1) ts.Run(true, map[string][]options.Option[protocol.Protocol]{}) - tx1 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx1", 1, "Genesis:0")) + tx1 := wallet.CreateBasicOutputsEquallyFromInputs("tx1", 1, "Genesis:0") - tx2 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx2", 1, "tx1:0")) + tx2 := wallet.CreateBasicOutputsEquallyFromInputs("tx2", 1, "tx1:0") - ts.IssuePayloadWithOptions("block1", blockIssuer, node1, tx2) + ts.IssuePayloadWithOptions("block1", wallet, tx2) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx2"), true, node1) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1"), false, node1) + ts.AssertTransactionsExist(wallet.Transactions("tx2"), true, node1) + ts.AssertTransactionsExist(wallet.Transactions("tx1"), false, node1) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx2"), false, node1) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx2"), false, node1) // make sure that the block is not booked - ts.IssuePayloadWithOptions("block2", blockIssuer, node1, tx1) + ts.IssuePayloadWithOptions("block2", wallet, tx1) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), true, node1) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, node1) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block1"): {"tx2"}, ts.Block("block2"): {"tx1"}, }, node1) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ - ts.TransactionFramework.Transaction("tx2"): {"tx2"}, - ts.TransactionFramework.Transaction("tx1"): {"tx1"}, + wallet.Transaction("tx2"): {"tx2"}, + wallet.Transaction("tx1"): {"tx1"}, }, node1) } @@ -54,7 +54,7 @@ func Test_DoubleSpend(t *testing.T) { node1 := ts.AddValidatorNode("node1") node2 := ts.AddValidatorNode("node2") - blockIssuer := ts.AddBasicBlockIssuer("default") + wallet := ts.AddGenesisWallet("default", node1) ts.Run(true, map[string][]options.Option[protocol.Protocol]{}) @@ -65,23 +65,23 @@ func Test_DoubleSpend(t *testing.T) { // Create and issue double spends { - tx1 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx1", 1, "Genesis:0")) - tx2 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx2", 1, "Genesis:0")) + tx1 := wallet.CreateBasicOutputsEquallyFromInputs("tx1", 1, "Genesis:0") + tx2 := wallet.CreateBasicOutputsEquallyFromInputs("tx2", 1, "Genesis:0") - ts.IssuePayloadWithOptions("block1", blockIssuer, node1, tx1, mock.WithStrongParents(ts.BlockID("Genesis"))) - ts.IssuePayloadWithOptions("block2", blockIssuer, node1, tx2, mock.WithStrongParents(ts.BlockID("Genesis"))) + ts.IssuePayloadWithOptions("block1", wallet, tx1, mock.WithStrongParents(ts.BlockID("Genesis"))) + ts.IssuePayloadWithOptions("block2", wallet, tx2, mock.WithStrongParents(ts.BlockID("Genesis"))) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block1"): {"tx1"}, ts.Block("block2"): {"tx2"}, }, node1, node2) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ - ts.TransactionFramework.Transaction("tx2"): {"tx2"}, - ts.TransactionFramework.Transaction("tx1"): {"tx1"}, + wallet.Transaction("tx2"): {"tx2"}, + wallet.Transaction("tx1"): {"tx1"}, }, node1, node2) } @@ -94,14 +94,14 @@ func Test_DoubleSpend(t *testing.T) { ts.Block("block3"): {"tx1"}, ts.Block("block4"): {"tx2"}, }, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) } // Issue an invalid block and assert that its vote is not cast. { ts.IssueValidationBlock("block5", node2, mock.WithStrongParents(ts.BlockIDs("block3", "block4")...)) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) } // Issue valid blocks that resolve the conflict. @@ -112,8 +112,8 @@ func Test_DoubleSpend(t *testing.T) { ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block6"): {"tx2"}, }, node1, node2) - ts.AssertTransactionsInCacheAccepted(ts.TransactionFramework.Transactions("tx2"), true, node1, node2) - ts.AssertTransactionsInCacheRejected(ts.TransactionFramework.Transactions("tx1"), true, node1, node2) + ts.AssertTransactionsInCacheAccepted(wallet.Transactions("tx2"), true, node1, node2) + ts.AssertTransactionsInCacheRejected(wallet.Transactions("tx1"), true, node1, node2) } } @@ -124,8 +124,7 @@ func Test_MultipleAttachments(t *testing.T) { nodeA := ts.AddValidatorNode("nodeA") nodeB := ts.AddValidatorNode("nodeB") - blockIssuerA := ts.AddBasicBlockIssuer("blockIssuerA") - blockIssuerB := ts.AddBasicBlockIssuer("blockIssuerB") + wallet := ts.AddGenesisWallet("default", nodeA) ts.Run(true, map[string][]options.Option[protocol.Protocol]{}) @@ -133,11 +132,12 @@ func Test_MultipleAttachments(t *testing.T) { // Create a transaction and issue it from both nodes, so that the conflict is accepted, but no attachment is included yet. { - tx1 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx1", 2, "Genesis:0")) + tx1 := wallet.CreateBasicOutputsEquallyFromInputs("tx1", 2, "Genesis:0") - ts.IssuePayloadWithOptions("A.1", blockIssuerA, nodeA, tx1, mock.WithStrongParents(ts.BlockID("Genesis"))) + ts.IssuePayloadWithOptions("A.1", wallet, tx1, mock.WithStrongParents(ts.BlockID("Genesis"))) ts.IssueValidationBlock("A.1.1", nodeA, mock.WithStrongParents(ts.BlockID("A.1"))) - ts.IssuePayloadWithOptions("B.1", blockIssuerB, nodeB, tx1, mock.WithStrongParents(ts.BlockID("Genesis"))) + wallet.SetDefaultNode(nodeB) + ts.IssuePayloadWithOptions("B.1", wallet, tx1, mock.WithStrongParents(ts.BlockID("Genesis"))) ts.IssueValidationBlock("B.1.1", nodeB, mock.WithStrongParents(ts.BlockID("B.1"))) ts.IssueValidationBlock("A.2", nodeA, mock.WithStrongParents(ts.BlockID("B.1.1"))) @@ -153,17 +153,19 @@ func Test_MultipleAttachments(t *testing.T) { ts.Block("B.2"): {"tx1"}, }), ts.Nodes()...) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ - ts.TransactionFramework.Transaction("tx1"): {"tx1"}, + wallet.Transaction("tx1"): {"tx1"}, }, ts.Nodes()...) ts.AssertConflictsInCacheAcceptanceState([]string{"tx1"}, acceptance.Accepted, ts.Nodes()...) } // Create a transaction that is included and whose conflict is accepted, but whose inputs are not accepted. { - tx2 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx2", 1, "tx1:1")) + tx2 := wallet.CreateBasicOutputsEquallyFromInputs("tx2", 1, "tx1:1") - ts.IssuePayloadWithOptions("A.3", nodeA.Validator, nodeA, tx2, mock.WithStrongParents(ts.BlockID("Genesis"))) - ts.IssueValidationBlock("B.3", nodeB, mock.WithStrongParents(ts.BlockID("A.3"))) + wallet.SetDefaultNode(nodeA) + ts.IssuePayloadWithOptions("A.3", wallet, tx2, mock.WithStrongParents(ts.BlockID("Genesis"))) + ts.IssueValidationBlock("A.3.1", nodeA, mock.WithStrongParents(ts.BlockID("A.3"))) + ts.IssueValidationBlock("B.3", nodeB, mock.WithStrongParents(ts.BlockID("A.3.1"))) ts.IssueValidationBlock("A.4", nodeA, mock.WithStrongParents(ts.BlockID("B.3"))) ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.3"), true, ts.Nodes()...) @@ -175,8 +177,8 @@ func Test_MultipleAttachments(t *testing.T) { ts.AssertBlocksInCachePreAccepted(ts.Blocks("B.4", "A.5"), false, ts.Nodes()...) ts.AssertBlocksInCacheAccepted(ts.Blocks("A.3"), true, ts.Nodes()...) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx1", "tx2"), true, ts.Nodes()...) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, ts.Nodes()...) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, ts.Nodes()...) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, ts.Nodes()...) ts.AssertBlocksInCacheConflicts(lo.MergeMaps(blocksConflicts, map[*blocks.Block][]string{ ts.Block("A.3"): {"tx2"}, @@ -186,8 +188,8 @@ func Test_MultipleAttachments(t *testing.T) { ts.Block("B.4"): {}, }), ts.Nodes()...) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ - ts.TransactionFramework.Transaction("tx1"): {"tx1"}, - ts.TransactionFramework.Transaction("tx2"): {"tx2"}, + wallet.Transaction("tx1"): {"tx1"}, + wallet.Transaction("tx2"): {"tx2"}, }, nodeA, nodeB) ts.AssertConflictsInCacheAcceptanceState([]string{"tx1", "tx2"}, acceptance.Accepted, ts.Nodes()...) } @@ -204,9 +206,9 @@ func Test_MultipleAttachments(t *testing.T) { ts.AssertBlocksInCacheAccepted(ts.Blocks("A.1", "B.1"), true, ts.Nodes()...) ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.7", "B.6"), false, ts.Nodes()...) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2"), true, ts.Nodes()...) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx1", "tx2"), true, ts.Nodes()...) - ts.AssertTransactionsInCacheAccepted(ts.TransactionFramework.Transactions("tx1", "tx2"), true, ts.Nodes()...) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), true, ts.Nodes()...) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, ts.Nodes()...) + ts.AssertTransactionsInCacheAccepted(wallet.Transactions("tx1", "tx2"), true, ts.Nodes()...) ts.AssertBlocksInCacheConflicts(lo.MergeMaps(blocksConflicts, map[*blocks.Block][]string{ ts.Block("A.6"): {}, @@ -216,8 +218,8 @@ func Test_MultipleAttachments(t *testing.T) { }), ts.Nodes()...) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ - ts.TransactionFramework.Transaction("tx1"): {"tx1"}, - ts.TransactionFramework.Transaction("tx2"): {"tx2"}, + wallet.Transaction("tx1"): {"tx1"}, + wallet.Transaction("tx2"): {"tx2"}, }, nodeA, nodeB) ts.AssertConflictsInCacheAcceptanceState([]string{"tx1", "tx2"}, acceptance.Accepted, nodeA, nodeB) } @@ -244,7 +246,7 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { node1 := ts.AddValidatorNode("node1") node2 := ts.AddValidatorNode("node2") - ts.AddBasicBlockIssuer("default") + wallet := ts.AddGenesisWallet("default", node1) ts.Run(true, map[string][]options.Option[protocol.Protocol]{}) @@ -257,16 +259,17 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { // Create and issue double spends { - tx1 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx1", 1, "Genesis:0")) - tx2 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx2", 1, "Genesis:0")) + tx1 := wallet.CreateBasicOutputsEquallyFromInputs("tx1", 1, "Genesis:0") + tx2 := wallet.CreateBasicOutputsEquallyFromInputs("tx2", 1, "Genesis:0") - ts.IssueBasicBlockAtSlotWithOptions("block1.1", 1, genesisCommitment, ts.DefaultBasicBlockIssuer(), node1, tx1) - ts.IssueBasicBlockAtSlotWithOptions("block1.2", 1, genesisCommitment, ts.DefaultBasicBlockIssuer(), node1, tx2) + wallet.SetDefaultNode(node1) + ts.IssueBasicBlockAtSlotWithOptions("block1.1", 1, wallet, tx1, mock.WithSlotCommitment(genesisCommitment)) + ts.IssueBasicBlockAtSlotWithOptions("block1.2", 1, wallet, tx2, mock.WithSlotCommitment(genesisCommitment)) ts.IssueValidationBlockAtSlot("block2.tx1", 2, genesisCommitment, node1, ts.BlockIDs("block1.1")...) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block1.1"): {"tx1"}, ts.Block("block1.2"): {"tx2"}, @@ -274,8 +277,8 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { }, node1, node2) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ - ts.TransactionFramework.Transaction("tx2"): {"tx2"}, - ts.TransactionFramework.Transaction("tx1"): {"tx1"}, + wallet.Transaction("tx2"): {"tx2"}, + wallet.Transaction("tx1"): {"tx1"}, }, node1, node2) } @@ -289,7 +292,7 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { ts.Block("block2.2"): {"tx2"}, ts.Block("block2.tx1"): {"tx1"}, }, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) } // Issue valid blocks that resolve the conflict. @@ -301,8 +304,8 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { ts.Block("block2.3"): {"tx2"}, ts.Block("block2.tx1"): {"tx1"}, }, node1, node2) - ts.AssertTransactionsInCacheAccepted(ts.TransactionFramework.Transactions("tx2"), true, node1, node2) - ts.AssertTransactionsInCacheRejected(ts.TransactionFramework.Transactions("tx1"), true, node1, node2) + ts.AssertTransactionsInCacheAccepted(wallet.Transactions("tx2"), true, node1, node2) + ts.AssertTransactionsInCacheRejected(wallet.Transactions("tx1"), true, node1, node2) } // Advance both nodes at the edge of slot 1 committability @@ -361,20 +364,21 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { commitment1 := lo.PanicOnErr(node2.Protocol.MainEngineInstance().Storage.Commitments().Load(1)).Commitment() // This should be booked on the rejected tx1 conflict - tx4 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx4", 1, "tx1:0")) + tx4 := wallet.CreateBasicOutputsEquallyFromInputs("tx4", 1, "tx1:0") // Issue TX3 on top of rejected TX1 and 1 commitment on node2 (committed to slot 1) { - ts.IssueBasicBlockAtSlotWithOptions("n2-commit1", 5, commitment1, ts.DefaultBasicBlockIssuer(), node2, tx4) + wallet.SetDefaultNode(node2) + ts.IssueBasicBlockAtSlotWithOptions("n2-commit1", 5, wallet, tx4, mock.WithSlotCommitment(commitment1)) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("n2-commit1"): {}, // no conflits inherited as the block is invalid and doesn't get booked. ts.Block("block2.tx1"): {"tx1"}, }, node2) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1"), true, node2) - ts.AssertTransactionsInCacheRejected(ts.TransactionFramework.Transactions("tx4"), true, node2) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx4"), true, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1"), true, node2) + ts.AssertTransactionsInCacheRejected(wallet.Transactions("tx4"), true, node2) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx4"), true, node2) // As the block commits to 1 but spending something orphaned in 1 it should be invalid ts.AssertBlocksInCacheBooked(ts.Blocks("n2-commit1"), false, node2) @@ -388,7 +392,7 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { ts.AssertBlocksInCacheBooked(ts.Blocks("n1-rejected-genesis"), true, node1) ts.AssertBlocksInCacheInvalid(ts.Blocks("n1-rejected-genesis"), false, node1) - ts.AssertTransactionsInCacheRejected(ts.TransactionFramework.Transactions("tx1"), true, node2) + ts.AssertTransactionsInCacheRejected(wallet.Transactions("tx1"), true, node2) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block2.tx1"): {"tx1"}, @@ -398,7 +402,8 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { // Issue TX4 on top of rejected TX1 but Genesis commitment on node2 (committed to slot 1) { - ts.IssueBasicBlockAtSlotWithOptions("n2-genesis", 5, genesisCommitment, ts.DefaultBasicBlockIssuer(), node2, tx4, mock.WithStrongParents(ts.BlockID("Genesis"))) + wallet.SetDefaultNode(node2) + ts.IssueBasicBlockAtSlotWithOptions("n2-genesis", 5, wallet, tx4, mock.WithStrongParents(ts.BlockID("Genesis")), mock.WithSlotCommitment(genesisCommitment)) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("n2-genesis"): {"tx4"}, // on rejected conflict @@ -410,11 +415,12 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { // Issue TX4 on top of rejected TX1 but Genesis commitment on node1 (committed to slot 0) { - ts.IssueBasicBlockAtSlotWithOptions("n1-genesis", 5, genesisCommitment, ts.DefaultBasicBlockIssuer(), node1, tx4, mock.WithStrongParents(ts.BlockID("Genesis"))) + wallet.SetDefaultNode(node1) + ts.IssueBasicBlockAtSlotWithOptions("n1-genesis", 5, wallet, tx4, mock.WithStrongParents(ts.BlockID("Genesis")), mock.WithSlotCommitment(genesisCommitment)) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1"), true, node2) - ts.AssertTransactionsInCacheRejected(ts.TransactionFramework.Transactions("tx4"), true, node2) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx4"), true, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1"), true, node2) + ts.AssertTransactionsInCacheRejected(wallet.Transactions("tx4"), true, node2) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx4"), true, node2) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("n1-genesis"): {"tx4"}, // on rejected conflict @@ -439,14 +445,16 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { ) // Exchange each-other blocks, ignoring invalidity - ts.IssueExistingBlock("n2-genesis", ts.DefaultBasicBlockIssuer(), node1) - ts.IssueExistingBlock("n2-commit1", ts.DefaultBasicBlockIssuer(), node1) - ts.IssueExistingBlock("n1-genesis", ts.DefaultBasicBlockIssuer(), node2) - ts.IssueExistingBlock("n1-rejected-genesis", ts.DefaultBasicBlockIssuer(), node2) + wallet.SetDefaultNode(node1) + ts.IssueExistingBlock("n2-genesis", wallet) + ts.IssueExistingBlock("n2-commit1", wallet) + wallet.SetDefaultNode(node2) + ts.IssueExistingBlock("n1-genesis", wallet) + ts.IssueExistingBlock("n1-rejected-genesis", wallet) ts.IssueValidationBlockAtSlot("n1-rejected-commit1", 5, commitment1, node1, ts.BlockIDs("n1-rejected-genesis")...) // Needs reissuing on node2 because it is invalid - ts.IssueExistingBlock("n1-rejected-commit1", ts.DefaultBasicBlockIssuer(), node2) + ts.IssueExistingBlock("n1-rejected-commit1", wallet) // The nodes agree on the results of the invalid blocks ts.AssertBlocksInCacheBooked(ts.Blocks("n2-genesis", "n1-genesis", "n1-rejected-genesis"), true, node1, node2) @@ -471,7 +479,7 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { // Commit further and test eviction of transactions { - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2", "tx4"), true, node1, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2", "tx4"), true, node1, node2) ts.IssueBlocksAtSlots("", []iotago.SlotIndex{6, 7, 8, 9, 10}, 5, "5.1", ts.Nodes("node1", "node2"), false, nil) @@ -482,7 +490,7 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { testsuite.WithEvictedSlot(8), ) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2", "tx4"), false, node1, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2", "tx4"), false, node1, node2) } } @@ -507,7 +515,7 @@ func Test_SpendPendingCommittedRace(t *testing.T) { node1 := ts.AddValidatorNode("node1") node2 := ts.AddValidatorNode("node2") - ts.AddBasicBlockIssuer("default") + wallet := ts.AddGenesisWallet("default", node1) ts.Run(true, map[string][]options.Option[protocol.Protocol]{}) @@ -520,23 +528,24 @@ func Test_SpendPendingCommittedRace(t *testing.T) { // Create and issue double spends { - tx1 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx1", 1, "Genesis:0")) - tx2 := lo.PanicOnErr(ts.TransactionFramework.CreateSimpleTransaction("tx2", 1, "Genesis:0")) + tx1 := wallet.CreateBasicOutputsEquallyFromInputs("tx1", 1, "Genesis:0") + tx2 := wallet.CreateBasicOutputsEquallyFromInputs("tx2", 1, "Genesis:0") - ts.IssueBasicBlockAtSlotWithOptions("block1.1", 1, genesisCommitment, ts.DefaultBasicBlockIssuer(), node2, tx1) - ts.IssueBasicBlockAtSlotWithOptions("block1.2", 1, genesisCommitment, ts.DefaultBasicBlockIssuer(), node2, tx2) + wallet.SetDefaultNode(node2) + ts.IssueBasicBlockAtSlotWithOptions("block1.1", 1, wallet, tx1) + ts.IssueBasicBlockAtSlotWithOptions("block1.2", 1, wallet, tx2) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) - ts.AssertTransactionsInCacheBooked(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block1.1"): {"tx1"}, ts.Block("block1.2"): {"tx2"}, }, node1, node2) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ - ts.TransactionFramework.Transaction("tx2"): {"tx2"}, - ts.TransactionFramework.Transaction("tx1"): {"tx1"}, + wallet.Transaction("tx2"): {"tx2"}, + wallet.Transaction("tx1"): {"tx1"}, }, node1, node2) } @@ -549,7 +558,7 @@ func Test_SpendPendingCommittedRace(t *testing.T) { ts.Block("block2.1"): {"tx1"}, ts.Block("block2.2"): {"tx2"}, }, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) } // Advance both nodes at the edge of slot 1 committability @@ -604,8 +613,8 @@ func Test_SpendPendingCommittedRace(t *testing.T) { ts.IssueValidationBlockAtSlot("n2-pending-genesis", 5, genesisCommitment, node2, ts.BlockIDs("block2.1")...) ts.IssueValidationBlockAtSlot("n2-pending-commit1", 5, commitment1, node2, ts.BlockIDs("block2.1")...) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1"), true, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1"), true, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1"), true, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1"), true, node2) ts.AssertBlocksInCacheBooked(ts.Blocks("n2-pending-genesis", "n2-pending-commit1"), true, node2) ts.AssertBlocksInCacheInvalid(ts.Blocks("n2-pending-genesis", "n2-pending-commit1"), false, node2) @@ -632,8 +641,9 @@ func Test_SpendPendingCommittedRace(t *testing.T) { ) // Exchange each-other blocks, ignoring invalidity - ts.IssueExistingBlock("n2-pending-genesis", ts.DefaultBasicBlockIssuer(), node1) - ts.IssueExistingBlock("n2-pending-commit1", ts.DefaultBasicBlockIssuer(), node1) + wallet.SetDefaultNode(node1) + ts.IssueExistingBlock("n2-pending-genesis", wallet) + ts.IssueExistingBlock("n2-pending-commit1", wallet) // The nodes agree on the results of the invalid blocks ts.AssertBlocksInCacheBooked(ts.Blocks("n2-pending-genesis", "n2-pending-commit1"), true, node1, node2) @@ -645,13 +655,13 @@ func Test_SpendPendingCommittedRace(t *testing.T) { ts.Block("n2-pending-commit1"): {}, // no conflits inherited as the block merges orphaned conflicts. }, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) } // Commit further and test eviction of transactions { - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) - ts.AssertTransactionsInCachePending(ts.TransactionFramework.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) ts.IssueBlocksAtSlots("", []iotago.SlotIndex{6, 7, 8, 9, 10}, 5, "5.1", ts.Nodes("node1", "node2"), false, nil) @@ -662,6 +672,6 @@ func Test_SpendPendingCommittedRace(t *testing.T) { testsuite.WithEvictedSlot(8), ) - ts.AssertTransactionsExist(ts.TransactionFramework.Transactions("tx1", "tx2"), false, node1, node2) + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), false, node1, node2) } } diff --git a/pkg/tests/committee_rotation_test.go b/pkg/tests/committee_rotation_test.go index 56b4f397d..375a3c98f 100644 --- a/pkg/tests/committee_rotation_test.go +++ b/pkg/tests/committee_rotation_test.go @@ -5,10 +5,10 @@ import ( "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/protocol" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/seatmanager/topstakers" "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/sybilprotectionv1" "github.com/iotaledger/iota-core/pkg/testsuite" + "github.com/iotaledger/iota-core/pkg/testsuite/snapshotcreator" iotago "github.com/iotaledger/iota.go/v4" ) @@ -38,12 +38,13 @@ func Test_TopStakersRotation(t *testing.T) { ) defer ts.Shutdown() - ts.AddValidatorNode("node1", 1_000_006) + node1 := ts.AddValidatorNode("node1", 1_000_006) ts.AddValidatorNode("node2", 1_000_005) ts.AddValidatorNode("node3", 1_000_004) ts.AddValidatorNode("node4", 1_000_003) ts.AddValidatorNode("node5", 1_000_002) ts.AddValidatorNode("node6", 1_000_001) + ts.AddGenesisWallet("default", node1) nodeOptions := make(map[string][]options.Option[protocol.Protocol]) @@ -77,24 +78,24 @@ func Test_TopStakersRotation(t *testing.T) { ts.IssueBlocksAtSlots("wave-1:", []iotago.SlotIndex{1, 2, 3, 4}, 4, "Genesis", ts.Nodes(), true, nil) - ts.IssueCandidacyAnnouncementInSlot("node1-candidacy:1", 4, "wave-1:4.3", ts.Node("node1")) - ts.IssueCandidacyAnnouncementInSlot("node4-candidacy:1", 5, "node1-candidacy:1", ts.Node("node4")) + ts.IssueCandidacyAnnouncementInSlot("node1-candidacy:1", 4, "wave-1:4.3", ts.Wallet("node1")) + ts.IssueCandidacyAnnouncementInSlot("node4-candidacy:1", 5, "node1-candidacy:1", ts.Wallet("node4")) ts.IssueBlocksAtSlots("wave-2:", []iotago.SlotIndex{5, 6, 7, 8, 9}, 4, "node4-candidacy:1", ts.Nodes(), true, nil) - ts.IssueCandidacyAnnouncementInSlot("node4-candidacy:2", 9, "wave-2:9.3", ts.Node("node4")) - ts.IssueCandidacyAnnouncementInSlot("node5-candidacy:1", 9, "node4-candidacy:2", ts.Node("node5")) + ts.IssueCandidacyAnnouncementInSlot("node4-candidacy:2", 9, "wave-2:9.3", ts.Wallet("node4")) + ts.IssueCandidacyAnnouncementInSlot("node5-candidacy:1", 9, "node4-candidacy:2", ts.Wallet("node5")) // This candidacy should be considered as it's announced at the last possible slot. - ts.IssueCandidacyAnnouncementInSlot("node6-candidacy:1", 10, "node5-candidacy:1", ts.Node("node6")) + ts.IssueCandidacyAnnouncementInSlot("node6-candidacy:1", 10, "node5-candidacy:1", ts.Wallet("node6")) ts.IssueBlocksAtSlots("wave-3:", []iotago.SlotIndex{10}, 4, "node6-candidacy:1", ts.Nodes(), true, nil) // Those candidacies should not be considered as they're issued after EpochNearingThreshold (slot 10). - ts.IssueCandidacyAnnouncementInSlot("node2-candidacy:1", 11, "wave-3:10.3", ts.Node("node2")) - ts.IssueCandidacyAnnouncementInSlot("node3-candidacy:1", 11, "node2-candidacy:1", ts.Node("node3")) - ts.IssueCandidacyAnnouncementInSlot("node4-candidacy:3", 11, "node3-candidacy:1", ts.Node("node3")) - ts.IssueCandidacyAnnouncementInSlot("node5-candidacy:2", 11, "node4-candidacy:3", ts.Node("node3")) + ts.IssueCandidacyAnnouncementInSlot("node2-candidacy:1", 11, "wave-3:10.3", ts.Wallet("node2")) + ts.IssueCandidacyAnnouncementInSlot("node3-candidacy:1", 11, "node2-candidacy:1", ts.Wallet("node3")) + ts.IssueCandidacyAnnouncementInSlot("node4-candidacy:3", 11, "node3-candidacy:1", ts.Wallet("node3")) + ts.IssueCandidacyAnnouncementInSlot("node5-candidacy:2", 11, "node4-candidacy:3", ts.Wallet("node3")) // Assert that only candidates that issued before slot 11 are considered. ts.AssertSybilProtectionCandidates(1, []iotago.AccountID{ diff --git a/pkg/tests/loss_of_acceptance_test.go b/pkg/tests/loss_of_acceptance_test.go index ed26be402..a8bb02537 100644 --- a/pkg/tests/loss_of_acceptance_test.go +++ b/pkg/tests/loss_of_acceptance_test.go @@ -32,8 +32,8 @@ func TestLossOfAcceptanceFromGenesis(t *testing.T) { ) defer ts.Shutdown() - ts.AddBasicBlockIssuer("default") node0 := ts.AddValidatorNode("node0") + ts.AddGenesisWallet("default", node0) ts.AddValidatorNode("node1") ts.AddNode("node2") @@ -117,8 +117,8 @@ func TestLossOfAcceptanceFromSnapshot(t *testing.T) { ) defer ts.Shutdown() - ts.AddBasicBlockIssuer("default") node0 := ts.AddValidatorNode("node0") + ts.AddGenesisWallet("default", node0) ts.AddValidatorNode("node1") node2 := ts.AddNode("node2") @@ -211,8 +211,8 @@ func TestLossOfAcceptanceWithRestartFromDisk(t *testing.T) { ) defer ts.Shutdown() - ts.AddBasicBlockIssuer("default") node0 := ts.AddValidatorNode("node0") + ts.AddGenesisWallet("default", node0) ts.AddValidatorNode("node1") node2 := ts.AddNode("node2") diff --git a/pkg/tests/protocol_engine_switching_test.go b/pkg/tests/protocol_engine_switching_test.go index b0c262f19..aa6bf7834 100644 --- a/pkg/tests/protocol_engine_switching_test.go +++ b/pkg/tests/protocol_engine_switching_test.go @@ -56,7 +56,7 @@ func TestProtocol_EngineSwitching(t *testing.T) { node6 := ts.AddValidatorNode("node6") node7 := ts.AddValidatorNode("node7") node8 := ts.AddNode("node8") - ts.AddBasicBlockIssuer("default", iotago.MaxBlockIssuanceCredits/2) + ts.AddGenesisWallet("default", node0, iotago.MaxBlockIssuanceCredits/2) const expectedCommittedSlotAfterPartitionMerge = 19 nodesP1 := []*mock.Node{node0, node1, node2, node3, node4, node5} diff --git a/pkg/tests/protocol_startup_test.go b/pkg/tests/protocol_startup_test.go index 20e957be5..11b6672d1 100644 --- a/pkg/tests/protocol_startup_test.go +++ b/pkg/tests/protocol_startup_test.go @@ -141,7 +141,7 @@ func Test_StartNodeFromSnapshotAndDisk(t *testing.T) { nodeA := ts.AddValidatorNode("nodeA") nodeB := ts.AddValidatorNode("nodeB") ts.AddNode("nodeC") - ts.AddBasicBlockIssuer("default", iotago.MaxBlockIssuanceCredits/2) + ts.AddGenesisWallet("default", nodeA, iotago.MaxBlockIssuanceCredits/2) nodeOptions := []options.Option[protocol.Protocol]{ protocol.WithStorageOptions( diff --git a/pkg/tests/upgrade_signaling_test.go b/pkg/tests/upgrade_signaling_test.go index b5ce6336b..8f5ed29f3 100644 --- a/pkg/tests/upgrade_signaling_test.go +++ b/pkg/tests/upgrade_signaling_test.go @@ -22,6 +22,7 @@ import ( "github.com/iotaledger/iota-core/pkg/storage" "github.com/iotaledger/iota-core/pkg/storage/permanent" "github.com/iotaledger/iota-core/pkg/testsuite" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/api" ) @@ -107,13 +108,13 @@ func Test_Upgrade_Signaling(t *testing.T) { ), ) - ts.AddValidatorNode("nodeA") + nodeA := ts.AddValidatorNode("nodeA") ts.AddValidatorNode("nodeB") ts.AddValidatorNode("nodeC") ts.AddValidatorNode("nodeD") ts.AddNode("nodeE") ts.AddNode("nodeF") - ts.AddBasicBlockIssuer("default", iotago.MaxBlockIssuanceCredits/2) + wallet := ts.AddGenesisWallet("default", nodeA, iotago.MaxBlockIssuanceCredits/2) ts.Run(true, map[string][]options.Option[protocol.Protocol]{ "nodeA": nodeOptionsWithoutV5, @@ -135,7 +136,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), - ValidatorStake: testsuite.MinValidatorAccountAmount, + ValidatorStake: mock.MinValidatorAccountAmount, DelegationStake: 0, FixedCost: 0, StakeEndEpoch: iotago.MaxEpochIndex, @@ -143,11 +144,11 @@ func Test_Upgrade_Signaling(t *testing.T) { }, ts.Nodes()...) ts.AssertAccountData(&accounts.AccountData{ - ID: ts.DefaultBasicBlockIssuer().AccountID, + ID: wallet.BlockIssuer.AccountID, Credits: &accounts.BlockIssuanceCredits{Value: iotago.MaxBlockIssuanceCredits / 2, UpdateTime: 0}, ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:5").OutputID(), - BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.DefaultBasicBlockIssuer().PublicKey))), + BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(wallet.BlockIssuer.PublicKey))), ValidatorStake: 0, DelegationStake: 0, FixedCost: 0, @@ -169,7 +170,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), - ValidatorStake: testsuite.MinValidatorAccountAmount, + ValidatorStake: mock.MinValidatorAccountAmount, DelegationStake: 0, FixedCost: 0, StakeEndEpoch: iotago.MaxEpochIndex, @@ -182,7 +183,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:4").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeD").Validator.PublicKey))), - ValidatorStake: testsuite.MinValidatorAccountAmount, + ValidatorStake: mock.MinValidatorAccountAmount, DelegationStake: 0, FixedCost: 0, StakeEndEpoch: iotago.MaxEpochIndex, @@ -203,7 +204,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), - ValidatorStake: testsuite.MinValidatorAccountAmount, + ValidatorStake: mock.MinValidatorAccountAmount, DelegationStake: 0, FixedCost: 0, StakeEndEpoch: iotago.MaxEpochIndex, @@ -368,7 +369,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:1").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeA").Validator.PublicKey))), - ValidatorStake: testsuite.MinValidatorAccountAmount, + ValidatorStake: mock.MinValidatorAccountAmount, DelegationStake: 0, FixedCost: 0, StakeEndEpoch: iotago.MaxEpochIndex, @@ -381,7 +382,7 @@ func Test_Upgrade_Signaling(t *testing.T) { ExpirySlot: iotago.MaxSlotIndex, OutputID: ts.AccountOutput("Genesis:4").OutputID(), BlockIssuerKeys: iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(ts.Node("nodeD").Validator.PublicKey))), - ValidatorStake: testsuite.MinValidatorAccountAmount, + ValidatorStake: mock.MinValidatorAccountAmount, DelegationStake: 0, FixedCost: 0, StakeEndEpoch: iotago.MaxEpochIndex, diff --git a/pkg/testsuite/blocks.go b/pkg/testsuite/blocks.go index cf6c89cc5..90e5c70ac 100644 --- a/pkg/testsuite/blocks.go +++ b/pkg/testsuite/blocks.go @@ -130,7 +130,7 @@ func (t *TestSuite) AssertBlocksInCacheConflicts(blockConflicts map[*blocks.Bloc return ierrors.Errorf("AssertBlocksInCacheConflicts: %s: block %s is root block", node.Name, blockFromCache.ID()) } - expectedConflictIDs := ds.NewSet(lo.Map(conflictAliases, t.TransactionFramework.TransactionID)...) + expectedConflictIDs := ds.NewSet(lo.Map(conflictAliases, t.DefaultWallet().TransactionID)...) actualConflictIDs := blockFromCache.ConflictIDs() if expectedConflictIDs.Size() != actualConflictIDs.Size() { diff --git a/pkg/testsuite/conflicts.go b/pkg/testsuite/conflicts.go index 7c7047da0..b1fa92989 100644 --- a/pkg/testsuite/conflicts.go +++ b/pkg/testsuite/conflicts.go @@ -13,7 +13,7 @@ func (t *TestSuite) AssertConflictsInCacheAcceptanceState(expectedConflictAliase for _, node := range nodes { for _, conflictAlias := range expectedConflictAliases { t.Eventually(func() error { - acceptanceState := node.Protocol.MainEngineInstance().Ledger.ConflictDAG().AcceptanceState(ds.NewSet(t.TransactionFramework.TransactionID(conflictAlias))) + acceptanceState := node.Protocol.MainEngineInstance().Ledger.ConflictDAG().AcceptanceState(ds.NewSet(t.DefaultWallet().TransactionID(conflictAlias))) if acceptanceState != expectedState { return ierrors.Errorf("assertTransactionsInCacheWithFunc: %s: conflict %s is %s, but expected %s", node.Name, conflictAlias, acceptanceState, expectedState) diff --git a/pkg/testsuite/mock/blockissuer.go b/pkg/testsuite/mock/blockissuer.go index 527bcff19..1e6fad7fa 100644 --- a/pkg/testsuite/mock/blockissuer.go +++ b/pkg/testsuite/mock/blockissuer.go @@ -12,6 +12,7 @@ import ( "golang.org/x/crypto/blake2b" "github.com/iotaledger/hive.go/core/safemath" + hiveEd25519 "github.com/iotaledger/hive.go/crypto/ed25519" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/event" @@ -45,14 +46,15 @@ type BlockIssuer struct { Name string Validator bool + AccountID iotago.AccountID + OutputID iotago.OutputID + PublicKey ed25519.PublicKey + privateKey ed25519.PrivateKey + events *Events workerPool *workerpool.WorkerPool - privateKey ed25519.PrivateKey - PublicKey ed25519.PublicKey - AccountID iotago.AccountID - optsTipSelectionTimeout time.Duration optsTipSelectionRetryInterval time.Duration // optsIncompleteBlockAccepted defines whether the node allows filling in incomplete block and issuing it for user. @@ -60,13 +62,12 @@ type BlockIssuer struct { optsRateSetterEnabled bool } -func NewBlockIssuer(t *testing.T, name string, validator bool, opts ...options.Option[BlockIssuer]) *BlockIssuer { - pub, priv, err := ed25519.GenerateKey(nil) - if err != nil { - panic(err) - } +func NewBlockIssuer(t *testing.T, name string, keyManager *KeyManager, accountID iotago.AccountID, validator bool, opts ...options.Option[BlockIssuer]) *BlockIssuer { + priv, pub := keyManager.KeyPair() - accountID := iotago.AccountID(blake2b.Sum256(pub)) + if accountID == iotago.EmptyAccountID { + accountID = iotago.AccountID(blake2b.Sum256(pub)) + } accountID.RegisterAlias(name) return options.Apply(&BlockIssuer{ @@ -85,6 +86,10 @@ func NewBlockIssuer(t *testing.T, name string, validator bool, opts ...options.O }, opts) } +func (i *BlockIssuer) BlockIssuerKeys() iotago.BlockIssuerKeys { + return iotago.NewBlockIssuerKeys(iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(hiveEd25519.PublicKey(i.PublicKey))) +} + // Shutdown shuts down the block issuer. func (i *BlockIssuer) Shutdown() { i.workerPool.Shutdown() @@ -188,7 +193,7 @@ func (i *BlockIssuer) IssueValidationBlock(ctx context.Context, alias string, no validationBlock, _ := block.ValidationBlock() - fmt.Printf("Issued ValidationBlock: %s - slot %d - commitment %s %d - latest finalized slot %d - version: %d - highestSupportedVersion: %d, hash: %s\n", block.ID(), block.ID().Slot(), block.SlotCommitmentID(), block.SlotCommitmentID().Slot(), block.ProtocolBlock().LatestFinalizedSlot, block.ProtocolBlock().ProtocolVersion, validationBlock.HighestSupportedVersion, validationBlock.ProtocolParametersHash) + fmt.Printf("Issued ValidationBlock: %s - slot %d - commitment %s %d - latest finalized slot %d - version: %d - highestSupportedVersion: %d, hash: %s\n", block.ID(), block.ID().Slot(), block.SlotCommitmentID(), block.SlotCommitmentID().Slot(), block.ProtocolBlock().Header.LatestFinalizedSlot, block.ProtocolBlock().Header.ProtocolVersion, validationBlock.HighestSupportedVersion, validationBlock.ProtocolParametersHash) return block } @@ -283,7 +288,7 @@ func (i *BlockIssuer) IssueBasicBlock(ctx context.Context, alias string, node *N require.NoErrorf(i.Testing, i.IssueBlock(block.ModelBlock(), node), "%s > failed to issue block with alias %s", i.Name, alias) - fmt.Printf("%s > Issued block: %s - slot %d - commitment %s %d - latest finalized slot %d\n", i.Name, block.ID(), block.ID().Slot(), block.SlotCommitmentID(), block.SlotCommitmentID().Slot(), block.ProtocolBlock().LatestFinalizedSlot) + fmt.Printf("%s > Issued block: %s - slot %d - commitment %s %d - latest finalized slot %d\n", i.Name, block.ID(), block.ID().Slot(), block.SlotCommitmentID(), block.SlotCommitmentID().Slot(), block.ProtocolBlock().Header.LatestFinalizedSlot) return block } @@ -361,30 +366,30 @@ func (i *BlockIssuer) IssueBlockAndAwaitEvent(ctx context.Context, block *model. } } -func (i *BlockIssuer) AttachBlock(ctx context.Context, iotaBlock *iotago.ProtocolBlock, node *Node, optIssuerAccount ...Account) (iotago.BlockID, error) { +func (i *BlockIssuer) AttachBlock(ctx context.Context, iotaBlock *iotago.Block, node *Node, optIssuerAccount ...Account) (iotago.BlockID, error) { // if anything changes, need to make a new signature var resign bool - apiForVersion, err := node.Protocol.APIForVersion(iotaBlock.ProtocolVersion) + apiForVersion, err := node.Protocol.APIForVersion(iotaBlock.Header.ProtocolVersion) if err != nil { - return iotago.EmptyBlockID, ierrors.Wrapf(ErrBlockAttacherInvalidBlock, "protocolVersion invalid: %d", iotaBlock.ProtocolVersion) + return iotago.EmptyBlockID, ierrors.Wrapf(ErrBlockAttacherInvalidBlock, "protocolVersion invalid: %d", iotaBlock.Header.ProtocolVersion) } protoParams := apiForVersion.ProtocolParameters() - if iotaBlock.NetworkID == 0 { - iotaBlock.NetworkID = protoParams.NetworkID() + if iotaBlock.Header.NetworkID == 0 { + iotaBlock.Header.NetworkID = protoParams.NetworkID() resign = true } - if iotaBlock.SlotCommitmentID == iotago.EmptyCommitmentID { - iotaBlock.SlotCommitmentID = node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID() - iotaBlock.LatestFinalizedSlot = node.Protocol.MainEngineInstance().Storage.Settings().LatestFinalizedSlot() + if iotaBlock.Header.SlotCommitmentID == iotago.EmptyCommitmentID { + iotaBlock.Header.SlotCommitmentID = node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID() + iotaBlock.Header.LatestFinalizedSlot = node.Protocol.MainEngineInstance().Storage.Settings().LatestFinalizedSlot() resign = true } - switch innerBlock := iotaBlock.Block.(type) { - case *iotago.BasicBlock: + switch innerBlock := iotaBlock.Body.(type) { + case *iotago.BasicBlockBody: switch payload := innerBlock.Payload.(type) { case *iotago.SignedTransaction: if payload.Transaction.NetworkID != protoParams.NetworkID() { @@ -404,7 +409,7 @@ func (i *BlockIssuer) AttachBlock(ctx context.Context, iotaBlock *iotago.Protoco resign = true } - case *iotago.ValidationBlock: + case *iotago.ValidationBlockBody: //nolint:revive,staticcheck //temporarily disable if len(iotaBlock.Parents()) == 0 { // TODO: implement tipselection for validator blocks @@ -412,20 +417,20 @@ func (i *BlockIssuer) AttachBlock(ctx context.Context, iotaBlock *iotago.Protoco } references := make(model.ParentReferences) - references[iotago.StrongParentType] = iotaBlock.Block.StrongParentIDs().RemoveDupsAndSort() - references[iotago.WeakParentType] = iotaBlock.Block.WeakParentIDs().RemoveDupsAndSort() - references[iotago.ShallowLikeParentType] = iotaBlock.Block.ShallowLikeParentIDs().RemoveDupsAndSort() - if iotaBlock.IssuingTime.Equal(time.Unix(0, 0)) { - iotaBlock.IssuingTime = time.Now().UTC() + references[iotago.StrongParentType] = iotaBlock.Body.StrongParentIDs().RemoveDupsAndSort() + references[iotago.WeakParentType] = iotaBlock.Body.WeakParentIDs().RemoveDupsAndSort() + references[iotago.ShallowLikeParentType] = iotaBlock.Body.ShallowLikeParentIDs().RemoveDupsAndSort() + if iotaBlock.Header.IssuingTime.Equal(time.Unix(0, 0)) { + iotaBlock.Header.IssuingTime = time.Now().UTC() resign = true } - if err = i.validateReferences(iotaBlock.IssuingTime, iotaBlock.SlotCommitmentID.Slot(), references, node); err != nil { + if err = i.validateReferences(iotaBlock.Header.IssuingTime, iotaBlock.Header.SlotCommitmentID.Slot(), references, node); err != nil { return iotago.EmptyBlockID, ierrors.Wrapf(ErrBlockAttacherAttachingNotPossible, "invalid block references, error: %w", err) } - if basicBlock, isBasicBlock := iotaBlock.Block.(*iotago.BasicBlock); isBasicBlock && basicBlock.MaxBurnedMana == 0 { - rmcSlot, err := safemath.SafeSub(apiForVersion.TimeProvider().SlotFromTime(iotaBlock.IssuingTime), apiForVersion.ProtocolParameters().MaxCommittableAge()) + if basicBlock, isBasicBlock := iotaBlock.Body.(*iotago.BasicBlockBody); isBasicBlock && basicBlock.MaxBurnedMana == 0 { + rmcSlot, err := safemath.SafeSub(apiForVersion.TimeProvider().SlotFromTime(iotaBlock.Header.IssuingTime), apiForVersion.ProtocolParameters().MaxCommittableAge()) if err != nil { rmcSlot = 0 } @@ -442,10 +447,10 @@ func (i *BlockIssuer) AttachBlock(ctx context.Context, iotaBlock *iotago.Protoco resign = true } - if iotaBlock.IssuerID.Empty() || resign { + if iotaBlock.Header.IssuerID.Empty() || resign { if i.optsIncompleteBlockAccepted && len(optIssuerAccount) > 0 { issuerAccount := optIssuerAccount[0] - iotaBlock.IssuerID = issuerAccount.ID() + iotaBlock.Header.IssuerID = issuerAccount.ID() signature, signatureErr := iotaBlock.Sign(iotago.NewAddressKeysForEd25519Address(issuerAccount.Address().(*iotago.Ed25519Address), issuerAccount.PrivateKey())) if signatureErr != nil { @@ -468,7 +473,7 @@ func (i *BlockIssuer) AttachBlock(ctx context.Context, iotaBlock *iotago.Protoco return iotago.EmptyBlockID, ierrors.Wrap(err, "error serializing block to model block") } - if !i.optsRateSetterEnabled || node.Protocol.MainEngineInstance().Scheduler.IsBlockIssuerReady(modelBlock.ProtocolBlock().IssuerID) { + if !i.optsRateSetterEnabled || node.Protocol.MainEngineInstance().Scheduler.IsBlockIssuerReady(modelBlock.ProtocolBlock().Header.IssuerID) { i.events.BlockConstructed.Trigger(modelBlock) if err = i.IssueBlockAndAwaitEvent(ctx, modelBlock, node, node.Protocol.Events.Engine.BlockDAG.BlockAttached); err != nil { diff --git a/pkg/testsuite/mock/hdwallet.go b/pkg/testsuite/mock/hdwallet.go deleted file mode 100644 index a4e1ceb4e..000000000 --- a/pkg/testsuite/mock/hdwallet.go +++ /dev/null @@ -1,138 +0,0 @@ -package mock - -import ( - "crypto/ed25519" - "fmt" - - "github.com/wollac/iota-crypto-demo/pkg/bip32path" - "github.com/wollac/iota-crypto-demo/pkg/slip10" - "github.com/wollac/iota-crypto-demo/pkg/slip10/eddsa" - - "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/iota-core/pkg/protocol/engine/utxoledger" - iotago "github.com/iotaledger/iota.go/v4" -) - -const ( - pathString = "44'/4218'/0'/%d'" -) - -type HDWallet struct { - name string - seed []byte - index uint64 - utxo []*utxoledger.Output -} - -func NewHDWallet(name string, seed []byte, index uint64) *HDWallet { - return &HDWallet{ - name: name, - seed: seed, - index: index, - utxo: make([]*utxoledger.Output, 0), - } -} - -func (hd *HDWallet) BookSpents(spentOutputs []*utxoledger.Output) { - for _, spent := range spentOutputs { - hd.BookSpent(spent) - } -} - -func (hd *HDWallet) BookSpent(spentOutput *utxoledger.Output) { - newUtxo := make([]*utxoledger.Output, 0) - for _, u := range hd.utxo { - if u.OutputID() == spentOutput.OutputID() { - fmt.Printf("%s spent %s\n", hd.name, u.OutputID().ToHex()) - - continue - } - newUtxo = append(newUtxo, u) - } - hd.utxo = newUtxo -} - -func (hd *HDWallet) Name() string { - return hd.name -} - -func (hd *HDWallet) Balance() iotago.BaseToken { - var balance iotago.BaseToken - for _, u := range hd.utxo { - balance += u.BaseTokenAmount() - } - - return balance -} - -func (hd *HDWallet) BookOutput(output *utxoledger.Output) { - if output != nil { - fmt.Printf("%s book %s\n", hd.name, output.OutputID().ToHex()) - hd.utxo = append(hd.utxo, output) - } -} - -// KeyPair calculates an ed25519 key pair by using slip10. -func (hd *HDWallet) KeyPair() (ed25519.PrivateKey, ed25519.PublicKey) { - path, err := bip32path.ParsePath(fmt.Sprintf(pathString, hd.index)) - if err != nil { - panic(err) - } - - curve := eddsa.Ed25519() - key, err := slip10.DeriveKeyFromPath(hd.seed, curve, path) - if err != nil { - panic(err) - } - - pubKey, privKey := key.Key.(eddsa.Seed).Ed25519Key() - - return ed25519.PrivateKey(privKey), ed25519.PublicKey(pubKey) -} - -func (hd *HDWallet) AddressSigner() iotago.AddressSigner { - privKey, pubKey := hd.KeyPair() - address := iotago.Ed25519AddressFromPubKey(pubKey) - - return iotago.NewInMemoryAddressSigner(iotago.NewAddressKeysForEd25519Address(address, privKey)) -} - -func (hd *HDWallet) Outputs() []*utxoledger.Output { - return hd.utxo -} - -// Address calculates an ed25519 address by using slip10. -func (hd *HDWallet) Address(addressType ...iotago.AddressType) iotago.DirectUnlockableAddress { - _, pubKey := hd.KeyPair() - - addrType := iotago.AddressEd25519 - if len(addressType) > 0 { - addrType = addressType[0] - } - - switch addrType { - case iotago.AddressEd25519: - return iotago.Ed25519AddressFromPubKey(pubKey) - case iotago.AddressImplicitAccountCreation: - return iotago.ImplicitAccountCreationAddressFromPubKey(pubKey) - default: - panic(ierrors.Wrapf(iotago.ErrUnknownAddrType, "type %d", addressType)) - } -} - -func (hd *HDWallet) PrintStatus() { - var status string - status += fmt.Sprintf("Name: %s\n", hd.name) - status += fmt.Sprintf("Address: %s\n", hd.Address().Bech32(iotago.PrefixTestnet)) - status += fmt.Sprintf("Balance: %d\n", hd.Balance()) - status += "Outputs: \n" - for _, u := range hd.utxo { - nativeTokenDescription := "" - nativeTokenFeature := u.Output().FeatureSet().NativeToken() - if nativeTokenFeature != nil { - nativeTokenDescription += fmt.Sprintf("%s: %s, ", nativeTokenFeature.ID.ToHex(), nativeTokenFeature.Amount) - } - status += fmt.Sprintf("\t%s [%s] = %d %v\n", u.OutputID().ToHex(), u.OutputType(), u.BaseTokenAmount(), nativeTokenDescription) - } - fmt.Printf("%s\n", status) -} diff --git a/pkg/testsuite/mock/keymanager.go b/pkg/testsuite/mock/keymanager.go new file mode 100644 index 000000000..236a50551 --- /dev/null +++ b/pkg/testsuite/mock/keymanager.go @@ -0,0 +1,75 @@ +package mock + +import ( + "crypto/ed25519" + "fmt" + + "github.com/wollac/iota-crypto-demo/pkg/bip32path" + "github.com/wollac/iota-crypto-demo/pkg/slip10" + "github.com/wollac/iota-crypto-demo/pkg/slip10/eddsa" + + "github.com/iotaledger/hive.go/ierrors" + iotago "github.com/iotaledger/iota.go/v4" +) + +const ( + pathString = "44'/4218'/0'/%d'" +) + +// KeyManager is a hierarchical deterministic key manager. +type KeyManager struct { + seed []byte + index uint64 +} + +func NewKeyManager(seed []byte, index uint64) *KeyManager { + return &KeyManager{ + seed: seed, + index: index, + } +} + +// KeyPair calculates an ed25519 key pair by using slip10. +func (k *KeyManager) KeyPair() (ed25519.PrivateKey, ed25519.PublicKey) { + path, err := bip32path.ParsePath(fmt.Sprintf(pathString, k.index)) + if err != nil { + panic(err) + } + + curve := eddsa.Ed25519() + key, err := slip10.DeriveKeyFromPath(k.seed, curve, path) + if err != nil { + panic(err) + } + + pubKey, privKey := key.Key.(eddsa.Seed).Ed25519Key() + + return ed25519.PrivateKey(privKey), ed25519.PublicKey(pubKey) +} + +// AddressSigner returns an address signer. +func (k *KeyManager) AddressSigner() iotago.AddressSigner { + privKey, pubKey := k.KeyPair() + + // add both address types for simplicity in tests + ed25519Address := iotago.Ed25519AddressFromPubKey(pubKey) + ed25519AddressKey := iotago.NewAddressKeysForEd25519Address(ed25519Address, privKey) + implicitAccountCreationAddress := iotago.ImplicitAccountCreationAddressFromPubKey(pubKey) + implicitAccountCreationAddressKey := iotago.NewAddressKeysForImplicitAccountCreationAddress(implicitAccountCreationAddress, privKey) + + return iotago.NewInMemoryAddressSigner(ed25519AddressKey, implicitAccountCreationAddressKey) +} + +// Address calculates an address of the specified type. +func (k *KeyManager) Address(addressType iotago.AddressType) iotago.DirectUnlockableAddress { + _, pubKey := k.KeyPair() + + switch addressType { + case iotago.AddressEd25519: + return iotago.Ed25519AddressFromPubKey(pubKey) + case iotago.AddressImplicitAccountCreation: + return iotago.ImplicitAccountCreationAddressFromPubKey(pubKey) + default: + panic(ierrors.Wrapf(iotago.ErrUnknownAddrType, "type %d", addressType)) + } +} diff --git a/pkg/testsuite/mock/node.go b/pkg/testsuite/mock/node.go index afca4da93..b9bde387f 100644 --- a/pkg/testsuite/mock/node.go +++ b/pkg/testsuite/mock/node.go @@ -2,7 +2,6 @@ package mock import ( "context" - "crypto/ed25519" "fmt" "sync/atomic" "testing" @@ -29,6 +28,7 @@ import ( "github.com/iotaledger/iota-core/pkg/protocol/engine/notarization" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/merklehasher" + "github.com/iotaledger/iota.go/v4/tpkg" ) // idAliases contains a list of aliases registered for a set of IDs. @@ -48,8 +48,9 @@ func UnregisterIDAliases() { type Node struct { Testing *testing.T - Name string - Validator *BlockIssuer + Name string + Validator *BlockIssuer + KeyManager *KeyManager ctx context.Context ctxCancel context.CancelFunc @@ -73,10 +74,9 @@ type Node struct { } func NewNode(t *testing.T, net *Network, partition string, name string, validator bool) *Node { - pub, priv, err := ed25519.GenerateKey(nil) - if err != nil { - panic(err) - } + seed := tpkg.RandEd25519Seed() + keyManager := NewKeyManager(seed[:], 0) + priv, pub := keyManager.KeyPair() accountID := iotago.AccountID(blake2b.Sum256(pub)) accountID.RegisterAlias(name) @@ -86,7 +86,7 @@ func NewNode(t *testing.T, net *Network, partition string, name string, validato var validatorBlockIssuer *BlockIssuer if validator { - validatorBlockIssuer = NewBlockIssuer(t, name, validator) + validatorBlockIssuer = NewBlockIssuer(t, name, keyManager, accountID, validator) } else { validatorBlockIssuer = nil } @@ -96,7 +96,8 @@ func NewNode(t *testing.T, net *Network, partition string, name string, validato Name: name, - Validator: validatorBlockIssuer, + Validator: validatorBlockIssuer, + KeyManager: keyManager, PeerID: peerID, @@ -354,19 +355,19 @@ func (n *Node) attachEngineLogsWithName(failOnBlockFiltered bool, instance *engi }) events.BlockGadget.BlockPreAccepted.Hook(func(block *blocks.Block) { - fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockPreAccepted: %s %s\n", n.Name, engineName, block.ID(), block.ProtocolBlock().SlotCommitmentID) + fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockPreAccepted: %s %s\n", n.Name, engineName, block.ID(), block.ProtocolBlock().Header.SlotCommitmentID) }) events.BlockGadget.BlockAccepted.Hook(func(block *blocks.Block) { - fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockAccepted: %s @ slot %s committing to %s\n", n.Name, engineName, block.ID(), block.ID().Slot(), block.ProtocolBlock().SlotCommitmentID) + fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockAccepted: %s @ slot %s committing to %s\n", n.Name, engineName, block.ID(), block.ID().Slot(), block.ProtocolBlock().Header.SlotCommitmentID) }) events.BlockGadget.BlockPreConfirmed.Hook(func(block *blocks.Block) { - fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockPreConfirmed: %s %s\n", n.Name, engineName, block.ID(), block.ProtocolBlock().SlotCommitmentID) + fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockPreConfirmed: %s %s\n", n.Name, engineName, block.ID(), block.ProtocolBlock().Header.SlotCommitmentID) }) events.BlockGadget.BlockConfirmed.Hook(func(block *blocks.Block) { - fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockConfirmed: %s %s\n", n.Name, engineName, block.ID(), block.ProtocolBlock().SlotCommitmentID) + fmt.Printf("%s > [%s] Consensus.BlockGadget.BlockConfirmed: %s %s\n", n.Name, engineName, block.ID(), block.ProtocolBlock().Header.SlotCommitmentID) }) events.SlotGadget.SlotFinalized.Hook(func(slot iotago.SlotIndex) { @@ -515,3 +516,11 @@ func (n *Node) AttachedBlocks() []*blocks.Block { return n.attachedBlocks } + +func (n *Node) IssueValidationBlock(ctx context.Context, alias string, opts ...options.Option[ValidatorBlockParams]) *blocks.Block { + if n.Validator == nil { + panic("node is not a validator") + } + + return n.Validator.IssueValidationBlock(ctx, alias, n, opts...) +} diff --git a/pkg/testsuite/mock/utils.go b/pkg/testsuite/mock/utils.go new file mode 100644 index 000000000..f7cc8adcd --- /dev/null +++ b/pkg/testsuite/mock/utils.go @@ -0,0 +1,221 @@ +package mock + +import ( + "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/pkg/protocol/engine/utxoledger" + iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/builder" +) + +const MinIssuerAccountAmount = iotago.BaseToken(372900) +const MinValidatorAccountAmount = iotago.BaseToken(722800) +const AccountConversionManaCost = iotago.Mana(1000000) + +// TransactionBuilder options + +func WithInputs(inputs utxoledger.Outputs) options.Option[builder.TransactionBuilder] { + return func(txBuilder *builder.TransactionBuilder) { + for _, input := range inputs { + switch input.OutputType() { + case iotago.OutputFoundry: + // For foundries we need to unlock the account output + txBuilder.AddInput(&builder.TxInput{ + UnlockTarget: input.Output().UnlockConditionSet().ImmutableAccount().Address, + InputID: input.OutputID(), + Input: input.Output(), + }) + case iotago.OutputAccount: + // For alias we need to unlock the state controller + txBuilder.AddInput(&builder.TxInput{ + UnlockTarget: input.Output().UnlockConditionSet().StateControllerAddress().Address, + InputID: input.OutputID(), + Input: input.Output(), + }) + default: + txBuilder.AddInput(&builder.TxInput{ + UnlockTarget: input.Output().UnlockConditionSet().Address().Address, + InputID: input.OutputID(), + Input: input.Output(), + }) + } + } + } +} + +func WithAccountInput(input *utxoledger.Output, governorTransition bool) options.Option[builder.TransactionBuilder] { + return func(txBuilder *builder.TransactionBuilder) { + switch input.OutputType() { + case iotago.OutputAccount: + address := input.Output().UnlockConditionSet().StateControllerAddress().Address + if governorTransition { + address = input.Output().UnlockConditionSet().GovernorAddress().Address + } + txBuilder.AddInput(&builder.TxInput{ + UnlockTarget: address, + InputID: input.OutputID(), + Input: input.Output(), + }) + default: + panic("only OutputAccount can be added as account input") + } + } +} + +func WithAllotments(allotments iotago.Allotments) options.Option[builder.TransactionBuilder] { + return func(txBuilder *builder.TransactionBuilder) { + for _, allotment := range allotments { + txBuilder.IncreaseAllotment(allotment.AccountID, allotment.Mana) + } + } +} + +func WithSlotCreated(creationSlot iotago.SlotIndex) options.Option[builder.TransactionBuilder] { + return func(txBuilder *builder.TransactionBuilder) { + txBuilder.SetCreationSlot(creationSlot) + } +} + +func WithContextInputs(contextInputs iotago.TxEssenceContextInputs) options.Option[builder.TransactionBuilder] { + return func(txBuilder *builder.TransactionBuilder) { + for _, input := range contextInputs { + txBuilder.AddContextInput(input) + } + } +} + +func WithOutputs(outputs iotago.Outputs[iotago.Output]) options.Option[builder.TransactionBuilder] { + return func(txBuilder *builder.TransactionBuilder) { + for _, output := range outputs { + txBuilder.AddOutput(output) + } + } +} + +func WithTaggedDataPayload(payload *iotago.TaggedData) options.Option[builder.TransactionBuilder] { + return func(txBuilder *builder.TransactionBuilder) { + txBuilder.AddTaggedDataPayload(payload) + } +} + +// DelegationOutput options + +func WithDelegatedAmount(delegatedAmount iotago.BaseToken) options.Option[builder.DelegationOutputBuilder] { + return func(delegationBuilder *builder.DelegationOutputBuilder) { + delegationBuilder.DelegatedAmount(delegatedAmount) + } +} + +func WithDelegatedValidatorAddress(validatorAddress *iotago.AccountAddress) options.Option[builder.DelegationOutputBuilder] { + return func(delegationBuilder *builder.DelegationOutputBuilder) { + delegationBuilder.ValidatorAddress(validatorAddress) + } +} + +func WithDelegationStartEpoch(startEpoch iotago.EpochIndex) options.Option[builder.DelegationOutputBuilder] { + return func(delegationBuilder *builder.DelegationOutputBuilder) { + delegationBuilder.StartEpoch(startEpoch) + } +} + +func WithDelegationEndEpoch(endEpoch iotago.EpochIndex) options.Option[builder.DelegationOutputBuilder] { + return func(delegationBuilder *builder.DelegationOutputBuilder) { + delegationBuilder.EndEpoch(endEpoch) + } +} + +func WithDelegationConditions(delegationConditions iotago.DelegationOutputUnlockConditions) options.Option[builder.DelegationOutputBuilder] { + return func(delegationBuilder *builder.DelegationOutputBuilder) { + delegationBuilder.Address(delegationConditions.MustSet().Address().Address) + } +} + +func WithDelegationAmount(amount iotago.BaseToken) options.Option[builder.DelegationOutputBuilder] { + return func(delegationBuilder *builder.DelegationOutputBuilder) { + delegationBuilder.Amount(amount) + } +} + +// BlockIssuer options + +func WithBlockIssuerFeature(keys iotago.BlockIssuerKeys, expirySlot iotago.SlotIndex) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + accountBuilder.BlockIssuer(keys, expirySlot) + } +} + +func WithAddBlockIssuerKey(key iotago.BlockIssuerKey) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + transition := accountBuilder.GovernanceTransition() + transition.BlockIssuerTransition().AddKeys(key) + } +} + +func WithBlockIssuerKeys(keys iotago.BlockIssuerKeys) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + transition := accountBuilder.GovernanceTransition() + transition.BlockIssuerTransition().Keys(keys) + } +} + +func WithBlockIssuerExpirySlot(expirySlot iotago.SlotIndex) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + transition := accountBuilder.GovernanceTransition() + transition.BlockIssuerTransition().ExpirySlot(expirySlot) + } +} + +func WithStakingFeature(amount iotago.BaseToken, fixedCost iotago.Mana, startEpoch iotago.EpochIndex, optEndEpoch ...iotago.EpochIndex) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + accountBuilder.Staking(amount, fixedCost, startEpoch, optEndEpoch...) + } +} + +// Account options + +func WithAccountMana(mana iotago.Mana) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + accountBuilder.Mana(mana) + } +} + +func WithAccountAmount(amount iotago.BaseToken) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + accountBuilder.Amount(amount) + } +} + +func WithAccountIncreasedFoundryCounter(diff uint32) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + accountBuilder.FoundriesToGenerate(diff) + } +} + +func WithAccountImmutableFeatures(features iotago.AccountOutputImmFeatures) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + for _, feature := range features.MustSet() { + switch feature.Type() { + case iotago.FeatureMetadata: + //nolint:forcetypeassert + accountBuilder.ImmutableMetadata(feature.(*iotago.MetadataFeature).Data) + case iotago.FeatureSender: + //nolint:forcetypeassert + accountBuilder.ImmutableSender(feature.(*iotago.SenderFeature).Address) + } + } + } +} + +func WithAccountConditions(conditions iotago.AccountOutputUnlockConditions) options.Option[builder.AccountOutputBuilder] { + return func(accountBuilder *builder.AccountOutputBuilder) { + for _, condition := range conditions.MustSet() { + switch condition.Type() { + case iotago.UnlockConditionStateControllerAddress: + //nolint:forcetypeassert + accountBuilder.StateController(condition.(*iotago.StateControllerAddressUnlockCondition).Address) + case iotago.UnlockConditionGovernorAddress: + //nolint:forcetypeassert + accountBuilder.Governor(condition.(*iotago.GovernorAddressUnlockCondition).Address) + } + } + } +} diff --git a/pkg/testsuite/mock/wallet.go b/pkg/testsuite/mock/wallet.go new file mode 100644 index 000000000..b161ed1af --- /dev/null +++ b/pkg/testsuite/mock/wallet.go @@ -0,0 +1,131 @@ +package mock + +import ( + "crypto/ed25519" + "testing" + + "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/iota-core/pkg/protocol/engine/utxoledger" + iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/tpkg" +) + +// Wallet is an object representing a wallet (similar to a FireFly wallet) capable of the following: +// - hierarchical deterministic key management +// - signing transactions +// - signing blocks +// - keeping track of unspent outputs. +type Wallet struct { + Testing *testing.T + + Name string + + Node *Node + + keyManager *KeyManager + + BlockIssuer *BlockIssuer + + outputs map[string]*utxoledger.Output + transactions map[string]*iotago.Transaction +} + +func NewWallet(t *testing.T, name string, node *Node, keyManager ...*KeyManager) *Wallet { + var km *KeyManager + if len(keyManager) == 0 { + randomSeed := tpkg.RandEd25519Seed() + km = NewKeyManager(randomSeed[:], 0) + } else { + km = keyManager[0] + } + + return &Wallet{ + Testing: t, + Name: name, + Node: node, + outputs: make(map[string]*utxoledger.Output), + transactions: make(map[string]*iotago.Transaction), + keyManager: km, + } +} + +func (w *Wallet) SetBlockIssuer(accountID iotago.AccountID) { + w.BlockIssuer = NewBlockIssuer(w.Testing, w.Name, w.keyManager, accountID, false) +} + +func (w *Wallet) SetDefaultNode(node *Node) { + w.Node = node +} + +func (w *Wallet) AddOutput(outputName string, output *utxoledger.Output) { + w.outputs[outputName] = output +} + +func (w *Wallet) Balance() iotago.BaseToken { + var balance iotago.BaseToken + for _, output := range w.outputs { + balance += output.BaseTokenAmount() + } + + return balance +} + +func (w *Wallet) Output(outputName string) *utxoledger.Output { + output, exists := w.outputs[outputName] + if !exists { + panic(ierrors.Errorf("output %s not registered in wallet %s", outputName, w.Name)) + } + + return output +} + +func (w *Wallet) AccountOutput(outputName string) *utxoledger.Output { + output := w.Output(outputName) + if _, ok := output.Output().(*iotago.AccountOutput); !ok { + panic(ierrors.Errorf("output %s is not an account output", outputName)) + } + + return output +} + +func (w *Wallet) Transaction(alias string) *iotago.Transaction { + transaction, exists := w.transactions[alias] + if !exists { + panic(ierrors.Errorf("transaction with given alias does not exist %s", alias)) + } + + return transaction +} + +func (w *Wallet) Transactions(transactionNames ...string) []*iotago.Transaction { + return lo.Map(transactionNames, w.Transaction) +} + +func (w *Wallet) TransactionID(alias string) iotago.TransactionID { + return lo.PanicOnErr(w.Transaction(alias).ID()) +} + +func (w *Wallet) Address() iotago.DirectUnlockableAddress { + address := w.keyManager.Address(iotago.AddressEd25519) + //nolint:forcetypeassert + return address.(*iotago.Ed25519Address) +} + +func (w *Wallet) ImplicitAccountCreationAddress() *iotago.ImplicitAccountCreationAddress { + address := w.keyManager.Address(iotago.AddressImplicitAccountCreation) + //nolint:forcetypeassert + return address.(*iotago.ImplicitAccountCreationAddress) +} + +func (w *Wallet) HasAddress(address iotago.Address) bool { + return address.Equal(w.Address()) || address.Equal(w.ImplicitAccountCreationAddress()) +} + +func (w *Wallet) KeyPair() (ed25519.PrivateKey, ed25519.PublicKey) { + return w.keyManager.KeyPair() +} + +func (w *Wallet) AddressSigner() iotago.AddressSigner { + return w.keyManager.AddressSigner() +} diff --git a/pkg/testsuite/mock/wallet_blocks.go b/pkg/testsuite/mock/wallet_blocks.go new file mode 100644 index 000000000..22fe8bea4 --- /dev/null +++ b/pkg/testsuite/mock/wallet_blocks.go @@ -0,0 +1,12 @@ +package mock + +import ( + "context" + + "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/pkg/protocol/engine/blocks" +) + +func (w *Wallet) IssueBasicBlock(ctx context.Context, blockName string, opts ...options.Option[BasicBlockParams]) *blocks.Block { + return w.BlockIssuer.IssueBasicBlock(ctx, blockName, w.Node, opts...) +} diff --git a/pkg/testsuite/mock/wallet_transactions.go b/pkg/testsuite/mock/wallet_transactions.go new file mode 100644 index 000000000..6b3481046 --- /dev/null +++ b/pkg/testsuite/mock/wallet_transactions.go @@ -0,0 +1,362 @@ +package mock + +import ( + "fmt" + "time" + + "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/lo" + "github.com/iotaledger/hive.go/runtime/options" + "github.com/iotaledger/iota-core/pkg/protocol/engine/utxoledger" + iotago "github.com/iotaledger/iota.go/v4" + "github.com/iotaledger/iota.go/v4/builder" + "github.com/iotaledger/iota.go/v4/tpkg" +) + +// Functionality for creating transactions in the mock wallet. + +func (w *Wallet) CreateAccountFromInput(transactionName string, inputName string, recipientWallet *Wallet, creationSlot iotago.SlotIndex, opts ...options.Option[builder.AccountOutputBuilder]) *iotago.SignedTransaction { + input := w.Output(inputName) + + accountOutput := options.Apply(builder.NewAccountOutputBuilder(recipientWallet.Address(), recipientWallet.Address(), input.BaseTokenAmount()). + Mana(input.StoredMana()), + opts).MustBuild() + + outputStates := iotago.Outputs[iotago.Output]{accountOutput} + + // if amount was set by options, a remainder output needs to be created + if accountOutput.Amount != input.BaseTokenAmount() { + remainderOutput := &iotago.BasicOutput{ + Amount: input.BaseTokenAmount() - accountOutput.Amount, + Mana: input.StoredMana() - accountOutput.Mana, + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: recipientWallet.Address()}, + }, + Features: iotago.BasicOutputFeatures{}, + } + outputStates = append(outputStates, remainderOutput) + } + + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithContextInputs(iotago.TxEssenceContextInputs{ + &iotago.CommitmentInput{ + CommitmentID: w.Node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), + }, + }), + WithInputs(utxoledger.Outputs{input}), + WithOutputs(outputStates), + WithSlotCreated(creationSlot), + )) + + // register the outputs in the recipient wallet (so wallet doesn't have to scan for outputs on its addresses) + recipientWallet.registerOutputs(transactionName, signedTransaction.Transaction) + + return signedTransaction +} + +// CreateDelegationFromInput creates a new DelegationOutput with given options from an input. If the remainder Output +// is not created, then StoredMana from the input is not passed and can potentially be burned. +// In order not to burn it, it needs to be assigned manually in another output in the transaction. +func (w *Wallet) CreateDelegationFromInput(transactionName string, inputName string, creationSlot iotago.SlotIndex, opts ...options.Option[builder.DelegationOutputBuilder]) *iotago.SignedTransaction { + input := w.Output(inputName) + + delegationOutput := options.Apply(builder.NewDelegationOutputBuilder(&iotago.AccountAddress{}, w.Address(), input.BaseTokenAmount()). + DelegatedAmount(input.BaseTokenAmount()), + opts).MustBuild() + + if delegationOutput.ValidatorAddress.AccountID() == iotago.EmptyAccountID || + delegationOutput.DelegatedAmount == 0 || + delegationOutput.StartEpoch == 0 { + panic(fmt.Sprintf("delegation output created incorrectly %+v", delegationOutput)) + } + + outputStates := iotago.Outputs[iotago.Output]{delegationOutput} + + // if options set an Amount, a remainder output needs to be created + if delegationOutput.Amount != input.BaseTokenAmount() { + outputStates = append(outputStates, &iotago.BasicOutput{ + Amount: input.BaseTokenAmount() - delegationOutput.Amount, + Mana: input.StoredMana(), + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: w.Address()}, + }, + Features: iotago.BasicOutputFeatures{}, + }) + } + + // create the signed transaction + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithContextInputs(iotago.TxEssenceContextInputs{ + &iotago.CommitmentInput{ + CommitmentID: w.Node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), + }, + }), + WithInputs(utxoledger.Outputs{input}), + WithOutputs(outputStates), + WithSlotCreated(creationSlot), + )) + + return signedTransaction +} + +// DelayedClaimingTransition transitions DelegationOutput into delayed claiming state by setting DelegationID and EndEpoch. +func (w *Wallet) DelayedClaimingTransition(transactionName string, inputName string, creationSlot iotago.SlotIndex, delegationEndEpoch iotago.EpochIndex) *iotago.SignedTransaction { + input := w.Output(inputName) + if input.OutputType() != iotago.OutputDelegation { + panic(ierrors.Errorf("%s is not a delegation output, cannot transition to delayed claiming state", inputName)) + } + + prevOutput, ok := input.Output().Clone().(*iotago.DelegationOutput) + if !ok { + panic(ierrors.Errorf("cloned output %s is not a delegation output, cannot transition to delayed claiming state", inputName)) + } + + delegationBuilder := builder.NewDelegationOutputBuilderFromPrevious(prevOutput).EndEpoch(delegationEndEpoch) + if prevOutput.DelegationID == iotago.EmptyDelegationID() { + delegationBuilder.DelegationID(iotago.DelegationIDFromOutputID(input.OutputID())) + } + + delegationOutput := delegationBuilder.MustBuild() + + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithContextInputs(iotago.TxEssenceContextInputs{ + &iotago.CommitmentInput{ + CommitmentID: w.Node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), + }, + }), + WithInputs(utxoledger.Outputs{input}), + WithOutputs(iotago.Outputs[iotago.Output]{delegationOutput}), + WithSlotCreated(creationSlot), + )) + + return signedTransaction +} + +func (w *Wallet) TransitionAccount(transactionName string, inputName string, opts ...options.Option[builder.AccountOutputBuilder]) *iotago.SignedTransaction { + input, exists := w.outputs[inputName] + if !exists { + panic(fmt.Sprintf("account with alias %s does not exist", inputName)) + } + + accountOutput, ok := input.Output().Clone().(*iotago.AccountOutput) + if !ok { + panic(fmt.Sprintf("output with alias %s is not *iotago.AccountOutput", inputName)) + } + + accountBuilder := builder.NewAccountOutputBuilderFromPrevious(accountOutput) + accountOutput = options.Apply(accountBuilder, opts).MustBuild() + + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithAccountInput(input, true), + WithContextInputs(iotago.TxEssenceContextInputs{ + &iotago.BlockIssuanceCreditInput{ + AccountID: accountOutput.AccountID, + }, + &iotago.CommitmentInput{ + CommitmentID: w.Node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), + }, + }), + WithOutputs(iotago.Outputs[iotago.Output]{accountOutput}), + )) + + return signedTransaction +} + +func (w *Wallet) DestroyAccount(transactionName string, inputName string, creationSlot iotago.SlotIndex) *iotago.SignedTransaction { + input := w.Output(inputName) + inputAccount, ok := input.Output().(*iotago.AccountOutput) + if !ok { + panic(fmt.Sprintf("output with alias %s is not *iotago.AccountOutput", inputName)) + } + + destructionOutputs := iotago.Outputs[iotago.Output]{&iotago.BasicOutput{ + Amount: input.BaseTokenAmount(), + Mana: input.StoredMana(), + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: w.Address()}, + }, + Features: iotago.BasicOutputFeatures{}, + }} + + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithContextInputs(iotago.TxEssenceContextInputs{ + &iotago.BlockIssuanceCreditInput{ + AccountID: inputAccount.AccountID, + }, + &iotago.CommitmentInput{ + CommitmentID: w.Node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), + }, + }), + WithAccountInput(input, true), + WithOutputs(destructionOutputs), + WithSlotCreated(creationSlot), + )) + + return signedTransaction +} + +// CreateImplicitAccountFromInput creates an implicit account output. +func (w *Wallet) CreateImplicitAccountFromInput(transactionName string, inputName string, recipientWallet *Wallet) *iotago.SignedTransaction { + input := w.Output(inputName) + + implicitAccountOutput := &iotago.BasicOutput{ + Amount: MinIssuerAccountAmount, + Mana: AccountConversionManaCost, + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: recipientWallet.ImplicitAccountCreationAddress()}, + }, + Features: iotago.BasicOutputFeatures{}, + } + + remainderBasicOutput := &iotago.BasicOutput{ + Amount: input.BaseTokenAmount() - MinIssuerAccountAmount, + Mana: input.StoredMana() - AccountConversionManaCost, + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: input.Output().UnlockConditionSet().Address().Address}, + }, + Features: iotago.BasicOutputFeatures{}, + } + + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithInputs(utxoledger.Outputs{input}), + WithOutputs(iotago.Outputs[iotago.Output]{implicitAccountOutput, remainderBasicOutput}), + )) + + // register the outputs in the recipient wallet (so wallet doesn't have to scan for outputs on its addresses) + recipientWallet.registerOutputs(transactionName, signedTransaction.Transaction) + + // register the implicit account as a block issuer in the wallet + implicitAccountID := iotago.AccountIDFromOutputID(recipientWallet.Output(fmt.Sprintf("%s:0", transactionName)).OutputID()) + recipientWallet.SetBlockIssuer(implicitAccountID) + + return signedTransaction +} + +func (w *Wallet) TransitionImplicitAccountToAccountOutput(transactionName string, inputName string, creationSlot iotago.SlotIndex, opts ...options.Option[builder.AccountOutputBuilder]) *iotago.SignedTransaction { + input := w.Output(inputName) + implicitAccountID := iotago.AccountIDFromOutputID(input.OutputID()) + + basicOutput, isBasic := input.Output().(*iotago.BasicOutput) + if !isBasic { + panic(fmt.Sprintf("output with alias %s is not *iotago.BasicOutput", inputName)) + } + if basicOutput.UnlockConditionSet().Address().Address.Type() != iotago.AddressImplicitAccountCreation { + panic(fmt.Sprintf("output with alias %s is not an implicit account", inputName)) + } + + accountOutput := options.Apply(builder.NewAccountOutputBuilder(w.Address(), w.Address(), MinIssuerAccountAmount). + AccountID(iotago.AccountIDFromOutputID(input.OutputID())), + opts).MustBuild() + + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithContextInputs(iotago.TxEssenceContextInputs{ + &iotago.BlockIssuanceCreditInput{ + AccountID: implicitAccountID, + }, + &iotago.CommitmentInput{ + CommitmentID: w.Node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment().MustID(), + }, + }), + WithInputs(utxoledger.Outputs{input}), + WithOutputs(iotago.Outputs[iotago.Output]{accountOutput}), + WithSlotCreated(creationSlot), + func(txBuilder *builder.TransactionBuilder) { + txBuilder.AllotAllMana(creationSlot, implicitAccountID) + }, + )) + + return signedTransaction +} + +func (w *Wallet) CreateBasicOutputsEquallyFromInputs(transactionName string, outputCount int, inputNames ...string) *iotago.SignedTransaction { + inputStates := make([]*utxoledger.Output, 0, len(inputNames)) + totalInputAmounts := iotago.BaseToken(0) + totalInputStoredMana := iotago.Mana(0) + + for _, inputName := range inputNames { + output := w.Output(inputName) + inputStates = append(inputStates, output) + totalInputAmounts += output.BaseTokenAmount() + totalInputStoredMana += output.StoredMana() + } + + manaAmount := totalInputStoredMana / iotago.Mana(outputCount) + remainderMana := totalInputStoredMana + + tokenAmount := totalInputAmounts / iotago.BaseToken(outputCount) + remainderFunds := totalInputAmounts + + outputStates := make(iotago.Outputs[iotago.Output], 0, outputCount) + for i := 0; i < outputCount; i++ { + if i+1 == outputCount { + tokenAmount = remainderFunds + manaAmount = remainderMana + } + remainderFunds -= tokenAmount + remainderMana -= manaAmount + + outputStates = append(outputStates, &iotago.BasicOutput{ + Amount: tokenAmount, + Mana: manaAmount, + Conditions: iotago.BasicOutputUnlockConditions{ + &iotago.AddressUnlockCondition{Address: w.Address()}, + }, + Features: iotago.BasicOutputFeatures{}, + }) + } + + signedTransaction := lo.PanicOnErr(w.createSignedTransactionWithOptions( + transactionName, + WithInputs(inputStates), + WithOutputs(outputStates), + )) + + return signedTransaction +} + +func (w *Wallet) createSignedTransactionWithOptions(transactionName string, opts ...options.Option[builder.TransactionBuilder]) (*iotago.SignedTransaction, error) { + currentAPI := w.Node.Protocol.CommittedAPI() + + txBuilder := builder.NewTransactionBuilder(currentAPI) + txBuilder.WithTransactionCapabilities(iotago.TransactionCapabilitiesBitMaskWithCapabilities(iotago.WithTransactionCanDoAnything())) + // Always add a random payload to randomize transaction ID. + randomPayload := tpkg.Rand12ByteArray() + txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: randomPayload[:], Data: randomPayload[:]}) + + addrSigner := w.AddressSigner() + signedTransaction, err := options.Apply(txBuilder, opts).Build(addrSigner) + + // register the outputs in the wallet + w.registerOutputs(transactionName, signedTransaction.Transaction) + + return signedTransaction, err +} + +func (w *Wallet) registerOutputs(transactionName string, transaction *iotago.Transaction) { + currentAPI := w.Node.Protocol.CommittedAPI() + (lo.PanicOnErr(transaction.ID())).RegisterAlias(transactionName) + w.transactions[transactionName] = transaction + + for outputID, output := range lo.PanicOnErr(transaction.OutputsSet()) { + // register the output if it belongs to this wallet + addressUC := output.UnlockConditionSet().Address() + stateControllerUC := output.UnlockConditionSet().StateControllerAddress() + if addressUC != nil && w.HasAddress(addressUC.Address) || stateControllerUC != nil && w.HasAddress(stateControllerUC.Address) { + clonedOutput := output.Clone() + actualOutputID := iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(transaction.ID()), outputID.Index()) + if clonedOutput.Type() == iotago.OutputAccount { + if accountOutput, ok := clonedOutput.(*iotago.AccountOutput); ok && accountOutput.AccountID == iotago.EmptyAccountID { + accountOutput.AccountID = iotago.AccountIDFromOutputID(actualOutputID) + } + } + w.outputs[fmt.Sprintf("%s:%d", transactionName, outputID.Index())] = utxoledger.CreateOutput(w.Node.Protocol, actualOutputID, iotago.EmptyBlockID, currentAPI.TimeProvider().SlotFromTime(time.Now()), clonedOutput, lo.PanicOnErr(iotago.OutputIDProofFromTransaction(transaction, outputID.Index()))) + } + } +} diff --git a/pkg/protocol/snapshotcreator/options.go b/pkg/testsuite/snapshotcreator/options.go similarity index 90% rename from pkg/protocol/snapshotcreator/options.go rename to pkg/testsuite/snapshotcreator/options.go index 74d986fe4..85aa1f439 100644 --- a/pkg/protocol/snapshotcreator/options.go +++ b/pkg/testsuite/snapshotcreator/options.go @@ -8,6 +8,7 @@ import ( ledger1 "github.com/iotaledger/iota-core/pkg/protocol/engine/ledger/ledger" "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/seatmanager" "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/seatmanager/poa" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" iotago "github.com/iotaledger/iota.go/v4" ) @@ -22,8 +23,8 @@ type Options struct { // RootBlocks define the initial blocks to which new blocks can attach to. RootBlocks map[iotago.BlockID]iotago.CommitmentID - // GenesisSeed defines the seed used to generate keypair that can spend Genesis outputs. - GenesisSeed []byte + // GenesisKeyManager defines the key manager used to generate keypair that can spend Genesis outputs. + GenesisKeyManager *mock.KeyManager // Accounts defines the accounts that are created in the ledger as part of the Genesis. Accounts []AccountDetails @@ -83,10 +84,10 @@ func WithRootBlocks(rootBlocks map[iotago.BlockID]iotago.CommitmentID) options.O } } -// WithGenesisSeed defines the seed used to generate keypair that can spend Genesis outputs. -func WithGenesisSeed(genesisSeed []byte) options.Option[Options] { +// WithGenesisKeyManager defines the seed used to generate keypair that can spend Genesis outputs. +func WithGenesisKeyManager(keyManager *mock.KeyManager) options.Option[Options] { return func(m *Options) { - m.GenesisSeed = genesisSeed + m.GenesisKeyManager = keyManager } } diff --git a/pkg/protocol/snapshotcreator/snapshotcreator.go b/pkg/testsuite/snapshotcreator/snapshotcreator.go similarity index 98% rename from pkg/protocol/snapshotcreator/snapshotcreator.go rename to pkg/testsuite/snapshotcreator/snapshotcreator.go index 5223e0083..f0d3ee8a0 100644 --- a/pkg/protocol/snapshotcreator/snapshotcreator.go +++ b/pkg/testsuite/snapshotcreator/snapshotcreator.go @@ -133,7 +133,7 @@ func CreateSnapshot(opts ...options.Option[Options]) error { }, iotago.BaseToken(0)) var genesisTransactionOutputs iotago.TxEssenceOutputs - genesisOutput, err := createGenesisOutput(api, opt.ProtocolParameters.TokenSupply()-totalAccountAmount-totalBasicOutputAmount, opt.GenesisSeed) + genesisOutput, err := createGenesisOutput(api, opt.ProtocolParameters.TokenSupply()-totalAccountAmount-totalBasicOutputAmount, opt.GenesisKeyManager) if err != nil { return ierrors.Wrap(err, "failed to create genesis outputs") } @@ -187,10 +187,9 @@ func CreateSnapshot(opts ...options.Option[Options]) error { return engineInstance.WriteSnapshot(opt.FilePath) } -func createGenesisOutput(api iotago.API, genesisTokenAmount iotago.BaseToken, genesisSeed []byte) (iotago.Output, error) { +func createGenesisOutput(api iotago.API, genesisTokenAmount iotago.BaseToken, genesisKeyManager *mock.KeyManager) (iotago.Output, error) { if genesisTokenAmount > 0 { - genesisWallet := mock.NewHDWallet("genesis", genesisSeed, 0) - output := createOutput(genesisWallet.Address(), genesisTokenAmount, 0) + output := createOutput(genesisKeyManager.Address(iotago.AddressEd25519), genesisTokenAmount, iotago.Mana(genesisTokenAmount)) if _, err := api.StorageScoreStructure().CoversMinDeposit(output, genesisTokenAmount); err != nil { return nil, ierrors.Wrap(err, "min rent not covered by Genesis output with index 0") diff --git a/pkg/testsuite/testsuite.go b/pkg/testsuite/testsuite.go index 52d99db5c..794702d79 100644 --- a/pkg/testsuite/testsuite.go +++ b/pkg/testsuite/testsuite.go @@ -19,26 +19,23 @@ import ( "github.com/iotaledger/iota-core/pkg/protocol" "github.com/iotaledger/iota-core/pkg/protocol/engine/blocks" "github.com/iotaledger/iota-core/pkg/protocol/engine/utxoledger" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" "github.com/iotaledger/iota-core/pkg/protocol/sybilprotection/sybilprotectionv1" "github.com/iotaledger/iota-core/pkg/storage/utils" "github.com/iotaledger/iota-core/pkg/testsuite/mock" + "github.com/iotaledger/iota-core/pkg/testsuite/snapshotcreator" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/tpkg" ) -const MinIssuerAccountAmount = iotago.BaseToken(372900) -const MinValidatorAccountAmount = iotago.BaseToken(722800) - type TestSuite struct { Testing *testing.T fakeTesting *testing.T network *mock.Network - Directory *utils.Directory - nodes *orderedmap.OrderedMap[string, *mock.Node] - blockIssuers *orderedmap.OrderedMap[string, *mock.BlockIssuer] - running bool + Directory *utils.Directory + nodes *orderedmap.OrderedMap[string, *mock.Node] + wallets *orderedmap.OrderedMap[string, *mock.Wallet] + running bool snapshotPath string blocks *shrinkingmap.ShrinkingMap[string, *blocks.Block] @@ -54,19 +51,19 @@ type TestSuite struct { uniqueBlockTimeCounter atomic.Int64 automaticTransactionIssuingCounters shrinkingmap.ShrinkingMap[string, int] mutex syncutils.RWMutex - TransactionFramework *TransactionFramework - genesisSeed [32]byte + genesisKeyManager *mock.KeyManager } func NewTestSuite(testingT *testing.T, opts ...options.Option[TestSuite]) *TestSuite { + genesisSeed := tpkg.RandEd25519Seed() return options.Apply(&TestSuite{ Testing: testingT, fakeTesting: &testing.T{}, - genesisSeed: tpkg.RandEd25519Seed(), + genesisKeyManager: mock.NewKeyManager(genesisSeed[:], 0), network: mock.NewNetwork(), Directory: utils.NewDirectory(testingT.TempDir()), nodes: orderedmap.New[string, *mock.Node](), - blockIssuers: orderedmap.New[string, *mock.BlockIssuer](), + wallets: orderedmap.New[string, *mock.Wallet](), blocks: shrinkingmap.New[string, *blocks.Block](), automaticTransactionIssuingCounters: *shrinkingmap.New[string, int](), @@ -153,10 +150,7 @@ func (t *TestSuite) AccountOutput(alias string) *utxoledger.Output { t.mutex.RLock() defer t.mutex.RUnlock() - output, exist := t.TransactionFramework.states[alias] - if !exist { - panic(fmt.Sprintf("account %s not registered", alias)) - } + output := t.DefaultWallet().Output(alias) if _, ok := output.Output().(*iotago.AccountOutput); !ok { panic(fmt.Sprintf("output %s is not an account", alias)) @@ -255,6 +249,18 @@ func (t *TestSuite) Node(name string) *mock.Node { return node } +func (t *TestSuite) Wallet(name string) *mock.Wallet { + t.mutex.RLock() + defer t.mutex.RUnlock() + + wallet, exist := t.wallets.Get(name) + if !exist { + panic(fmt.Sprintf("wallet %s does not exist", name)) + } + + return wallet +} + func (t *TestSuite) Nodes(names ...string) []*mock.Node { if len(names) == 0 { t.mutex.RLock() @@ -320,7 +326,7 @@ func (t *TestSuite) addNodeToPartition(name string, partition string, validator node := mock.NewNode(t.Testing, t.network, partition, name, validator) t.nodes.Set(name, node) - amount := MinValidatorAccountAmount + amount := mock.MinValidatorAccountAmount if len(optAmount) > 0 { amount = optAmount[0] } @@ -349,7 +355,11 @@ func (t *TestSuite) AddValidatorNodeToPartition(name string, partition string, o } func (t *TestSuite) AddValidatorNode(name string, optAmount ...iotago.BaseToken) *mock.Node { - return t.addNodeToPartition(name, mock.NetworkMainPartition, true, optAmount...) + node := t.addNodeToPartition(name, mock.NetworkMainPartition, true, optAmount...) + // create a wallet for each validator node which uses the validator account as a block issuer + t.addWallet(name, node, node.Validator.AccountID, node.KeyManager) + + return node } func (t *TestSuite) AddNodeToPartition(name string, partition string, optAmount ...iotago.BaseToken) *mock.Node { @@ -364,9 +374,10 @@ func (t *TestSuite) RemoveNode(name string) { t.nodes.Delete(name) } -func (t *TestSuite) AddBasicBlockIssuer(name string, blockIssuanceCredits ...iotago.BlockIssuanceCredits) *mock.BlockIssuer { - newBlockIssuer := mock.NewBlockIssuer(t.Testing, name, false) - t.blockIssuers.Set(name, newBlockIssuer) +// AddGenesisWallet adds a wallet to the test suite with a block issuer in the genesis snapshot and access to the genesis seed. +// If no block issuance credits are provided, the wallet will be assigned half of the maximum block issuance credits. +func (t *TestSuite) AddGenesisWallet(name string, node *mock.Node, blockIssuanceCredits ...iotago.BlockIssuanceCredits) *mock.Wallet { + newWallet := t.addWallet(name, node, iotago.EmptyAccountID, t.genesisKeyManager) var bic iotago.BlockIssuanceCredits if len(blockIssuanceCredits) == 0 { bic = iotago.MaxBlockIssuanceCredits / 2 @@ -375,24 +386,34 @@ func (t *TestSuite) AddBasicBlockIssuer(name string, blockIssuanceCredits ...iot } accountDetails := snapshotcreator.AccountDetails{ - Address: iotago.Ed25519AddressFromPubKey(newBlockIssuer.PublicKey), - Amount: MinIssuerAccountAmount, - Mana: iotago.Mana(MinIssuerAccountAmount), - IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(newBlockIssuer.PublicKey)), + Address: iotago.Ed25519AddressFromPubKey(newWallet.BlockIssuer.PublicKey), + Amount: mock.MinIssuerAccountAmount, + Mana: iotago.Mana(mock.MinIssuerAccountAmount), + IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(newWallet.BlockIssuer.PublicKey)), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: bic, } t.optsAccounts = append(t.optsAccounts, accountDetails) - return newBlockIssuer + return newWallet } -func (t *TestSuite) DefaultBasicBlockIssuer() *mock.BlockIssuer { - defaultBasicBlockIssuer, exists := t.blockIssuers.Get("default") - require.True(t.Testing, exists, "default block issuer not found") +func (t *TestSuite) addWallet(name string, node *mock.Node, accountID iotago.AccountID, keyManager *mock.KeyManager) *mock.Wallet { + newWallet := mock.NewWallet(t.Testing, name, node, keyManager) + newWallet.SetBlockIssuer(accountID) + t.wallets.Set(name, newWallet) - return defaultBasicBlockIssuer + return newWallet +} + +func (t *TestSuite) DefaultWallet() *mock.Wallet { + defaultWallet, exists := t.wallets.Get("default") + if !exists { + return nil + } + + return defaultWallet } func (t *TestSuite) Run(failOnBlockFiltered bool, nodesOptions ...map[string][]options.Option[protocol.Protocol]) { @@ -401,11 +422,10 @@ func (t *TestSuite) Run(failOnBlockFiltered bool, nodesOptions ...map[string][]o // Create accounts for any block issuer nodes added before starting the network. if t.optsAccounts != nil { - wallet := mock.NewHDWallet("genesis", t.genesisSeed[:], 0) t.optsSnapshotOptions = append(t.optsSnapshotOptions, snapshotcreator.WithAccounts(lo.Map(t.optsAccounts, func(accountDetails snapshotcreator.AccountDetails) snapshotcreator.AccountDetails { - // if no custom address is assigned to the account, assign an address generated from GenesisSeed + // if no custom address is assigned to the account, assign an address generated from GenesisKeyManager if accountDetails.Address == nil { - accountDetails.Address = wallet.Address() + accountDetails.Address = t.genesisKeyManager.Address(iotago.AddressEd25519) } if accountDetails.AccountID.Empty() { @@ -422,7 +442,7 @@ func (t *TestSuite) Run(failOnBlockFiltered bool, nodesOptions ...map[string][]o })...)) } - err := snapshotcreator.CreateSnapshot(append([]options.Option[snapshotcreator.Options]{snapshotcreator.WithGenesisSeed(t.genesisSeed[:])}, t.optsSnapshotOptions...)...) + err := snapshotcreator.CreateSnapshot(append([]options.Option[snapshotcreator.Options]{snapshotcreator.WithGenesisKeyManager(t.genesisKeyManager)}, t.optsSnapshotOptions...)...) if err != nil { panic(fmt.Sprintf("failed to create snapshot: %s", err)) } @@ -443,8 +463,13 @@ func (t *TestSuite) Run(failOnBlockFiltered bool, nodesOptions ...map[string][]o node.Initialize(failOnBlockFiltered, baseOpts...) - if t.TransactionFramework == nil { - t.TransactionFramework = NewTransactionFramework(node.Protocol, t.genesisSeed[:]) + if defaultWallet := t.DefaultWallet(); defaultWallet != nil { + if err := node.Protocol.MainEngineInstance().Ledger.ForEachUnspentOutput(func(output *utxoledger.Output) bool { + defaultWallet.AddOutput(fmt.Sprintf("Genesis:%d", output.OutputID().Index()), output) + return true + }); err != nil { + panic(err) + } } return true @@ -473,7 +498,7 @@ func (t *TestSuite) BlockIssuersForNodes(nodes []*mock.Node) []*mock.BlockIssuer if node.IsValidator() { blockIssuers = append(blockIssuers, node.Validator) } else { - blockIssuers = append(blockIssuers, t.DefaultBasicBlockIssuer()) + blockIssuers = append(blockIssuers, t.DefaultWallet().BlockIssuer) } } diff --git a/pkg/testsuite/testsuite_issue_blocks.go b/pkg/testsuite/testsuite_issue_blocks.go index 8b07356ac..982f4a714 100644 --- a/pkg/testsuite/testsuite_issue_blocks.go +++ b/pkg/testsuite/testsuite_issue_blocks.go @@ -49,29 +49,19 @@ func (t *TestSuite) limitParentsCountInBlockOptions(blockOpts []options.Option[m return blockOpts } -func (t *TestSuite) RegisterBlock(alias string, block *blocks.Block) { +func (t *TestSuite) RegisterBlock(blockName string, block *blocks.Block) { t.mutex.Lock() defer t.mutex.Unlock() - t.registerBlock(alias, block) + t.registerBlock(blockName, block) } -func (t *TestSuite) registerBlock(alias string, block *blocks.Block) { - t.blocks.Set(alias, block) - block.ID().RegisterAlias(alias) +func (t *TestSuite) registerBlock(blockName string, block *blocks.Block) { + t.blocks.Set(blockName, block) + block.ID().RegisterAlias(blockName) } -func (t *TestSuite) CreateBasicBlock(alias string, blockIssuer *mock.BlockIssuer, node *mock.Node, blockOpts ...options.Option[mock.BasicBlockParams]) { - t.mutex.Lock() - defer t.mutex.Unlock() - - block, err := blockIssuer.CreateBasicBlock(context.Background(), alias, node, blockOpts...) - require.NoError(t.Testing, err) - - t.registerBlock(alias, block) -} - -func (t *TestSuite) IssueValidationBlockAtSlot(alias string, slot iotago.SlotIndex, slotCommitment *iotago.Commitment, node *mock.Node, parents ...iotago.BlockID) *blocks.Block { +func (t *TestSuite) IssueValidationBlockAtSlot(blockName string, slot iotago.SlotIndex, slotCommitment *iotago.Commitment, node *mock.Node, parents ...iotago.BlockID) *blocks.Block { t.AssertBlocksExist(t.Blocks(lo.Map(parents, func(id iotago.BlockID) string { return id.Alias() })...), true, node) t.mutex.Lock() @@ -83,48 +73,48 @@ func (t *TestSuite) IssueValidationBlockAtSlot(alias string, slot iotago.SlotInd require.Truef(t.Testing, issuingTime.Before(time.Now()), "node: %s: issued block (%s, slot: %d) is in the current (%s, slot: %d) or future slot", node.Name, issuingTime, slot, time.Now(), timeProvider.SlotFromTime(time.Now())) require.True(t.Testing, node.IsValidator(), "node: %s: is not a validator node", node.Name) - block := node.Validator.IssueValidationBlock(context.Background(), alias, node, mock.WithValidationBlockHeaderOptions(mock.WithIssuingTime(issuingTime), mock.WithSlotCommitment(slotCommitment), mock.WithStrongParents(parents...))) + block := node.Validator.IssueValidationBlock(context.Background(), blockName, node, mock.WithValidationBlockHeaderOptions(mock.WithIssuingTime(issuingTime), mock.WithSlotCommitment(slotCommitment), mock.WithStrongParents(parents...))) - t.registerBlock(alias, block) + t.registerBlock(blockName, block) return block } -func (t *TestSuite) IssueExistingBlock(alias string, blockIssuer *mock.BlockIssuer, node *mock.Node) { +func (t *TestSuite) IssueExistingBlock(blockName string, wallet *mock.Wallet) { t.mutex.Lock() defer t.mutex.Unlock() - block, exists := t.blocks.Get(alias) + block, exists := t.blocks.Get(blockName) require.True(t.Testing, exists) require.NotNil(t.Testing, block) - require.NoError(t.Testing, blockIssuer.IssueBlock(block.ModelBlock(), node)) + require.NoError(t.Testing, wallet.BlockIssuer.IssueBlock(block.ModelBlock(), wallet.Node)) } -func (t *TestSuite) IssueValidationBlockWithOptions(alias string, blockIssuer *mock.BlockIssuer, node *mock.Node, blockOpts ...options.Option[mock.ValidatorBlockParams]) *blocks.Block { +func (t *TestSuite) IssueValidationBlockWithOptions(blockName string, node *mock.Node, blockOpts ...options.Option[mock.ValidatorBlockParams]) *blocks.Block { t.mutex.Lock() defer t.mutex.Unlock() - block := blockIssuer.IssueValidationBlock(context.Background(), alias, node, blockOpts...) + block := node.IssueValidationBlock(context.Background(), blockName, blockOpts...) - t.registerBlock(alias, block) + t.registerBlock(blockName, block) return block } -func (t *TestSuite) IssueBasicBlockWithOptions(alias string, blockIssuer *mock.BlockIssuer, node *mock.Node, blockOpts ...options.Option[mock.BasicBlockParams]) *blocks.Block { +func (t *TestSuite) IssueBasicBlockWithOptions(blockName string, wallet *mock.Wallet, blockOpts ...options.Option[mock.BasicBlockParams]) *blocks.Block { t.mutex.Lock() defer t.mutex.Unlock() - block := blockIssuer.IssueBasicBlock(context.Background(), alias, node, blockOpts...) + block := wallet.IssueBasicBlock(context.Background(), blockName, blockOpts...) - t.registerBlock(alias, block) + t.registerBlock(blockName, block) return block } -func (t *TestSuite) IssueBasicBlockAtSlotWithOptions(alias string, slot iotago.SlotIndex, slotCommitment *iotago.Commitment, blockIssuer *mock.BlockIssuer, node *mock.Node, payload iotago.Payload, blockOpts ...options.Option[mock.BlockHeaderParams]) *blocks.Block { - t.assertParentsExistFromBlockOptions(blockOpts, node) +func (t *TestSuite) IssueBasicBlockAtSlotWithOptions(blockName string, slot iotago.SlotIndex, wallet *mock.Wallet, payload iotago.Payload, blockOpts ...options.Option[mock.BlockHeaderParams]) *blocks.Block { + t.assertParentsExistFromBlockOptions(blockOpts, wallet.Node) t.mutex.Lock() defer t.mutex.Unlock() @@ -132,29 +122,29 @@ func (t *TestSuite) IssueBasicBlockAtSlotWithOptions(alias string, slot iotago.S timeProvider := t.API.TimeProvider() issuingTime := timeProvider.SlotStartTime(slot).Add(time.Duration(t.uniqueBlockTimeCounter.Add(1))) - require.Truef(t.Testing, issuingTime.Before(time.Now()), "node: %s: issued block (%s, slot: %d) is in the current (%s, slot: %d) or future slot", node.Name, issuingTime, slot, time.Now(), timeProvider.SlotFromTime(time.Now())) + require.Truef(t.Testing, issuingTime.Before(time.Now()), "wallet: %s: issued block (%s, slot: %d) is in the current (%s, slot: %d) or future slot", wallet.Name, issuingTime, slot, time.Now(), timeProvider.SlotFromTime(time.Now())) - block := blockIssuer.IssueBasicBlock(context.Background(), alias, node, mock.WithBasicBlockHeader(append(blockOpts, mock.WithIssuingTime(issuingTime), mock.WithSlotCommitment(slotCommitment))...), mock.WithPayload(payload)) + block := wallet.IssueBasicBlock(context.Background(), blockName, mock.WithBasicBlockHeader(append(blockOpts, mock.WithIssuingTime(issuingTime))...), mock.WithPayload(payload)) - t.registerBlock(alias, block) + t.registerBlock(blockName, block) return block } -func (t *TestSuite) IssuePayloadWithOptions(alias string, blockIssuer *mock.BlockIssuer, node *mock.Node, payload iotago.Payload, blockHeaderOpts ...options.Option[mock.BlockHeaderParams]) *blocks.Block { - t.assertParentsExistFromBlockOptions(blockHeaderOpts, node) +func (t *TestSuite) IssuePayloadWithOptions(blockName string, wallet *mock.Wallet, payload iotago.Payload, blockHeaderOpts ...options.Option[mock.BlockHeaderParams]) *blocks.Block { + t.assertParentsExistFromBlockOptions(blockHeaderOpts, wallet.Node) t.mutex.Lock() defer t.mutex.Unlock() - block := blockIssuer.IssueBasicBlock(context.Background(), alias, node, mock.WithPayload(payload), mock.WithBasicBlockHeader(blockHeaderOpts...)) + block := wallet.IssueBasicBlock(context.Background(), blockName, mock.WithPayload(payload), mock.WithBasicBlockHeader(blockHeaderOpts...)) - t.registerBlock(alias, block) + t.registerBlock(blockName, block) return block } -func (t *TestSuite) IssueValidationBlock(alias string, node *mock.Node, blockHeaderOpts ...options.Option[mock.BlockHeaderParams]) *blocks.Block { +func (t *TestSuite) IssueValidationBlock(blockName string, node *mock.Node, blockHeaderOpts ...options.Option[mock.BlockHeaderParams]) *blocks.Block { t.assertParentsExistFromBlockOptions(blockHeaderOpts, node) require.Truef(t.Testing, node.IsValidator(), "node: %s: is not a validator node", node.Name) @@ -162,21 +152,20 @@ func (t *TestSuite) IssueValidationBlock(alias string, node *mock.Node, blockHea t.mutex.Lock() defer t.mutex.Unlock() - block := node.Validator.IssueValidationBlock(context.Background(), alias, node, mock.WithValidationBlockHeaderOptions(blockHeaderOpts...)) + block := node.Validator.IssueValidationBlock(context.Background(), blockName, node, mock.WithValidationBlockHeaderOptions(blockHeaderOpts...)) - t.registerBlock(alias, block) + t.registerBlock(blockName, block) return block } -func (t *TestSuite) IssueCandidacyAnnouncementInSlot(alias string, slot iotago.SlotIndex, parentsPrefixAlias string, node *mock.Node, issuingOptions ...options.Option[mock.BlockHeaderParams]) *blocks.Block { +func (t *TestSuite) IssueCandidacyAnnouncementInSlot(alias string, slot iotago.SlotIndex, parentsPrefixAlias string, wallet *mock.Wallet, issuingOptions ...options.Option[mock.BlockHeaderParams]) *blocks.Block { timeProvider := t.API.TimeProvider() issuingTime := timeProvider.SlotStartTime(slot).Add(time.Duration(t.uniqueBlockTimeCounter.Add(1))) - require.Truef(t.Testing, issuingTime.Before(time.Now()), "node: %s: issued block (%s, slot: %d) is in the current (%s, slot: %d) or future slot", node.Name, issuingTime, slot, time.Now(), timeProvider.SlotFromTime(time.Now())) + require.Truef(t.Testing, issuingTime.Before(time.Now()), "wallet: %s: issued block (%s, slot: %d) is in the current (%s, slot: %d) or future slot", wallet.Name, issuingTime, slot, time.Now(), timeProvider.SlotFromTime(time.Now())) return t.IssuePayloadWithOptions( alias, - node.Validator, - node, + wallet, &iotago.CandidacyAnnouncement{}, append(issuingOptions, mock.WithStrongParents(t.BlockIDsWithPrefix(parentsPrefixAlias)...), @@ -185,15 +174,14 @@ func (t *TestSuite) IssueCandidacyAnnouncementInSlot(alias string, slot iotago.S ) } -func (t *TestSuite) IssueBlockRowInSlot(prefix string, slot iotago.SlotIndex, row int, parentsPrefixAlias string, nodes []*mock.Node, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) []*blocks.Block { - blockIssuers := t.BlockIssuersForNodes(nodes) +func (t *TestSuite) IssueBlockRowInSlot(prefix string, slot iotago.SlotIndex, row int, parentsPrefix string, nodes []*mock.Node, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) []*blocks.Block { blocksIssued := make([]*blocks.Block, 0, len(nodes)) - strongParents := t.BlockIDsWithPrefix(parentsPrefixAlias) + strongParents := t.BlockIDsWithPrefix(parentsPrefix) issuingOptionsCopy := lo.MergeMaps(make(map[string][]options.Option[mock.BlockHeaderParams]), issuingOptions) - for index, node := range nodes { - blockAlias := fmt.Sprintf("%s%d.%d-%s", prefix, slot, row, node.Name) + for _, node := range nodes { + blockName := fmt.Sprintf("%s%d.%d-%s", prefix, slot, row, node.Name) issuingOptionsCopy[node.Name] = append(issuingOptionsCopy[node.Name], mock.WithStrongParents(strongParents...)) timeProvider := t.API.TimeProvider() @@ -202,23 +190,22 @@ func (t *TestSuite) IssueBlockRowInSlot(prefix string, slot iotago.SlotIndex, ro var b *blocks.Block // Only issue validator blocks if account has staking feature and is part of committee. - if blockIssuers[index].Validator && lo.Return1(node.Protocol.MainEngineInstance().SybilProtection.SeatManager().CommitteeInSlot(slot)).HasAccount(node.Validator.AccountID) { + if node.Validator != nil && lo.Return1(node.Protocol.MainEngineInstance().SybilProtection.SeatManager().CommitteeInSlot(slot)).HasAccount(node.Validator.AccountID) { blockHeaderOptions := append(issuingOptionsCopy[node.Name], mock.WithIssuingTime(issuingTime)) t.assertParentsCommitmentExistFromBlockOptions(blockHeaderOptions, node) t.assertParentsExistFromBlockOptions(blockHeaderOptions, node) - b = t.IssueValidationBlockWithOptions(blockAlias, blockIssuers[index], node, mock.WithValidationBlockHeaderOptions(blockHeaderOptions...), mock.WithHighestSupportedVersion(node.HighestSupportedVersion()), mock.WithProtocolParametersHash(node.ProtocolParametersHash())) + b = t.IssueValidationBlockWithOptions(blockName, node, mock.WithValidationBlockHeaderOptions(blockHeaderOptions...), mock.WithHighestSupportedVersion(node.HighestSupportedVersion()), mock.WithProtocolParametersHash(node.ProtocolParametersHash())) } else { txCount := t.automaticTransactionIssuingCounters.Compute(node.Partition, func(currentValue int, exists bool) int { return currentValue + 1 }) - inputAlias := fmt.Sprintf("automaticSpent-%d:0", txCount-1) - txAlias := fmt.Sprintf("automaticSpent-%d", txCount) + inputName := fmt.Sprintf("automaticSpent-%d:0", txCount-1) + txName := fmt.Sprintf("automaticSpent-%d", txCount) if txCount == 1 { - inputAlias = "Genesis:0" + inputName = "Genesis:0" } - tx, err := t.TransactionFramework.CreateSimpleTransaction(txAlias, 1, inputAlias) - require.NoError(t.Testing, err) + tx := t.DefaultWallet().CreateBasicOutputsEquallyFromInputs(txName, 1, inputName) issuingOptionsCopy[node.Name] = t.limitParentsCountInBlockOptions(issuingOptionsCopy[node.Name], iotago.BlockMaxParents) @@ -226,7 +213,8 @@ func (t *TestSuite) IssueBlockRowInSlot(prefix string, slot iotago.SlotIndex, ro t.assertParentsCommitmentExistFromBlockOptions(blockHeaderOptions, node) t.assertParentsExistFromBlockOptions(blockHeaderOptions, node) - b = t.IssueBasicBlockWithOptions(blockAlias, blockIssuers[index], node, mock.WithPayload(tx), mock.WithBasicBlockHeader(blockHeaderOptions...)) + t.DefaultWallet().SetDefaultNode(node) + b = t.IssueBasicBlockWithOptions(blockName, t.DefaultWallet(), mock.WithPayload(tx), mock.WithBasicBlockHeader(blockHeaderOptions...)) } blocksIssued = append(blocksIssued, b) } @@ -234,32 +222,32 @@ func (t *TestSuite) IssueBlockRowInSlot(prefix string, slot iotago.SlotIndex, ro return blocksIssued } -func (t *TestSuite) IssueBlockRowsInSlot(prefix string, slot iotago.SlotIndex, rows int, initialParentsPrefixAlias string, nodes []*mock.Node, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) (allBlocksIssued []*blocks.Block, lastBlockRow []*blocks.Block) { +func (t *TestSuite) IssueBlockRowsInSlot(prefix string, slot iotago.SlotIndex, rows int, initialParentsPrefix string, nodes []*mock.Node, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) (allBlocksIssued []*blocks.Block, lastBlockRow []*blocks.Block) { var blocksIssued, lastBlockRowIssued []*blocks.Block - parentsPrefixAlias := initialParentsPrefixAlias + parentsPrefix := initialParentsPrefix for row := 0; row < rows; row++ { if row > 0 { - parentsPrefixAlias = fmt.Sprintf("%s%d.%d", prefix, slot, row-1) + parentsPrefix = fmt.Sprintf("%s%d.%d", prefix, slot, row-1) } - lastBlockRowIssued = t.IssueBlockRowInSlot(prefix, slot, row, parentsPrefixAlias, nodes, issuingOptions) + lastBlockRowIssued = t.IssueBlockRowInSlot(prefix, slot, row, parentsPrefix, nodes, issuingOptions) blocksIssued = append(blocksIssued, lastBlockRowIssued...) } return blocksIssued, lastBlockRowIssued } -func (t *TestSuite) IssueBlocksAtSlots(prefix string, slots []iotago.SlotIndex, rowsPerSlot int, initialParentsPrefixAlias string, nodes []*mock.Node, waitForSlotsCommitted bool, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) (allBlocksIssued []*blocks.Block, lastBlockRow []*blocks.Block) { +func (t *TestSuite) IssueBlocksAtSlots(prefix string, slots []iotago.SlotIndex, rowsPerSlot int, initialParentsPrefix string, nodes []*mock.Node, waitForSlotsCommitted bool, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) (allBlocksIssued []*blocks.Block, lastBlockRow []*blocks.Block) { var blocksIssued, lastBlockRowIssued []*blocks.Block - parentsPrefixAlias := initialParentsPrefixAlias + parentsPrefix := initialParentsPrefix for i, slot := range slots { if i > 0 { - parentsPrefixAlias = fmt.Sprintf("%s%d.%d", prefix, slots[i-1], rowsPerSlot-1) + parentsPrefix = fmt.Sprintf("%s%d.%d", prefix, slots[i-1], rowsPerSlot-1) } - blocksInSlot, lastRowInSlot := t.IssueBlockRowsInSlot(prefix, slot, rowsPerSlot, parentsPrefixAlias, nodes, issuingOptions) + blocksInSlot, lastRowInSlot := t.IssueBlockRowsInSlot(prefix, slot, rowsPerSlot, parentsPrefix, nodes, issuingOptions) blocksIssued = append(blocksIssued, blocksInSlot...) lastBlockRowIssued = lastRowInSlot @@ -275,8 +263,8 @@ func (t *TestSuite) IssueBlocksAtSlots(prefix string, slots []iotago.SlotIndex, return blocksIssued, lastBlockRowIssued } -func (t *TestSuite) IssueBlocksAtEpoch(prefix string, epoch iotago.EpochIndex, rowsPerSlot int, initialParentsPrefixAlias string, nodes []*mock.Node, waitForSlotsCommitted bool, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) (allBlocksIssued []*blocks.Block, lastBlockRow []*blocks.Block) { - return t.IssueBlocksAtSlots(prefix, t.SlotsForEpoch(epoch), rowsPerSlot, initialParentsPrefixAlias, nodes, waitForSlotsCommitted, issuingOptions) +func (t *TestSuite) IssueBlocksAtEpoch(prefix string, epoch iotago.EpochIndex, rowsPerSlot int, initialParentsPrefix string, nodes []*mock.Node, waitForSlotsCommitted bool, issuingOptions map[string][]options.Option[mock.BlockHeaderParams]) (allBlocksIssued []*blocks.Block, lastBlockRow []*blocks.Block) { + return t.IssueBlocksAtSlots(prefix, t.SlotsForEpoch(epoch), rowsPerSlot, initialParentsPrefix, nodes, waitForSlotsCommitted, issuingOptions) } func (t *TestSuite) SlotsForEpoch(epoch iotago.EpochIndex) []iotago.SlotIndex { @@ -315,8 +303,8 @@ func (t *TestSuite) CommitUntilSlot(slot iotago.SlotIndex, parent *blocks.Block) committeeAtBlockSlot, exists := node.Protocol.MainEngineInstance().SybilProtection.SeatManager().CommitteeInSlot(nextBlockSlot) require.True(t.Testing, exists, "node: %s: does not have committee selected for slot %d", node.Name, nextBlockSlot) if committeeAtBlockSlot.HasAccount(node.Validator.AccountID) { - blockAlias := fmt.Sprintf("chain-%s-%d-%s", parent.ID().Alias(), chainIndex, node.Name) - tip = t.IssueValidationBlockAtSlot(blockAlias, nextBlockSlot, node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), node, tip.ID()) + blockName := fmt.Sprintf("chain-%s-%d-%s", parent.ID().Alias(), chainIndex, node.Name) + tip = t.IssueValidationBlockAtSlot(blockName, nextBlockSlot, node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), node, tip.ID()) } } // acceptance of nextBlockSlot @@ -324,8 +312,8 @@ func (t *TestSuite) CommitUntilSlot(slot iotago.SlotIndex, parent *blocks.Block) committeeAtBlockSlot, exists := node.Protocol.MainEngineInstance().SybilProtection.SeatManager().CommitteeInSlot(nextBlockSlot) require.True(t.Testing, exists, "node: %s: does not have committee selected for slot %d", node.Name, nextBlockSlot) if committeeAtBlockSlot.HasAccount(node.Validator.AccountID) { - blockAlias := fmt.Sprintf("chain-%s-%d-%s", parent.ID().Alias(), chainIndex+1, node.Name) - tip = t.IssueValidationBlockAtSlot(blockAlias, nextBlockSlot, node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), node, tip.ID()) + blockName := fmt.Sprintf("chain-%s-%d-%s", parent.ID().Alias(), chainIndex+1, node.Name) + tip = t.IssueValidationBlockAtSlot(blockName, nextBlockSlot, node.Protocol.MainEngineInstance().Storage.Settings().LatestCommitment().Commitment(), node, tip.ID()) } } diff --git a/pkg/testsuite/testsuite_options.go b/pkg/testsuite/testsuite_options.go index eec758168..6f467834e 100644 --- a/pkg/testsuite/testsuite_options.go +++ b/pkg/testsuite/testsuite_options.go @@ -5,7 +5,7 @@ import ( "time" "github.com/iotaledger/hive.go/runtime/options" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/pkg/testsuite/snapshotcreator" iotago "github.com/iotaledger/iota.go/v4" ) diff --git a/pkg/testsuite/transactions.go b/pkg/testsuite/transactions.go index f87e92e3a..23d2eb885 100644 --- a/pkg/testsuite/transactions.go +++ b/pkg/testsuite/transactions.go @@ -141,7 +141,7 @@ func (t *TestSuite) AssertTransactionInCacheConflicts(transactionConflicts map[* return ierrors.Errorf("AssertTransactionInCacheConflicts: %s: block %s does not exist", node.Name, transactionID) } - expectedConflictIDs := ds.NewSet(lo.Map(conflictAliases, t.TransactionFramework.TransactionID)...) + expectedConflictIDs := ds.NewSet(lo.Map(conflictAliases, t.DefaultWallet().TransactionID)...) actualConflictIDs := transactionFromCache.ConflictIDs() if expectedConflictIDs.Size() != actualConflictIDs.Size() { diff --git a/pkg/testsuite/transactions_framework.go b/pkg/testsuite/transactions_framework.go deleted file mode 100644 index 0419fda55..000000000 --- a/pkg/testsuite/transactions_framework.go +++ /dev/null @@ -1,603 +0,0 @@ -package testsuite - -import ( - "fmt" - "time" - - "github.com/iotaledger/hive.go/ierrors" - "github.com/iotaledger/hive.go/lo" - "github.com/iotaledger/hive.go/runtime/options" - "github.com/iotaledger/iota-core/pkg/protocol" - "github.com/iotaledger/iota-core/pkg/protocol/engine/utxoledger" - "github.com/iotaledger/iota-core/pkg/testsuite/mock" - iotago "github.com/iotaledger/iota.go/v4" - "github.com/iotaledger/iota.go/v4/builder" - "github.com/iotaledger/iota.go/v4/tpkg" -) - -type TransactionFramework struct { - apiProvider iotago.APIProvider - - wallet *mock.HDWallet - states map[string]*utxoledger.Output - signedTransactions map[string]*iotago.SignedTransaction - transactions map[string]*iotago.Transaction -} - -func NewTransactionFramework(protocol *protocol.Protocol, genesisSeed []byte) *TransactionFramework { - tf := &TransactionFramework{ - apiProvider: protocol, - states: make(map[string]*utxoledger.Output), - signedTransactions: make(map[string]*iotago.SignedTransaction), - transactions: make(map[string]*iotago.Transaction), - - wallet: mock.NewHDWallet("genesis", genesisSeed, 0), - } - - if err := protocol.MainEngineInstance().Ledger.ForEachUnspentOutput(func(output *utxoledger.Output) bool { - tf.states[fmt.Sprintf("Genesis:%d", output.OutputID().Index())] = output - return true - }); err != nil { - panic(err) - } - - if len(tf.states) == 0 { - panic("no genesis outputs found") - } - - return tf -} - -func (t *TransactionFramework) RegisterTransaction(alias string, transaction *iotago.Transaction) { - currentAPI := t.apiProvider.CommittedAPI() - (lo.PanicOnErr(transaction.ID())).RegisterAlias(alias) - - t.transactions[alias] = transaction - - for outputID, output := range lo.PanicOnErr(transaction.OutputsSet()) { - clonedOutput := output.Clone() - actualOutputID := iotago.OutputIDFromTransactionIDAndIndex(lo.PanicOnErr(transaction.ID()), outputID.Index()) - if clonedOutput.Type() == iotago.OutputAccount { - if accountOutput, ok := clonedOutput.(*iotago.AccountOutput); ok && accountOutput.AccountID == iotago.EmptyAccountID { - accountOutput.AccountID = iotago.AccountIDFromOutputID(actualOutputID) - } - } - - t.states[fmt.Sprintf("%s:%d", alias, outputID.Index())] = utxoledger.CreateOutput(t.apiProvider, actualOutputID, iotago.EmptyBlockID, currentAPI.TimeProvider().SlotFromTime(time.Now()), clonedOutput, lo.PanicOnErr(iotago.OutputIDProofFromTransaction(transaction, outputID.Index()))) - } -} - -func (t *TransactionFramework) RegisterSignedTransaction(alias string, signedTransaction *iotago.SignedTransaction) { - (lo.PanicOnErr(signedTransaction.ID())).RegisterAlias(alias) - - t.signedTransactions[alias] = signedTransaction -} - -func (t *TransactionFramework) CreateSignedTransactionWithOptions(alias string, signingWallets []*mock.HDWallet, opts ...options.Option[builder.TransactionBuilder]) (*iotago.SignedTransaction, error) { - currentAPI := t.apiProvider.CommittedAPI() - - walletKeys := make([]iotago.AddressKeys, 0, len(signingWallets)*2) - for _, wallet := range signingWallets { - inputPrivateKey, _ := wallet.KeyPair() - // add address keys for both types of directly unlockable addresses to simplify the TransactionFramework - //nolint:forcetypeassert - walletKeys = append(walletKeys, iotago.NewAddressKeysForEd25519Address(wallet.Address(iotago.AddressEd25519).(*iotago.Ed25519Address), inputPrivateKey)) - //nolint:forcetypeassert - walletKeys = append(walletKeys, iotago.NewAddressKeysForImplicitAccountCreationAddress(wallet.Address(iotago.AddressImplicitAccountCreation).(*iotago.ImplicitAccountCreationAddress), inputPrivateKey)) - } - - txBuilder := builder.NewTransactionBuilder(currentAPI) - txBuilder.WithTransactionCapabilities(iotago.TransactionCapabilitiesBitMaskWithCapabilities(iotago.WithTransactionCanDoAnything())) - // Always add a random payload to randomize transaction ID. - randomPayload := tpkg.Rand12ByteArray() - txBuilder.AddTaggedDataPayload(&iotago.TaggedData{Tag: randomPayload[:], Data: randomPayload[:]}) - - signedTransaction, err := options.Apply(txBuilder, opts).Build(iotago.NewInMemoryAddressSigner(walletKeys...)) - if err == nil { - t.RegisterSignedTransaction(alias, signedTransaction) - t.RegisterTransaction(alias, signedTransaction.Transaction) - } - - return signedTransaction, err -} - -func (t *TransactionFramework) CreateSimpleTransaction(alias string, outputCount int, inputAliases ...string) (*iotago.SignedTransaction, error) { - inputStates, outputStates, signingWallets := t.CreateBasicOutputsEqually(outputCount, inputAliases...) - - return t.CreateSignedTransactionWithOptions(alias, signingWallets, WithInputs(inputStates), WithOutputs(outputStates)) -} - -func (t *TransactionFramework) CreateBasicOutputsEqually(outputCount int, inputAliases ...string) (consumedInputs utxoledger.Outputs, outputs iotago.Outputs[iotago.Output], signingWallets []*mock.HDWallet) { - inputStates := make([]*utxoledger.Output, 0, len(inputAliases)) - totalInputAmounts := iotago.BaseToken(0) - totalInputStoredMana := iotago.Mana(0) - - for _, inputAlias := range inputAliases { - output := t.Output(inputAlias) - inputStates = append(inputStates, output) - totalInputAmounts += output.BaseTokenAmount() - totalInputStoredMana += output.StoredMana() - } - - manaAmount := totalInputStoredMana / iotago.Mana(outputCount) - remainderMana := totalInputStoredMana - - tokenAmount := totalInputAmounts / iotago.BaseToken(outputCount) - remainderFunds := totalInputAmounts - - outputStates := make(iotago.Outputs[iotago.Output], 0, outputCount) - for i := 0; i < outputCount; i++ { - if i+1 == outputCount { - tokenAmount = remainderFunds - manaAmount = remainderMana - } - remainderFunds -= tokenAmount - remainderMana -= manaAmount - - outputStates = append(outputStates, &iotago.BasicOutput{ - Amount: tokenAmount, - Mana: manaAmount, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: t.DefaultAddress()}, - }, - Features: iotago.BasicOutputFeatures{}, - }) - } - - return inputStates, outputStates, []*mock.HDWallet{t.wallet} -} - -func (t *TransactionFramework) CreateBasicOutputs(amountDistribution []iotago.BaseToken, manaDistribution []iotago.Mana, inputAliases ...string) (consumedInputs utxoledger.Outputs, outputs iotago.Outputs[iotago.Output], signingWallets []*mock.HDWallet) { - if len(amountDistribution) != len(manaDistribution) { - panic("amount and mana distributions should have the same length") - } - - inputStates := make([]*utxoledger.Output, 0, len(inputAliases)) - totalInputAmounts := iotago.BaseToken(0) - totalInputStoredMana := iotago.Mana(0) - - for _, inputAlias := range inputAliases { - output := t.Output(inputAlias) - inputStates = append(inputStates, output) - totalInputAmounts += output.BaseTokenAmount() - totalInputStoredMana += output.StoredMana() - } - - if lo.Sum(amountDistribution...) != totalInputAmounts { - panic("amount on input and output side must be equal") - } - - outputStates := make(iotago.Outputs[iotago.Output], 0, len(amountDistribution)) - for idx, outputAmount := range amountDistribution { - outputStates = append(outputStates, &iotago.BasicOutput{ - Amount: outputAmount, - Mana: manaDistribution[idx], - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: t.DefaultAddress()}, - }, - Features: iotago.BasicOutputFeatures{}, - }) - } - - return inputStates, outputStates, []*mock.HDWallet{t.wallet} -} - -func (t *TransactionFramework) CreateAccountFromInput(inputAlias string, opts ...options.Option[builder.AccountOutputBuilder]) (utxoledger.Outputs, iotago.Outputs[iotago.Output], []*mock.HDWallet) { - input := t.Output(inputAlias) - - accountOutput := options.Apply(builder.NewAccountOutputBuilder(t.DefaultAddress(), t.DefaultAddress(), input.BaseTokenAmount()). - Mana(input.StoredMana()). - StateController(t.DefaultAddress()). - Governor(t.DefaultAddress()), - opts).MustBuild() - - outputStates := iotago.Outputs[iotago.Output]{accountOutput} - - // if amount was set by options, a remainder output needs to be created - if accountOutput.Amount != input.BaseTokenAmount() { - outputStates = append(outputStates, &iotago.BasicOutput{ - Amount: input.BaseTokenAmount() - accountOutput.Amount, - Mana: input.StoredMana() - accountOutput.Mana, - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: t.DefaultAddress()}, - }, - Features: iotago.BasicOutputFeatures{}, - }) - } - - return utxoledger.Outputs{input}, outputStates, []*mock.HDWallet{t.wallet} -} - -// CreateImplicitAccountFromInput creates an implicit account output. -func (t *TransactionFramework) CreateImplicitAccountFromInput(inputAlias string) (utxoledger.Outputs, iotago.Outputs[iotago.Output], *iotago.ImplicitAccountCreationAddress, []*mock.HDWallet) { - input := t.Output(inputAlias) - - //nolint:forcetypeassert - implicitAccountAddress := t.DefaultAddress(iotago.AddressImplicitAccountCreation).(*iotago.ImplicitAccountCreationAddress) - - basicOutput := &iotago.BasicOutput{ - Amount: input.BaseTokenAmount(), - Mana: input.StoredMana(), - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: implicitAccountAddress}, - }, - Features: iotago.BasicOutputFeatures{}, - } - - return utxoledger.Outputs{input}, iotago.Outputs[iotago.Output]{basicOutput}, implicitAccountAddress, []*mock.HDWallet{t.wallet} -} - -// CreateDelegationFromInput creates a new DelegationOutput with given options from an input. If the remainder Output -// is not created, then StoredMana from the input is not passed and can potentially be burned. -// In order not to burn it, it needs to be assigned manually in another output in the transaction. -func (t *TransactionFramework) CreateDelegationFromInput(inputAlias string, opts ...options.Option[builder.DelegationOutputBuilder]) (utxoledger.Outputs, iotago.Outputs[iotago.Output], []*mock.HDWallet) { - input := t.Output(inputAlias) - - delegationOutput := options.Apply(builder.NewDelegationOutputBuilder(&iotago.AccountAddress{}, t.DefaultAddress(), input.BaseTokenAmount()). - DelegatedAmount(input.BaseTokenAmount()), - opts).MustBuild() - - if delegationOutput.ValidatorAddress.AccountID() == iotago.EmptyAccountID || - delegationOutput.DelegatedAmount == 0 || - delegationOutput.StartEpoch == 0 { - panic(fmt.Sprintf("delegation output created incorrectly %+v", delegationOutput)) - } - - outputStates := iotago.Outputs[iotago.Output]{delegationOutput} - - // if options set an Amount, a remainder output needs to be created - if delegationOutput.Amount != input.BaseTokenAmount() { - outputStates = append(outputStates, &iotago.BasicOutput{ - Amount: input.BaseTokenAmount() - delegationOutput.Amount, - Mana: input.StoredMana(), - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: t.DefaultAddress()}, - }, - Features: iotago.BasicOutputFeatures{}, - }) - } - - return utxoledger.Outputs{input}, outputStates, []*mock.HDWallet{t.wallet} -} - -// DelayedClaimingTransition transitions DelegationOutput into delayed claiming state by setting DelegationID and EndEpoch. -func (t *TransactionFramework) DelayedClaimingTransition(inputAlias string, delegationEndEpoch iotago.EpochIndex) (utxoledger.Outputs, iotago.Outputs[iotago.Output], []*mock.HDWallet) { - input := t.Output(inputAlias) - if input.OutputType() != iotago.OutputDelegation { - panic(ierrors.Errorf("%s is not a delegation output, cannot transition to delayed claiming state", inputAlias)) - } - - prevOutput, ok := input.Output().Clone().(*iotago.DelegationOutput) - if !ok { - panic(ierrors.Errorf("cloned output %s is not a delegation output, cannot transition to delayed claiming state", inputAlias)) - } - - delegationBuilder := builder.NewDelegationOutputBuilderFromPrevious(prevOutput).EndEpoch(delegationEndEpoch) - if prevOutput.DelegationID == iotago.EmptyDelegationID() { - delegationBuilder.DelegationID(iotago.DelegationIDFromOutputID(input.OutputID())) - } - - return utxoledger.Outputs{input}, iotago.Outputs[iotago.Output]{delegationBuilder.MustBuild()}, []*mock.HDWallet{t.wallet} -} - -func (t *TransactionFramework) DestroyAccount(alias string) (consumedInputs *utxoledger.Output, outputs iotago.Outputs[iotago.Output], signingWallets []*mock.HDWallet) { - output := t.Output(alias) - - outputStates := iotago.Outputs[iotago.Output]{&iotago.BasicOutput{ - Amount: output.BaseTokenAmount(), - Mana: output.StoredMana(), - Conditions: iotago.BasicOutputUnlockConditions{ - &iotago.AddressUnlockCondition{Address: t.DefaultAddress()}, - }, - Features: iotago.BasicOutputFeatures{}, - }} - - return output, outputStates, []*mock.HDWallet{t.wallet} -} - -func (t *TransactionFramework) TransitionAccount(alias string, opts ...options.Option[builder.AccountOutputBuilder]) (consumedInput *utxoledger.Output, outputs iotago.Outputs[iotago.Output], signingWallets []*mock.HDWallet) { - output, exists := t.states[alias] - if !exists { - panic(fmt.Sprintf("account with alias %s does not exist", alias)) - } - - accountOutput, ok := output.Output().Clone().(*iotago.AccountOutput) - if !ok { - panic(fmt.Sprintf("output with alias %s is not *iotago.AccountOutput", alias)) - } - - accountBuilder := builder.NewAccountOutputBuilderFromPrevious(accountOutput) - accountOutput = options.Apply(accountBuilder, opts).MustBuild() - - return output, iotago.Outputs[iotago.Output]{accountOutput}, []*mock.HDWallet{t.wallet} -} - -func (t *TransactionFramework) TransitionImplicitAccountToAccountOutput(alias string, opts ...options.Option[builder.AccountOutputBuilder]) (consumedInput utxoledger.Outputs, outputs iotago.Outputs[iotago.Output], signingWallets []*mock.HDWallet) { - input, exists := t.states[alias] - if !exists { - panic(fmt.Sprintf("output with alias %s does not exist", alias)) - } - - basicOutput, isBasic := input.Output().(*iotago.BasicOutput) - if !isBasic { - panic(fmt.Sprintf("output with alias %s is not *iotago.BasicOutput", alias)) - } - if basicOutput.UnlockConditionSet().Address().Address.Type() != iotago.AddressImplicitAccountCreation { - panic(fmt.Sprintf("output with alias %s is not an implicit account", alias)) - } - - accountOutput := options.Apply(builder.NewAccountOutputBuilder(t.DefaultAddress(), t.DefaultAddress(), input.BaseTokenAmount()). - Mana(input.StoredMana()). - AccountID(iotago.AccountIDFromOutputID(input.OutputID())), - opts).MustBuild() - - return utxoledger.Outputs{input}, iotago.Outputs[iotago.Output]{accountOutput}, []*mock.HDWallet{t.wallet} -} - -func (t *TransactionFramework) Output(alias string) *utxoledger.Output { - output, exists := t.states[alias] - if !exists { - panic(ierrors.Errorf("output with given alias does not exist %s", alias)) - } - - return output -} - -func (t *TransactionFramework) OutputID(alias string) iotago.OutputID { - return t.Output(alias).OutputID() -} - -func (t *TransactionFramework) SignedTransaction(alias string) *iotago.SignedTransaction { - transaction, exists := t.signedTransactions[alias] - if !exists { - panic(ierrors.Errorf("transaction with given alias does not exist %s", alias)) - } - - return transaction -} - -func (t *TransactionFramework) SignedTransactionID(alias string) iotago.SignedTransactionID { - return lo.PanicOnErr(t.SignedTransaction(alias).ID()) -} - -func (t *TransactionFramework) SignedTransactions(aliases ...string) []*iotago.SignedTransaction { - return lo.Map(aliases, t.SignedTransaction) -} - -func (t *TransactionFramework) SignedTransactionIDs(aliases ...string) []iotago.SignedTransactionID { - return lo.Map(aliases, t.SignedTransactionID) -} - -func (t *TransactionFramework) Transaction(alias string) *iotago.Transaction { - transaction, exists := t.transactions[alias] - if !exists { - panic(ierrors.Errorf("transaction with given alias does not exist %s", alias)) - } - - return transaction -} - -func (t *TransactionFramework) TransactionID(alias string) iotago.TransactionID { - return lo.PanicOnErr(t.Transaction(alias).ID()) -} - -func (t *TransactionFramework) Transactions(aliases ...string) []*iotago.Transaction { - return lo.Map(aliases, t.Transaction) -} - -func (t *TransactionFramework) TransactionIDs(aliases ...string) []iotago.TransactionID { - return lo.Map(aliases, t.TransactionID) -} - -func (t *TransactionFramework) DefaultAddress(addressType ...iotago.AddressType) iotago.Address { - return t.wallet.Address(addressType...) -} - -// DelegationOutput options - -func WithDelegatedAmount(delegatedAmount iotago.BaseToken) options.Option[builder.DelegationOutputBuilder] { - return func(delegationBuilder *builder.DelegationOutputBuilder) { - delegationBuilder.DelegatedAmount(delegatedAmount) - } -} - -func WithDelegatedValidatorAddress(validatorAddress *iotago.AccountAddress) options.Option[builder.DelegationOutputBuilder] { - return func(delegationBuilder *builder.DelegationOutputBuilder) { - delegationBuilder.ValidatorAddress(validatorAddress) - } -} - -func WithDelegationStartEpoch(startEpoch iotago.EpochIndex) options.Option[builder.DelegationOutputBuilder] { - return func(delegationBuilder *builder.DelegationOutputBuilder) { - delegationBuilder.StartEpoch(startEpoch) - } -} - -func WithDelegationEndEpoch(endEpoch iotago.EpochIndex) options.Option[builder.DelegationOutputBuilder] { - return func(delegationBuilder *builder.DelegationOutputBuilder) { - delegationBuilder.EndEpoch(endEpoch) - } -} - -func WithDelegationConditions(delegationConditions iotago.DelegationOutputUnlockConditions) options.Option[builder.DelegationOutputBuilder] { - return func(delegationBuilder *builder.DelegationOutputBuilder) { - delegationBuilder.Address(delegationConditions.MustSet().Address().Address) - } -} - -func WithDelegationAmount(amount iotago.BaseToken) options.Option[builder.DelegationOutputBuilder] { - return func(delegationBuilder *builder.DelegationOutputBuilder) { - delegationBuilder.Amount(amount) - } -} - -// BlockIssuer options - -func WithBlockIssuerFeature(keys iotago.BlockIssuerKeys, expirySlot iotago.SlotIndex) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - accountBuilder.BlockIssuer(keys, expirySlot) - } -} - -func WithAddBlockIssuerKey(key iotago.BlockIssuerKey) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - transition := accountBuilder.GovernanceTransition() - transition.BlockIssuerTransition().AddKeys(key) - } -} - -func WithBlockIssuerKeys(keys iotago.BlockIssuerKeys) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - transition := accountBuilder.GovernanceTransition() - transition.BlockIssuerTransition().Keys(keys) - } -} - -func WithBlockIssuerExpirySlot(expirySlot iotago.SlotIndex) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - transition := accountBuilder.GovernanceTransition() - transition.BlockIssuerTransition().ExpirySlot(expirySlot) - } -} - -func WithStakingFeature(amount iotago.BaseToken, fixedCost iotago.Mana, startEpoch iotago.EpochIndex, optEndEpoch ...iotago.EpochIndex) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - accountBuilder.Staking(amount, fixedCost, startEpoch, optEndEpoch...) - } -} - -// Account options - -func WithAccountMana(mana iotago.Mana) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - accountBuilder.Mana(mana) - } -} - -func WithAccountAmount(amount iotago.BaseToken) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - accountBuilder.Amount(amount) - } -} - -func WithAccountIncreasedFoundryCounter(diff uint32) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - accountBuilder.FoundriesToGenerate(diff) - } -} - -func WithAccountImmutableFeatures(features iotago.AccountOutputImmFeatures) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - for _, feature := range features.MustSet() { - switch feature.Type() { - case iotago.FeatureMetadata: - //nolint:forcetypeassert - accountBuilder.ImmutableMetadata(feature.(*iotago.MetadataFeature).Data) - case iotago.FeatureSender: - //nolint:forcetypeassert - accountBuilder.ImmutableSender(feature.(*iotago.SenderFeature).Address) - } - } - } -} - -func WithAccountConditions(conditions iotago.AccountOutputUnlockConditions) options.Option[builder.AccountOutputBuilder] { - return func(accountBuilder *builder.AccountOutputBuilder) { - for _, condition := range conditions.MustSet() { - switch condition.Type() { - case iotago.UnlockConditionStateControllerAddress: - //nolint:forcetypeassert - accountBuilder.StateController(condition.(*iotago.StateControllerAddressUnlockCondition).Address) - case iotago.UnlockConditionGovernorAddress: - //nolint:forcetypeassert - accountBuilder.Governor(condition.(*iotago.GovernorAddressUnlockCondition).Address) - } - } - } -} - -// TransactionBuilder options - -func WithInputs(inputs utxoledger.Outputs) options.Option[builder.TransactionBuilder] { - return func(txBuilder *builder.TransactionBuilder) { - for _, input := range inputs { - switch input.OutputType() { - case iotago.OutputFoundry: - // For foundries we need to unlock the alias - txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: input.Output().UnlockConditionSet().ImmutableAccount().Address, - InputID: input.OutputID(), - Input: input.Output(), - }) - case iotago.OutputAccount: - // For alias we need to unlock the state controller - txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: input.Output().UnlockConditionSet().StateControllerAddress().Address, - InputID: input.OutputID(), - Input: input.Output(), - }) - default: - txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: input.Output().UnlockConditionSet().Address().Address, - InputID: input.OutputID(), - Input: input.Output(), - }) - } - } - } -} - -func WithAccountInput(input *utxoledger.Output, governorTransition bool) options.Option[builder.TransactionBuilder] { - return func(txBuilder *builder.TransactionBuilder) { - switch input.OutputType() { - case iotago.OutputAccount: - address := input.Output().UnlockConditionSet().StateControllerAddress().Address - if governorTransition { - address = input.Output().UnlockConditionSet().GovernorAddress().Address - } - txBuilder.AddInput(&builder.TxInput{ - UnlockTarget: address, - InputID: input.OutputID(), - Input: input.Output(), - }) - default: - panic("only OutputAccount can be added as account input") - } - } -} - -func WithAllotments(allotments iotago.Allotments) options.Option[builder.TransactionBuilder] { - return func(txBuilder *builder.TransactionBuilder) { - for _, allotment := range allotments { - txBuilder.IncreaseAllotment(allotment.AccountID, allotment.Mana) - } - } -} - -func WithSlotCreated(creationSlot iotago.SlotIndex) options.Option[builder.TransactionBuilder] { - return func(txBuilder *builder.TransactionBuilder) { - txBuilder.SetCreationSlot(creationSlot) - } -} - -func WithContextInputs(contextInputs iotago.TxEssenceContextInputs) options.Option[builder.TransactionBuilder] { - return func(txBuilder *builder.TransactionBuilder) { - for _, input := range contextInputs { - txBuilder.AddContextInput(input) - } - } -} - -func WithOutputs(outputs iotago.Outputs[iotago.Output]) options.Option[builder.TransactionBuilder] { - return func(txBuilder *builder.TransactionBuilder) { - for _, output := range outputs { - txBuilder.AddOutput(output) - } - } -} - -func WithTaggedDataPayload(payload *iotago.TaggedData) options.Option[builder.TransactionBuilder] { - return func(txBuilder *builder.TransactionBuilder) { - txBuilder.AddTaggedDataPayload(payload) - } -} diff --git a/pkg/toolset/ed25519.go b/pkg/toolset/ed25519.go new file mode 100644 index 000000000..bae379fbf --- /dev/null +++ b/pkg/toolset/ed25519.go @@ -0,0 +1,172 @@ +package toolset + +import ( + "crypto/ed25519" + "encoding/hex" + "fmt" + "os" + + flag "github.com/spf13/pflag" + "github.com/wollac/iota-crypto-demo/pkg/bip32path" + "github.com/wollac/iota-crypto-demo/pkg/bip39" + "github.com/wollac/iota-crypto-demo/pkg/slip10" + "github.com/wollac/iota-crypto-demo/pkg/slip10/eddsa" + + "github.com/iotaledger/hive.go/app/configuration" + "github.com/iotaledger/hive.go/crypto" + iotago "github.com/iotaledger/iota.go/v4" +) + +func printEd25519Info(mnemonic bip39.Mnemonic, path bip32path.Path, prvKey ed25519.PrivateKey, pubKey ed25519.PublicKey, hrp iotago.NetworkPrefix, outputJSON bool) error { + addr := iotago.Ed25519AddressFromPubKey(pubKey) + + type keys struct { + BIP39 string `json:"mnemonic,omitempty"` + BIP32 string `json:"path,omitempty"` + PrivateKey string `json:"privateKey,omitempty"` + PublicKey string `json:"publicKey"` + Ed25519Address string `json:"ed25519"` + Bech32Address string `json:"bech32"` + } + + k := keys{ + PublicKey: hex.EncodeToString(pubKey), + Ed25519Address: hex.EncodeToString(addr[:]), + Bech32Address: addr.Bech32(hrp), + } + + if prvKey != nil { + k.PrivateKey = hex.EncodeToString(prvKey) + } + + if mnemonic != nil { + k.BIP39 = mnemonic.String() + k.BIP32 = path.String() + } + + if outputJSON { + return printJSON(k) + } + + if len(k.BIP39) > 0 { + fmt.Println("Your seed BIP39 mnemonic: ", k.BIP39) + fmt.Println() + fmt.Println("Your BIP32 path: ", k.BIP32) + } + + if k.PrivateKey != "" { + fmt.Println("Your ed25519 private key: ", k.PrivateKey) + } + + fmt.Println("Your ed25519 public key: ", k.PublicKey) + fmt.Println("Your ed25519 address: ", k.Ed25519Address) + fmt.Println("Your bech32 address: ", k.Bech32Address) + + return nil +} + +func generateEd25519Key(args []string) error { + fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError) + hrpFlag := fs.String(FlagToolHRP, string(iotago.PrefixTestnet), "the HRP which should be used for the Bech32 address") + bip32Path := fs.String(FlagToolBIP32Path, "m/44'/4218'/0'/0'/0'", "the BIP32 path that should be used to derive keys from seed") + mnemonicFlag := fs.String(FlagToolMnemonic, "", "the BIP-39 mnemonic sentence that should be used to derive the seed from (optional)") + outputJSONFlag := fs.Bool(FlagToolOutputJSON, false, FlagToolDescriptionOutputJSON) + + fs.Usage = func() { + _, _ = fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolEd25519Key) + fs.PrintDefaults() + println(fmt.Sprintf("\nexample: %s --%s %s", + ToolEd25519Key, + FlagToolHRP, + string(iotago.PrefixTestnet))) + } + + if err := parseFlagSet(fs, args); err != nil { + return err + } + + if len(*hrpFlag) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolHRP) + } + + if len(*bip32Path) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolBIP32Path) + } + + var mnemonicSentence bip39.Mnemonic + if len(*mnemonicFlag) == 0 { + // Generate random entropy by using ed25519 key generation and using the private key seed (32 bytes) + _, random, err := ed25519.GenerateKey(nil) + if err != nil { + return err + } + entropy := random.Seed() + + mnemonicSentence, err = bip39.EntropyToMnemonic(entropy) + if err != nil { + return err + } + } else { + mnemonicSentence = bip39.ParseMnemonic(*mnemonicFlag) + if len(mnemonicSentence) != 24 { + return fmt.Errorf("'%s' contains an invalid sentence length. Mnemonic should be 24 words", FlagToolMnemonic) + } + } + + path, err := bip32path.ParsePath(*bip32Path) + if err != nil { + return err + } + + seed, err := bip39.MnemonicToSeed(mnemonicSentence, "") + if err != nil { + return err + } + + key, err := slip10.DeriveKeyFromPath(seed, eddsa.Ed25519(), path) + if err != nil { + return err + } + pubKey, prvKey := key.Key.(eddsa.Seed).Ed25519Key() + + return printEd25519Info(mnemonicSentence, path, ed25519.PrivateKey(prvKey), ed25519.PublicKey(pubKey), iotago.NetworkPrefix(*hrpFlag), *outputJSONFlag) +} + +func generateEd25519Address(args []string) error { + fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError) + hrpFlag := fs.String(FlagToolHRP, string(iotago.PrefixTestnet), "the HRP which should be used for the Bech32 address") + publicKeyFlag := fs.String(FlagToolPublicKey, "", "an ed25519 public key") + outputJSONFlag := fs.Bool(FlagToolOutputJSON, false, FlagToolDescriptionOutputJSON) + + fs.Usage = func() { + _, _ = fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolEd25519Addr) + fs.PrintDefaults() + println(fmt.Sprintf("\nexample: %s --%s %s --%s %s", + ToolEd25519Addr, + FlagToolHRP, + string(iotago.PrefixTestnet), + FlagToolPublicKey, + "[PUB_KEY]", + )) + } + + if err := parseFlagSet(fs, args); err != nil { + return err + } + + if len(*hrpFlag) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolHRP) + } + + if len(*publicKeyFlag) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolPublicKey) + } + + // parse pubkey + pubKey, err := crypto.ParseEd25519PublicKeyFromString(*publicKeyFlag) + if err != nil { + return fmt.Errorf("can't decode '%s': %w", FlagToolPublicKey, err) + } + + return printEd25519Info(nil, nil, nil, pubKey, iotago.NetworkPrefix(*hrpFlag), *outputJSONFlag) +} diff --git a/pkg/toolset/jwt.go b/pkg/toolset/jwt.go new file mode 100644 index 000000000..9585eee8c --- /dev/null +++ b/pkg/toolset/jwt.go @@ -0,0 +1,109 @@ +package toolset + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/libp2p/go-libp2p/core/peer" + flag "github.com/spf13/pflag" + + "github.com/iotaledger/hive.go/app/configuration" + hivep2p "github.com/iotaledger/hive.go/crypto/p2p" + "github.com/iotaledger/hive.go/crypto/pem" + "github.com/iotaledger/iota-core/components/p2p" + "github.com/iotaledger/iota-core/pkg/jwt" +) + +func generateJWTApiToken(args []string) error { + + fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError) + databasePathFlag := fs.String(FlagToolDatabasePath, DefaultValueP2PDatabasePath, "the path to the p2p database folder") + apiJWTSaltFlag := fs.String(FlagToolSalt, DefaultValueAPIJWTTokenSalt, "salt used inside the JWT tokens for the REST API") + outputJSONFlag := fs.Bool(FlagToolOutputJSON, false, FlagToolDescriptionOutputJSON) + + fs.Usage = func() { + _, _ = fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolJWTApi) + fs.PrintDefaults() + println(fmt.Sprintf("\nexample: %s --%s %s --%s %s", + ToolJWTApi, + FlagToolDatabasePath, + DefaultValueP2PDatabasePath, + FlagToolSalt, + DefaultValueAPIJWTTokenSalt)) + } + + if err := parseFlagSet(fs, args); err != nil { + return err + } + + if len(*databasePathFlag) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolDatabasePath) + } + if len(*apiJWTSaltFlag) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolSalt) + } + + databasePath := *databasePathFlag + privKeyFilePath := filepath.Join(databasePath, p2p.IdentityPrivateKeyFileName) + + salt := *apiJWTSaltFlag + + _, err := os.Stat(privKeyFilePath) + switch { + case os.IsNotExist(err): + // private key does not exist + return fmt.Errorf("private key file (%s) does not exist", privKeyFilePath) + + case err == nil || os.IsExist(err): + // private key file exists + + default: + return fmt.Errorf("unable to check private key file (%s): %w", privKeyFilePath, err) + } + + privKey, err := pem.ReadEd25519PrivateKeyFromPEMFile(privKeyFilePath) + if err != nil { + return fmt.Errorf("reading private key file for peer identity failed: %w", err) + } + + libp2pPrivKey, err := hivep2p.Ed25519PrivateKeyToLibp2pPrivateKey(privKey) + if err != nil { + return fmt.Errorf("reading private key file for peer identity failed: %w", err) + } + + peerID, err := peer.IDFromPublicKey(libp2pPrivKey.GetPublic()) + if err != nil { + return fmt.Errorf("unable to get peer identity from public key: %w", err) + } + + // API tokens do not expire. + jwtAuth, err := jwt.NewAuth(salt, + 0, + peerID.String(), + libp2pPrivKey, + ) + if err != nil { + return fmt.Errorf("JWT auth initialization failed: %w", err) + } + + jwtToken, err := jwtAuth.IssueJWT() + if err != nil { + return fmt.Errorf("issuing JWT token failed: %w", err) + } + + if *outputJSONFlag { + + result := struct { + JWT string `json:"jwt"` + }{ + JWT: jwtToken, + } + + return printJSON(result) + } + + fmt.Println("Your API JWT token: ", jwtToken) + + return nil +} diff --git a/pkg/toolset/node_info.go b/pkg/toolset/node_info.go new file mode 100644 index 000000000..058a3e6d6 --- /dev/null +++ b/pkg/toolset/node_info.go @@ -0,0 +1,50 @@ +package toolset + +import ( + "context" + "fmt" + "os" + + flag "github.com/spf13/pflag" + + "github.com/iotaledger/hive.go/app/configuration" + "github.com/iotaledger/iota.go/v4/nodeclient" +) + +func nodeInfo(args []string) error { + fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError) + nodeURLFlag := fs.String(FlagToolNodeURL, "http://localhost:14265", "URL of the node (optional)") + outputJSONFlag := fs.Bool(FlagToolOutputJSON, false, FlagToolDescriptionOutputJSON) + + fs.Usage = func() { + _, _ = fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolNodeInfo) + fs.PrintDefaults() + println(fmt.Sprintf("\nexample: %s --%s %s", + ToolNodeInfo, + FlagToolNodeURL, + "http://192.168.1.221:14265", + )) + } + + if err := parseFlagSet(fs, args); err != nil { + return err + } + + client, err := nodeclient.New(*nodeURLFlag) + if err != nil { + return err + } + + info, err := client.Info(context.Background()) + if err != nil { + return err + } + + if *outputJSONFlag { + return printJSON(info) + } + + fmt.Printf("Name: %s\nVersion: %s\nLatestAcceptedBlockSlot: %d\nLatestConfirmedBlockSlot: %d\nIsHealthy: %s\n", info.Name, info.Version, info.Status.LatestAcceptedBlockSlot, info.Status.LatestConfirmedBlockSlot, yesOrNo(info.Status.IsHealthy)) + + return nil +} diff --git a/pkg/toolset/p2p_identity_extract.go b/pkg/toolset/p2p_identity_extract.go new file mode 100644 index 000000000..45a364d10 --- /dev/null +++ b/pkg/toolset/p2p_identity_extract.go @@ -0,0 +1,66 @@ +package toolset + +import ( + "fmt" + "os" + "path/filepath" + + flag "github.com/spf13/pflag" + + "github.com/iotaledger/hive.go/app/configuration" + hivep2p "github.com/iotaledger/hive.go/crypto/p2p" + "github.com/iotaledger/hive.go/crypto/pem" + "github.com/iotaledger/iota-core/components/p2p" +) + +func extractP2PIdentity(args []string) error { + + fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError) + databasePathFlag := fs.String(FlagToolDatabasePath, DefaultValueP2PDatabasePath, "the path to the p2p database folder") + outputJSONFlag := fs.Bool(FlagToolOutputJSON, false, FlagToolDescriptionOutputJSON) + + fs.Usage = func() { + _, _ = fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolP2PExtractIdentity) + fs.PrintDefaults() + println(fmt.Sprintf("\nexample: %s --%s %s", + ToolP2PExtractIdentity, + FlagToolDatabasePath, + DefaultValueP2PDatabasePath)) + } + + if err := parseFlagSet(fs, args); err != nil { + return err + } + + if len(*databasePathFlag) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolDatabasePath) + } + + databasePath := *databasePathFlag + privKeyFilePath := filepath.Join(databasePath, p2p.IdentityPrivateKeyFileName) + + _, err := os.Stat(privKeyFilePath) + switch { + case os.IsNotExist(err): + // private key does not exist + return fmt.Errorf("private key file (%s) does not exist", privKeyFilePath) + + case err == nil || os.IsExist(err): + // private key file exists + + default: + return fmt.Errorf("unable to check private key file (%s): %w", privKeyFilePath, err) + } + + privKey, err := pem.ReadEd25519PrivateKeyFromPEMFile(privKeyFilePath) + if err != nil { + return fmt.Errorf("reading private key file for peer identity failed: %w", err) + } + + libp2pPrivKey, err := hivep2p.Ed25519PrivateKeyToLibp2pPrivateKey(privKey) + if err != nil { + return err + } + + return printP2PIdentity(libp2pPrivKey, libp2pPrivKey.GetPublic(), *outputJSONFlag) +} diff --git a/pkg/toolset/p2p_identity_gen.go b/pkg/toolset/p2p_identity_gen.go new file mode 100644 index 000000000..b376fd5e8 --- /dev/null +++ b/pkg/toolset/p2p_identity_gen.go @@ -0,0 +1,136 @@ +package toolset + +import ( + "crypto/ed25519" + "encoding/hex" + "fmt" + "os" + "path/filepath" + + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/mr-tron/base58" + flag "github.com/spf13/pflag" + + "github.com/iotaledger/hive.go/app/configuration" + hivecrypto "github.com/iotaledger/hive.go/crypto" + "github.com/iotaledger/hive.go/crypto/pem" + "github.com/iotaledger/iota-core/components/p2p" + "github.com/iotaledger/iota.go/v4/hexutil" +) + +func generateP2PIdentity(args []string) error { + + fs := configuration.NewUnsortedFlagSet("", flag.ContinueOnError) + databasePathFlag := fs.String(FlagToolOutputPath, DefaultValueP2PDatabasePath, "the path to the output folder") + privateKeyFlag := fs.String(FlagToolPrivateKey, "", "the p2p private key") + outputJSONFlag := fs.Bool(FlagToolOutputJSON, false, FlagToolDescriptionOutputJSON) + + fs.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage of %s:\n", ToolP2PIdentityGen) + fs.PrintDefaults() + println(fmt.Sprintf("\nexample: %s --%s %s --%s %s", + ToolP2PIdentityGen, + FlagToolDatabasePath, + DefaultValueP2PDatabasePath, + FlagToolPrivateKey, + "[PRIVATE_KEY]", + )) + } + + if err := parseFlagSet(fs, args); err != nil { + return err + } + + if len(*databasePathFlag) == 0 { + return fmt.Errorf("'%s' not specified", FlagToolDatabasePath) + } + + databasePath := *databasePathFlag + privKeyFilePath := filepath.Join(databasePath, p2p.IdentityPrivateKeyFileName) + + if err := os.MkdirAll(databasePath, 0700); err != nil { + return fmt.Errorf("could not create peer store database dir '%s': %w", databasePath, err) + } + + _, err := os.Stat(privKeyFilePath) + switch { + case err == nil || os.IsExist(err): + // private key file already exists + return fmt.Errorf("private key file (%s) already exists", privKeyFilePath) + + case os.IsNotExist(err): + // private key file does not exist, create a new one + + default: + return fmt.Errorf("unable to check private key file (%s): %w", privKeyFilePath, err) + } + + var privKey ed25519.PrivateKey + if privateKeyFlag != nil && len(*privateKeyFlag) > 0 { + privKey, err = hivecrypto.ParseEd25519PrivateKeyFromString(*privateKeyFlag) + if err != nil { + return fmt.Errorf("invalid private key given '%s': %w", *privateKeyFlag, err) + } + } else { + // create identity + _, privKey, err = ed25519.GenerateKey(nil) + if err != nil { + return fmt.Errorf("unable to generate Ed25519 private key for peer identity: %w", err) + } + } + + libp2pPrivKey, libp2pPubKey, err := crypto.KeyPairFromStdKey(&privKey) + if err != nil { + return fmt.Errorf("unable to convert given private key '%s': %w", hexutil.EncodeHex(privKey), err) + } + + if err := pem.WriteEd25519PrivateKeyToPEMFile(privKeyFilePath, privKey); err != nil { + return fmt.Errorf("writing private key file for peer identity failed: %w", err) + } + + return printP2PIdentity(libp2pPrivKey, libp2pPubKey, *outputJSONFlag) +} + +func printP2PIdentity(libp2pPrivKey crypto.PrivKey, libp2pPubKey crypto.PubKey, outputJSON bool) error { + + type P2PIdentity struct { + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` + PublicKeyBase58 string `json:"publicKeyBase58"` + PeerID string `json:"peerId"` + } + + privKeyBytes, err := libp2pPrivKey.Raw() + if err != nil { + return fmt.Errorf("unable to get raw private key bytes: %w", err) + } + + pubKeyBytes, err := libp2pPubKey.Raw() + if err != nil { + return fmt.Errorf("unable to get raw public key bytes: %w", err) + } + + peerID, err := peer.IDFromPublicKey(libp2pPubKey) + if err != nil { + return fmt.Errorf("unable to get peer identity from public key: %w", err) + } + + identity := P2PIdentity{ + PrivateKey: hex.EncodeToString(privKeyBytes), + PublicKey: hex.EncodeToString(pubKeyBytes), + PublicKeyBase58: base58.Encode(pubKeyBytes), + PeerID: peerID.String(), + } + + if outputJSON { + return printJSON(identity) + } + + fmt.Println("Your p2p private key (hex): ", identity.PrivateKey) + fmt.Println("Your p2p public key (hex): ", identity.PublicKey) + fmt.Println("Your p2p public key (base58): ", identity.PublicKeyBase58) + fmt.Println("Your p2p PeerID: ", identity.PeerID) + + return nil +} diff --git a/pkg/toolset/toolset.go b/pkg/toolset/toolset.go new file mode 100644 index 000000000..cad18b14e --- /dev/null +++ b/pkg/toolset/toolset.go @@ -0,0 +1,157 @@ +package toolset + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + flag "github.com/spf13/pflag" + + "github.com/iotaledger/hive.go/app/configuration" + "github.com/iotaledger/hive.go/ierrors" +) + +const ( + FlagToolDatabasePath = "databasePath" + + FlagToolOutputPath = "outputPath" + + FlagToolPrivateKey = "privateKey" + FlagToolPublicKey = "publicKey" + + FlagToolHRP = "hrp" + FlagToolBIP32Path = "bip32Path" + FlagToolMnemonic = "mnemonic" + FlagToolSalt = "salt" + + FlagToolNodeURL = "nodeURL" + + FlagToolOutputJSON = "json" + FlagToolDescriptionOutputJSON = "format output as JSON" +) + +const ( + ToolP2PIdentityGen = "p2pidentity-gen" + ToolP2PExtractIdentity = "p2pidentity-extract" + ToolEd25519Key = "ed25519-key" + ToolEd25519Addr = "ed25519-addr" + ToolJWTApi = "jwt-api" + ToolNodeInfo = "node-info" +) + +const ( + DefaultValueAPIJWTTokenSalt = "IOTA" + DefaultValueP2PDatabasePath = "testnet/p2pstore" +) + +// ShouldHandleTools checks if tools were requested. +func ShouldHandleTools() bool { + args := os.Args[1:] + + for _, arg := range args { + if strings.ToLower(arg) == "tool" || strings.ToLower(arg) == "tools" { + return true + } + } + + return false +} + +// HandleTools handles available tools. +func HandleTools() { + + args := os.Args[1:] + if len(args) == 1 { + listTools() + os.Exit(1) + } + + tools := map[string]func([]string) error{ + ToolP2PIdentityGen: generateP2PIdentity, + ToolP2PExtractIdentity: extractP2PIdentity, + ToolEd25519Key: generateEd25519Key, + ToolEd25519Addr: generateEd25519Address, + ToolJWTApi: generateJWTApiToken, + ToolNodeInfo: nodeInfo, + } + + tool, exists := tools[strings.ToLower(args[1])] + if !exists { + fmt.Print("tool not found.\n\n") + listTools() + os.Exit(1) + } + + if err := tool(args[2:]); err != nil { + if ierrors.Is(err, flag.ErrHelp) { + // help text was requested + os.Exit(0) + } + + fmt.Printf("\nerror: %s\n", err) + os.Exit(1) + } + + os.Exit(0) +} + +func listTools() { + fmt.Printf("%-20s generates a p2p identity private key file\n", fmt.Sprintf("%s:", ToolP2PIdentityGen)) + fmt.Printf("%-20s extracts the p2p identity from the private key file\n", fmt.Sprintf("%s:", ToolP2PExtractIdentity)) + fmt.Printf("%-20s generates an ed25519 key pair\n", fmt.Sprintf("%s:", ToolEd25519Key)) + fmt.Printf("%-20s generates an ed25519 address from a public key\n", fmt.Sprintf("%s:", ToolEd25519Addr)) + fmt.Printf("%-20s generates a JWT token for REST-API access\n", fmt.Sprintf("%s:", ToolJWTApi)) + fmt.Printf("%-20s queries the info endpoint of a node\n", fmt.Sprintf("%s:", ToolNodeInfo)) +} + +func yesOrNo(value bool) string { + if value { + return "YES" + } + + return "NO" +} + +func parseFlagSet(fs *flag.FlagSet, args []string) error { + + if err := fs.Parse(args); err != nil { + return err + } + + // Check if all parameters were parsed + if fs.NArg() != 0 { + return ierrors.New("too much arguments") + } + + return nil +} + +func printJSON(obj interface{}) error { + output, err := json.MarshalIndent(obj, "", " ") + if err != nil { + return err + } + + fmt.Println(string(output)) + + return nil +} + +//nolint:unused // we will need it at a later point in time +func loadConfigFile(filePath string, parameters map[string]any) error { + config := configuration.New() + flagset := configuration.NewUnsortedFlagSet("", flag.ContinueOnError) + + for namespace, pointerToStruct := range parameters { + config.BindParameters(flagset, namespace, pointerToStruct) + } + + if err := config.LoadFile(filePath); err != nil { + return fmt.Errorf("loading config file failed: %w", err) + } + + config.UpdateBoundParameters() + + return nil +} diff --git a/tools/docker-network/docker-compose.yml b/tools/docker-network/docker-compose.yml index bd63e2eab..22d21b2dc 100644 --- a/tools/docker-network/docker-compose.yml +++ b/tools/docker-network/docker-compose.yml @@ -20,7 +20,7 @@ services: networks: - iota-core ports: - - "8080:8080/tcp" # REST-API + - "8080:14265/tcp" # REST-API - "8081:8081/tcp" # Dashboard - "6081:6061/tcp" # pprof - "9089:9029/tcp" # INX @@ -49,7 +49,7 @@ services: networks: - iota-core ports: - - "8070:8080/tcp" # REST-API + - "8070:14265/tcp" # REST-API - "8071:8081/tcp" # Dashboard - "6071:6061/tcp" # pprof - "9029:9029/tcp" # INX @@ -77,7 +77,7 @@ services: networks: - iota-core ports: - - "8090:8080/tcp" # REST-API + - "8090:14265/tcp" # REST-API - "8091:8081/tcp" # Dashboard - "6091:6061/tcp" # pprof - "9099:9029/tcp" # INX @@ -105,7 +105,7 @@ services: networks: - iota-core ports: - - "8040:8080/tcp" # REST-API + - "8040:14265/tcp" # REST-API - "8041:8081/tcp" # Dashboard - "6041:6061/tcp" # pprof - "9049:9029/tcp" # INX @@ -130,7 +130,7 @@ services: networks: - iota-core ports: - - "8030:8080/tcp" # REST-API + - "8030:14265/tcp" # REST-API - "8031:8081/tcp" # Dashboard - "6031:6061/tcp" # pprof - "9039:9029/tcp" # INX @@ -193,7 +193,7 @@ services: restart: unless-stopped depends_on: node-1-validator: - condition: service_started + condition: service_healthy ulimits: nofile: soft: 16384 @@ -210,7 +210,7 @@ services: restart: unless-stopped depends_on: node-1-validator: - condition: service_started + condition: service_healthy inx-indexer: condition: service_started networks: @@ -229,7 +229,7 @@ services: restart: unless-stopped depends_on: node-1-validator: - condition: service_started + condition: service_healthy inx-indexer: condition: service_started inx-blockissuer: diff --git a/tools/gendoc/go.mod b/tools/gendoc/go.mod index f024b6b9d..0fa7e6386 100644 --- a/tools/gendoc/go.mod +++ b/tools/gendoc/go.mod @@ -59,21 +59,21 @@ require ( github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 // indirect github.com/iotaledger/hive.go/ads v0.0.0-20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b // indirect + github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42 // indirect github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b // indirect + github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42 // indirect github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b // indirect + github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42 // indirect github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b // indirect + github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42 // indirect github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b // indirect github.com/iotaledger/hive.go/logger v0.0.0-20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b // indirect + github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42 // indirect github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b // indirect - github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231023191159-38919c4705e0 // indirect - github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231023190837-6e7b2cdfd4fd // indirect - github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1 // indirect + github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42 // indirect + github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231028104239-869296c43f26 // indirect + github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231028104044-69b02af0058d // indirect + github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a // indirect github.com/ipfs/boxo v0.13.1 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect @@ -156,6 +156,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect + github.com/wollac/iota-crypto-demo v0.0.0-20221117162917-b10619eccb98 // indirect github.com/zyedidia/generic v1.2.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.19.0 // indirect diff --git a/tools/gendoc/go.sum b/tools/gendoc/go.sum index 2a2b0dd6e..955217c98 100644 --- a/tools/gendoc/go.sum +++ b/tools/gendoc/go.sum @@ -285,36 +285,36 @@ github.com/iotaledger/hive.go/app v0.0.0-20231020115340-13da292c580b h1:mX3NXaTM github.com/iotaledger/hive.go/app v0.0.0-20231020115340-13da292c580b/go.mod h1:8ZbIKR84oQd/3iQ5eeT7xpudO9/ytzXP7veIYnk7Orc= github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3 h1:4aVJTc0KS77uEw0Tny4r0n1ORwcbAQDECaCclgf/6lE= github.com/iotaledger/hive.go/apputils v0.0.0-20230829152614-7afc7a4d89b3/go.mod h1:TZeAqieDu+xDOZp2e9+S+8pZp1PrfgcwLUnxmd8IgLU= -github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b h1:HF4e0wz0JMIT4m3saqdQ//T9nWHV9d5sLMtEwNDuykM= -github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= +github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42 h1:drmpgLlJy7kZ09Dt1qKSnbILU+27Qu2jp4VdPDNwbFk= +github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b h1:ZERXxhQBUBV1AqTE6cUI4vTxSx4JrnsMuLZFgj32xLM= github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b/go.mod h1:Mc+ACqBGPxrPMIPUBOm6/HL0J6m0iVMwjtIEKW3uow8= -github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b h1:ZUUqRRO6XnQmVcXlXyx07vqySn28+bln6jp9KagYCjY= -github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b/go.mod h1:h3o6okvMSEK3KOX6pOp3yq1h9ohTkTfo6X8MzEadeb0= +github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42 h1:r8TkdQJB7/bJd8cF8z5GQ+rX/7JpbPdPoN7wMoV1OCM= +github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42/go.mod h1:h3o6okvMSEK3KOX6pOp3yq1h9ohTkTfo6X8MzEadeb0= github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b h1:8b2sH+2Vf0y5BDYTMwKa09iQr3JF9JrzTI64DkXb+9U= github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b/go.mod h1:3XkUSKfHaVxGbT0XAvjNlVYqPzhfLTGhDtdNA5UBPco= -github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b h1:JJPnr231djUTgTnE4oGz847WE9VA7Py6E6fgZwT5TQo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= +github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42 h1:QMxd32Y/veVhTDPCiOFgetjUbG7sr9MryF29/rSPkMA= +github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b h1:LusmtjpfG/q8lc15Fp9W3kABbN3tArKx/zw2ibdY1DU= github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b/go.mod h1:O/U3jtiUDeqqM0MZQFu2UPqS9fUm0C5hNISxlmg/thE= -github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b h1:UvFWI8wQJS/XQOeWHpPsaFVeS2nxJ7nIGFr+IFjrnVw= -github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b/go.mod h1:s4kzx9QY1MVWHJralj+3q5kI0eARtrJhphYD/iBbPfo= +github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42 h1:AvNLzONVMspwx7nD/NyYUgb5Hi7/zgzIOegr1uRD/M8= +github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42/go.mod h1:s4kzx9QY1MVWHJralj+3q5kI0eARtrJhphYD/iBbPfo= github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b h1:IwhoeOeRu25mBdrimuOOvbbhHYX0QipibV69ubn8nX0= github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b/go.mod h1:JvokzmpmFZPDskMlUqqjgHtD8usVJU4nAY/TNMGge8M= github.com/iotaledger/hive.go/logger v0.0.0-20231020115340-13da292c580b h1:EhVgAU/f2J3VYZwP60dRdyfAeDU3c/gBzX9blKtQGKA= github.com/iotaledger/hive.go/logger v0.0.0-20231020115340-13da292c580b/go.mod h1:aBfAfIB2GO/IblhYt5ipCbyeL9bXSNeAwtYVA3hZaHg= -github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b h1:O68POYIqBLnoHN+HIszc58QwAI2qocYq0WKGfVrXmMg= -github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b/go.mod h1:jRw8yFipiPaqmTPHh7hTcxAP9u6pjRGpByS3REJKkbY= +github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42 h1:1QMJ39qXIx/IZVzus3+97IV7Pa++e+d340TvbMjhiBU= +github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42/go.mod h1:jRw8yFipiPaqmTPHh7hTcxAP9u6pjRGpByS3REJKkbY= github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b h1:zaXZn9yV/95SRDkgCZQeBbSbmcJTKSZbCB7oBd71Qwg= github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b/go.mod h1:SdK26z8/VhWtxaqCuQrufm80SELgowQPmu9T/8eUQ8g= -github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b h1:MDZhTZTVDiydXcW5j4TA7HixVCyAdToIMPhHfJee7cE= -github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= -github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231023191159-38919c4705e0 h1:/8pbFXhTSroJvjJMfJqfHjzoT9N8B4LUY3SbKruD5MM= -github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231023191159-38919c4705e0/go.mod h1:My1SB4vZj42EgTDNJ/dgW8lUpLNmvtzu8f89J5y2kP0= -github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231023190837-6e7b2cdfd4fd h1:hh5mAnnaZHOYAi4CIqR9K/mv786ex9AQgpisbJ4ZMow= -github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231023190837-6e7b2cdfd4fd/go.mod h1:MK0SHfNicBmcaZb3qS3tA8NEJIWKNbcNtNNKuSDKqXY= -github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1 h1:7ChiFHg4KsdS4mKjYpFUUNe9t9nsQzNtJ/XnUV2w5ZM= -github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1/go.mod h1:jqbLYq4a/FwuiPBqFfkAwwxU8vs3+kReRq2/tyX5qRA= +github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42 h1:OlDhgvJ48bZxcvTeebJ1b96xtNnJAddejd2Q4rlH1mU= +github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= +github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231028104239-869296c43f26 h1:ZZs7IzdxrogQWGF1HfUUfR3KW8WhfxE4hUbfwZCDXFY= +github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231028104239-869296c43f26/go.mod h1:aFS0dN6QgKGgZakGgEv57NOLw+pLGdEiGcfDZ3h9GL0= +github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231028104044-69b02af0058d h1:0SVvkN04C+Ylc2puM/c77HuvRMmHRl0BkNjlZx1YWeA= +github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231028104044-69b02af0058d/go.mod h1:WFa5hHen6fi3RBX4K6r4fzhGpoh+7KJVIyFztZHdM84= +github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a h1:WLW4iaJAx4N9Pujv+gzHklnnjCt5MPrtXyVcK3UXdNc= +github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a/go.mod h1:jqbLYq4a/FwuiPBqFfkAwwxU8vs3+kReRq2/tyX5qRA= github.com/ipfs/boxo v0.13.1 h1:nQ5oQzcMZR3oL41REJDcTbrvDvuZh3J9ckc9+ILeRQI= github.com/ipfs/boxo v0.13.1/go.mod h1:btrtHy0lmO1ODMECbbEY1pxNtrLilvKSYLoGQt1yYCk= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= @@ -668,6 +668,8 @@ github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSD github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/wollac/iota-crypto-demo v0.0.0-20221117162917-b10619eccb98 h1:i7k63xHOX2ntuHrhHewfKro67c834jug2DIk599fqAA= +github.com/wollac/iota-crypto-demo v0.0.0-20221117162917-b10619eccb98/go.mod h1:Knu2XMRWe8SkwTlHc/+ghP+O9DEaZRQQEyTjvLJ5Cck= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= diff --git a/tools/genesis-snapshot/go.mod b/tools/genesis-snapshot/go.mod index 080b961b4..aaab649cb 100644 --- a/tools/genesis-snapshot/go.mod +++ b/tools/genesis-snapshot/go.mod @@ -5,12 +5,12 @@ go 1.21 replace github.com/iotaledger/iota-core => ../../ require ( - github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b - github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b + github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42 + github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42 + github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42 + github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42 github.com/iotaledger/iota-core v0.0.0-00010101000000-000000000000 - github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1 + github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a github.com/mr-tron/base58 v1.2.0 github.com/spf13/pflag v1.0.5 golang.org/x/crypto v0.14.0 @@ -27,13 +27,13 @@ require ( github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 // indirect github.com/iotaledger/hive.go/ads v0.0.0-20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b // indirect + github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42 // indirect github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b // indirect github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b // indirect github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b // indirect github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b // indirect github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b // indirect - github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b // indirect + github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/tools/genesis-snapshot/go.sum b/tools/genesis-snapshot/go.sum index fd8d7e3ec..3dbf42773 100644 --- a/tools/genesis-snapshot/go.sum +++ b/tools/genesis-snapshot/go.sum @@ -30,30 +30,30 @@ github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 h1:dTrD7X2PT github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7/go.mod h1:ZRdPu684P0fQ1z8sXz4dj9H5LWHhz4a9oCtvjunkSrw= github.com/iotaledger/hive.go/ads v0.0.0-20231020115340-13da292c580b h1:D68khiAFb9DwTvjZc2nc4R0E6wUdKyYCUXkmdaMzuoQ= github.com/iotaledger/hive.go/ads v0.0.0-20231020115340-13da292c580b/go.mod h1:IFh0gDfeMgZtfCo+5afK59IDR4xXh+cTR9YtLnZPcbY= -github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b h1:HF4e0wz0JMIT4m3saqdQ//T9nWHV9d5sLMtEwNDuykM= -github.com/iotaledger/hive.go/constraints v0.0.0-20231020115340-13da292c580b/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= +github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42 h1:drmpgLlJy7kZ09Dt1qKSnbILU+27Qu2jp4VdPDNwbFk= +github.com/iotaledger/hive.go/constraints v0.0.0-20231027195901-620bd7470e42/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b h1:ZERXxhQBUBV1AqTE6cUI4vTxSx4JrnsMuLZFgj32xLM= github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20231020115340-13da292c580b/go.mod h1:Mc+ACqBGPxrPMIPUBOm6/HL0J6m0iVMwjtIEKW3uow8= -github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b h1:ZUUqRRO6XnQmVcXlXyx07vqySn28+bln6jp9KagYCjY= -github.com/iotaledger/hive.go/crypto v0.0.0-20231020115340-13da292c580b/go.mod h1:h3o6okvMSEK3KOX6pOp3yq1h9ohTkTfo6X8MzEadeb0= +github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42 h1:r8TkdQJB7/bJd8cF8z5GQ+rX/7JpbPdPoN7wMoV1OCM= +github.com/iotaledger/hive.go/crypto v0.0.0-20231027195901-620bd7470e42/go.mod h1:h3o6okvMSEK3KOX6pOp3yq1h9ohTkTfo6X8MzEadeb0= github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b h1:8b2sH+2Vf0y5BDYTMwKa09iQr3JF9JrzTI64DkXb+9U= github.com/iotaledger/hive.go/ds v0.0.0-20231020115340-13da292c580b/go.mod h1:3XkUSKfHaVxGbT0XAvjNlVYqPzhfLTGhDtdNA5UBPco= -github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b h1:JJPnr231djUTgTnE4oGz847WE9VA7Py6E6fgZwT5TQo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20231020115340-13da292c580b/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= +github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42 h1:QMxd32Y/veVhTDPCiOFgetjUbG7sr9MryF29/rSPkMA= +github.com/iotaledger/hive.go/ierrors v0.0.0-20231027195901-620bd7470e42/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b h1:LusmtjpfG/q8lc15Fp9W3kABbN3tArKx/zw2ibdY1DU= github.com/iotaledger/hive.go/kvstore v0.0.0-20231020115340-13da292c580b/go.mod h1:O/U3jtiUDeqqM0MZQFu2UPqS9fUm0C5hNISxlmg/thE= -github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b h1:UvFWI8wQJS/XQOeWHpPsaFVeS2nxJ7nIGFr+IFjrnVw= -github.com/iotaledger/hive.go/lo v0.0.0-20231020115340-13da292c580b/go.mod h1:s4kzx9QY1MVWHJralj+3q5kI0eARtrJhphYD/iBbPfo= +github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42 h1:AvNLzONVMspwx7nD/NyYUgb5Hi7/zgzIOegr1uRD/M8= +github.com/iotaledger/hive.go/lo v0.0.0-20231027195901-620bd7470e42/go.mod h1:s4kzx9QY1MVWHJralj+3q5kI0eARtrJhphYD/iBbPfo= github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b h1:IwhoeOeRu25mBdrimuOOvbbhHYX0QipibV69ubn8nX0= github.com/iotaledger/hive.go/log v0.0.0-20231020115340-13da292c580b/go.mod h1:JvokzmpmFZPDskMlUqqjgHtD8usVJU4nAY/TNMGge8M= -github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b h1:O68POYIqBLnoHN+HIszc58QwAI2qocYq0WKGfVrXmMg= -github.com/iotaledger/hive.go/runtime v0.0.0-20231020115340-13da292c580b/go.mod h1:jRw8yFipiPaqmTPHh7hTcxAP9u6pjRGpByS3REJKkbY= +github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42 h1:1QMJ39qXIx/IZVzus3+97IV7Pa++e+d340TvbMjhiBU= +github.com/iotaledger/hive.go/runtime v0.0.0-20231027195901-620bd7470e42/go.mod h1:jRw8yFipiPaqmTPHh7hTcxAP9u6pjRGpByS3REJKkbY= github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b h1:zaXZn9yV/95SRDkgCZQeBbSbmcJTKSZbCB7oBd71Qwg= github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231020115340-13da292c580b/go.mod h1:SdK26z8/VhWtxaqCuQrufm80SELgowQPmu9T/8eUQ8g= -github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b h1:MDZhTZTVDiydXcW5j4TA7HixVCyAdToIMPhHfJee7cE= -github.com/iotaledger/hive.go/stringify v0.0.0-20231020115340-13da292c580b/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= -github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1 h1:7ChiFHg4KsdS4mKjYpFUUNe9t9nsQzNtJ/XnUV2w5ZM= -github.com/iotaledger/iota.go/v4 v4.0.0-20231025071930-7cc5b35d50b1/go.mod h1:jqbLYq4a/FwuiPBqFfkAwwxU8vs3+kReRq2/tyX5qRA= +github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42 h1:OlDhgvJ48bZxcvTeebJ1b96xtNnJAddejd2Q4rlH1mU= +github.com/iotaledger/hive.go/stringify v0.0.0-20231027195901-620bd7470e42/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= +github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a h1:WLW4iaJAx4N9Pujv+gzHklnnjCt5MPrtXyVcK3UXdNc= +github.com/iotaledger/iota.go/v4 v4.0.0-20231028103644-b834fd54b02a/go.mod h1:jqbLYq4a/FwuiPBqFfkAwwxU8vs3+kReRq2/tyX5qRA= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= diff --git a/tools/genesis-snapshot/main.go b/tools/genesis-snapshot/main.go index a8d292a87..63d303a83 100644 --- a/tools/genesis-snapshot/main.go +++ b/tools/genesis-snapshot/main.go @@ -8,7 +8,8 @@ import ( "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/runtime/options" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" + "github.com/iotaledger/iota-core/pkg/testsuite/snapshotcreator" "github.com/iotaledger/iota-core/tools/genesis-snapshot/presets" ) @@ -49,7 +50,8 @@ func parseFlags() (opt []options.Option[snapshotcreator.Options], conf string) { if err != nil { log.Fatal(ierrors.Errorf("failed to decode base58 seed, using the default one: %w", err)) } - opt = append(opt, snapshotcreator.WithGenesisSeed(genesisSeed)) + keyManager := mock.NewKeyManager(genesisSeed[:], 0) + opt = append(opt, snapshotcreator.WithGenesisKeyManager(keyManager)) } return opt, *config diff --git a/tools/genesis-snapshot/presets/presets.go b/tools/genesis-snapshot/presets/presets.go index 96d3ce284..8157c81e2 100644 --- a/tools/genesis-snapshot/presets/presets.go +++ b/tools/genesis-snapshot/presets/presets.go @@ -9,8 +9,8 @@ import ( "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/iota-core/pkg/protocol" - "github.com/iotaledger/iota-core/pkg/protocol/snapshotcreator" - "github.com/iotaledger/iota-core/pkg/testsuite" + "github.com/iotaledger/iota-core/pkg/testsuite/mock" + "github.com/iotaledger/iota-core/pkg/testsuite/snapshotcreator" iotago "github.com/iotaledger/iota.go/v4" "github.com/iotaledger/iota.go/v4/hexutil" ) @@ -40,38 +40,38 @@ var Docker = []options.Option[snapshotcreator.Options]{ snapshotcreator.AccountDetails{ // node-1-validator AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0x293dc170d9a59474e6d81cfba7f7d924c09b25d7166bcfba606e53114d0a758b"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0x293dc170d9a59474e6d81cfba7f7d924c09b25d7166bcfba606e53114d0a758b"))), - Amount: testsuite.MinValidatorAccountAmount, + Amount: mock.MinValidatorAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0x293dc170d9a59474e6d81cfba7f7d924c09b25d7166bcfba606e53114d0a758b")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, StakingEpochEnd: iotago.MaxEpochIndex, FixedCost: 1, - StakedAmount: testsuite.MinValidatorAccountAmount, - Mana: iotago.Mana(testsuite.MinValidatorAccountAmount), + StakedAmount: mock.MinValidatorAccountAmount, + Mana: iotago.Mana(mock.MinValidatorAccountAmount), }, snapshotcreator.AccountDetails{ // node-2-validator AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0x05c1de274451db8de8182d64c6ee0dca3ae0c9077e0b4330c976976171d79064"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0x05c1de274451db8de8182d64c6ee0dca3ae0c9077e0b4330c976976171d79064"))), - Amount: testsuite.MinValidatorAccountAmount, + Amount: mock.MinValidatorAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0x05c1de274451db8de8182d64c6ee0dca3ae0c9077e0b4330c976976171d79064")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, StakingEpochEnd: iotago.MaxEpochIndex, FixedCost: 1, - StakedAmount: testsuite.MinValidatorAccountAmount, - Mana: iotago.Mana(testsuite.MinValidatorAccountAmount), + StakedAmount: mock.MinValidatorAccountAmount, + Mana: iotago.Mana(mock.MinValidatorAccountAmount), }, snapshotcreator.AccountDetails{ // node-3-validator AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0x1e4b21eb51dcddf65c20db1065e1f1514658b23a3ddbf48d30c0efc926a9a648"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0x1e4b21eb51dcddf65c20db1065e1f1514658b23a3ddbf48d30c0efc926a9a648"))), - Amount: testsuite.MinValidatorAccountAmount, + Amount: mock.MinValidatorAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0x1e4b21eb51dcddf65c20db1065e1f1514658b23a3ddbf48d30c0efc926a9a648")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, StakingEpochEnd: iotago.MaxEpochIndex, FixedCost: 1, - StakedAmount: testsuite.MinValidatorAccountAmount, - Mana: iotago.Mana(testsuite.MinValidatorAccountAmount), + StakedAmount: mock.MinValidatorAccountAmount, + Mana: iotago.Mana(mock.MinValidatorAccountAmount), }, snapshotcreator.AccountDetails{ /* @@ -84,11 +84,11 @@ var Docker = []options.Option[snapshotcreator.Options]{ */ AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0x997be92a22b1933f36e26fba5f721756f95811d6b4ae21564197c2bfa4f28270"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0x997be92a22b1933f36e26fba5f721756f95811d6b4ae21564197c2bfa4f28270"))), - Amount: testsuite.MinIssuerAccountAmount, + Amount: mock.MinIssuerAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0x997be92a22b1933f36e26fba5f721756f95811d6b4ae21564197c2bfa4f28270")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, - Mana: iotago.Mana(testsuite.MinIssuerAccountAmount), + Mana: iotago.Mana(mock.MinIssuerAccountAmount), }, ), snapshotcreator.WithBasicOutputs( @@ -100,10 +100,10 @@ var Docker = []options.Option[snapshotcreator.Options]{ ed25519 address: 2f64f9d179991f50542b01e034fa043b195403875b8677efaf196b41c88803d0 bech32 address: rms1qqhkf7w30xv375z59vq7qd86qsa3j4qrsadcval04uvkkswg3qpaqf4hga2 - => restricted address with mana enabled: rms19qqz7e8e69uej86s2s4srcp5lgzrkx25qwr4hpnha7h3j66pezyq85qpqgqjjc5k + => restricted address with mana enabled: rms1xqqz7e8e69uej86s2s4srcp5lgzrkx25qwr4hpnha7h3j66pezyq85qpqg55v3ur */ snapshotcreator.BasicOutputDetails{ - Address: lo.Return2(iotago.ParseBech32("rms19qqz7e8e69uej86s2s4srcp5lgzrkx25qwr4hpnha7h3j66pezyq85qpqgqjjc5k")), + Address: lo.Return2(iotago.ParseBech32("rms1xqqz7e8e69uej86s2s4srcp5lgzrkx25qwr4hpnha7h3j66pezyq85qpqg55v3ur")), Amount: 1_000_000_000_000_000, Mana: 10_000_000, }, @@ -128,38 +128,38 @@ var Feature = []options.Option[snapshotcreator.Options]{ snapshotcreator.AccountDetails{ // node-01 AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0x01fb6b9db5d96240aef00bc950d1c67a6494513f6d7cf784e57b4972b96ab2fe"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0x01fb6b9db5d96240aef00bc950d1c67a6494513f6d7cf784e57b4972b96ab2fe"))), - Amount: testsuite.MinValidatorAccountAmount, + Amount: mock.MinValidatorAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0x01fb6b9db5d96240aef00bc950d1c67a6494513f6d7cf784e57b4972b96ab2fe")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, StakingEpochEnd: iotago.MaxEpochIndex, FixedCost: 1, - StakedAmount: testsuite.MinValidatorAccountAmount, - Mana: iotago.Mana(testsuite.MinValidatorAccountAmount), + StakedAmount: mock.MinValidatorAccountAmount, + Mana: iotago.Mana(mock.MinValidatorAccountAmount), }, snapshotcreator.AccountDetails{ // node-02 AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0x83e7f71a440afd48981a8b4684ddae24434b7182ce5c47cfb56ac528525fd4b6"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0x83e7f71a440afd48981a8b4684ddae24434b7182ce5c47cfb56ac528525fd4b6"))), - Amount: testsuite.MinValidatorAccountAmount, + Amount: mock.MinValidatorAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0x83e7f71a440afd48981a8b4684ddae24434b7182ce5c47cfb56ac528525fd4b6")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, StakingEpochEnd: iotago.MaxEpochIndex, FixedCost: 1, - StakedAmount: testsuite.MinValidatorAccountAmount, - Mana: iotago.Mana(testsuite.MinValidatorAccountAmount), + StakedAmount: mock.MinValidatorAccountAmount, + Mana: iotago.Mana(mock.MinValidatorAccountAmount), }, snapshotcreator.AccountDetails{ // node-03 AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0xac628986b2ef52a1679f2289fcd7b4198476976dea4c30ae34ff04ae52e14805"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0xac628986b2ef52a1679f2289fcd7b4198476976dea4c30ae34ff04ae52e14805"))), - Amount: testsuite.MinValidatorAccountAmount, + Amount: mock.MinValidatorAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0xac628986b2ef52a1679f2289fcd7b4198476976dea4c30ae34ff04ae52e14805")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, StakingEpochEnd: iotago.MaxEpochIndex, FixedCost: 1, - StakedAmount: testsuite.MinValidatorAccountAmount, - Mana: iotago.Mana(testsuite.MinValidatorAccountAmount), + StakedAmount: mock.MinValidatorAccountAmount, + Mana: iotago.Mana(mock.MinValidatorAccountAmount), }, snapshotcreator.AccountDetails{ /* @@ -171,11 +171,11 @@ var Feature = []options.Option[snapshotcreator.Options]{ */ AccountID: blake2b.Sum256(lo.PanicOnErr(hexutil.DecodeHex("0x670a1a20ddb02a6cec53ec3196bc7d5bd26df2f5a6ca90b5fffd71364f104b25"))), Address: iotago.Ed25519AddressFromPubKey(lo.PanicOnErr(hexutil.DecodeHex("0x670a1a20ddb02a6cec53ec3196bc7d5bd26df2f5a6ca90b5fffd71364f104b25"))), - Amount: testsuite.MinIssuerAccountAmount, + Amount: mock.MinIssuerAccountAmount, IssuerKey: iotago.Ed25519PublicKeyBlockIssuerKeyFromPublicKey(ed25519.PublicKey(lo.PanicOnErr(hexutil.DecodeHex("0x670a1a20ddb02a6cec53ec3196bc7d5bd26df2f5a6ca90b5fffd71364f104b25")))), ExpirySlot: iotago.MaxSlotIndex, BlockIssuanceCredits: iotago.MaxBlockIssuanceCredits / 4, - Mana: iotago.Mana(testsuite.MinIssuerAccountAmount), + Mana: iotago.Mana(mock.MinIssuerAccountAmount), }, ), snapshotcreator.WithBasicOutputs( @@ -186,10 +186,10 @@ var Feature = []options.Option[snapshotcreator.Options]{ ed25519 address: 48acd764f626523646d5ccf22f807e96d30b7ab0064f370b66fa811985985ec4 bech32 address: rms1qpy2e4my7cn9ydjx6hx0ytuq06tdxzm6kqry7dctvmagzxv9np0vg9c55n4 - => restricted address with mana enabled: rms19qqy3txhvnmzv53kgm2ueu30splfd5ct02cqvnehpdn04qgeskv9a3qpqgh3p7yy + => restricted address with mana enabled: rms1xqqy3txhvnmzv53kgm2ueu30splfd5ct02cqvnehpdn04qgeskv9a3qpqgrhlhv3 */ snapshotcreator.BasicOutputDetails{ - Address: lo.Return2(iotago.ParseBech32("rms19qqy3txhvnmzv53kgm2ueu30splfd5ct02cqvnehpdn04qgeskv9a3qpqgh3p7yy")), + Address: lo.Return2(iotago.ParseBech32("rms1xqqy3txhvnmzv53kgm2ueu30splfd5ct02cqvnehpdn04qgeskv9a3qpqgrhlhv3")), Amount: 1_000_000_000_000_000, Mana: 10_000_000, },