diff --git a/chains/linearizable_vm.go b/chains/linearizable_vm.go new file mode 100644 index 000000000000..ab06a8e87844 --- /dev/null +++ b/chains/linearizable_vm.go @@ -0,0 +1,80 @@ +// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package chains + +import ( + "context" + + "github.com/ava-labs/avalanchego/api/metrics" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex" + "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/snow/engine/snowman/block" + + dbManager "github.com/ava-labs/avalanchego/database/manager" +) + +var ( + _ vertex.LinearizableVM = (*initializeOnLinearizeVM)(nil) + _ block.ChainVM = (*linearizeOnInitializeVM)(nil) +) + +// initializeOnLinearizeVM transforms the consensus engine's call to Linearize +// into a call to Initialize. This enables the proposervm to be initialized by +// the call to Linearize. This also provides the stopVertexID to the +// linearizeOnInitializeVM. +type initializeOnLinearizeVM struct { + vertex.DAGVM + vmToInitialize common.VM + vmToLinearize *linearizeOnInitializeVM + + registerer metrics.OptionalGatherer + ctx *snow.Context + dbManager dbManager.Manager + genesisBytes []byte + upgradeBytes []byte + configBytes []byte + toEngine chan<- common.Message + fxs []*common.Fx + appSender common.AppSender +} + +func (vm *initializeOnLinearizeVM) Linearize(ctx context.Context, stopVertexID ids.ID) error { + vm.vmToLinearize.stopVertexID = stopVertexID + vm.ctx.Metrics = vm.registerer + return vm.vmToInitialize.Initialize( + ctx, + vm.ctx, + vm.dbManager, + vm.genesisBytes, + vm.upgradeBytes, + vm.configBytes, + vm.toEngine, + vm.fxs, + vm.appSender, + ) +} + +// linearizeOnInitializeVM transforms the proposervm's call to Initialize into a +// call to Linearize. This enables the proposervm to provide its toEngine +// channel to the VM that is being linearized. +type linearizeOnInitializeVM struct { + vertex.LinearizableVMWithEngine + stopVertexID ids.ID +} + +func (vm *linearizeOnInitializeVM) Initialize( + ctx context.Context, + _ *snow.Context, + _ dbManager.Manager, + _ []byte, + _ []byte, + _ []byte, + toEngine chan<- common.Message, + _ []*common.Fx, + _ common.AppSender, +) error { + return vm.Linearize(ctx, vm.stopVertexID, toEngine) +} diff --git a/chains/manager.go b/chains/manager.go index 8f4ca02cab48..b08562f1fde3 100644 --- a/chains/manager.go +++ b/chains/manager.go @@ -76,6 +76,18 @@ const ( ) var ( + // Commonly shared VM DB prefix + vmDBPrefix = []byte("vm") + + // Bootstrapping prefixes for LinearizableVMs + vertexDBPrefix = []byte("vertex") + vertexBootstrappingDBPrefix = []byte("vertex_bs") + txBootstrappingDBPrefix = []byte("tx_bs") + blockBootstrappingDBPrefix = []byte("block_bs") + + // Bootstrapping prefixes for ChainVMs + bootstrappingDB = []byte("bs") + errUnknownVMType = errors.New("the vm should have type avalanche.DAGVM or snowman.ChainVM") errCreatePlatformVM = errors.New("attempted to create a chain running the PlatformVM") errNotBootstrapped = errors.New("subnets not bootstrapped") @@ -527,7 +539,7 @@ func (m *manager) buildChain(chainParams ChainParameters, sb subnets.Subnet) (*c var chain *chain switch vm := vm.(type) { - case vertex.DAGVM: + case vertex.LinearizableVMWithEngine: chain, err = m.createAvalancheChain( ctx, chainParams.GenesisData, @@ -577,7 +589,7 @@ func (m *manager) createAvalancheChain( genesisData []byte, vdrs, beacons validators.Set, - vm vertex.DAGVM, + vm vertex.LinearizableVMWithEngine, fxs []*common.Fx, bootstrapWeight uint64, sb subnets.Subnet, @@ -595,12 +607,13 @@ func (m *manager) createAvalancheChain( return nil, err } prefixDBManager := meterDBManager.NewPrefixDBManager(ctx.ChainID[:]) - vmDBManager := prefixDBManager.NewPrefixDBManager([]byte("vm")) + vmDBManager := prefixDBManager.NewPrefixDBManager(vmDBPrefix) db := prefixDBManager.Current() - vertexDB := prefixdb.New([]byte("vertex"), db.Database) - vertexBootstrappingDB := prefixdb.New([]byte("vertex_bs"), db.Database) - txBootstrappingDB := prefixdb.New([]byte("tx_bs"), db.Database) + vertexDB := prefixdb.New(vertexDBPrefix, db.Database) + vertexBootstrappingDB := prefixdb.New(vertexBootstrappingDBPrefix, db.Database) + txBootstrappingDB := prefixdb.New(txBootstrappingDBPrefix, db.Database) + blockBootstrappingDB := prefixdb.New(blockBootstrappingDBPrefix, db.Database) vtxBlocker, err := queue.NewWithMissing(vertexBootstrappingDB, "vtx", ctx.AvalancheRegisterer) if err != nil { @@ -610,13 +623,17 @@ func (m *manager) createAvalancheChain( if err != nil { return nil, err } + blockBlocker, err := queue.NewWithMissing(blockBootstrappingDB, "block", ctx.Registerer) + if err != nil { + return nil, err + } // The channel through which a VM may send messages to the consensus engine // VM uses this channel to notify engine that a block is ready to be made msgChan := make(chan common.Message, defaultChannelSize) - // Passes messages from the consensus engine to the network - messageSender, err := sender.New( + // Passes messages from the avalanche engines to the network + avalancheMessageSender, err := sender.New( ctx, m.MsgCreator, m.Net, @@ -626,14 +643,48 @@ func (m *manager) createAvalancheChain( sb, ) if err != nil { - return nil, fmt.Errorf("couldn't initialize sender: %w", err) + return nil, fmt.Errorf("couldn't initialize avalanche sender: %w", err) } if m.TracingEnabled { - messageSender = sender.Trace(messageSender, m.Tracer) + avalancheMessageSender = sender.Trace(avalancheMessageSender, m.Tracer) + } + + err = m.VertexAcceptorGroup.RegisterAcceptor( + ctx.ChainID, + "gossip", + avalancheMessageSender, + false, + ) + if err != nil { // Set up the event dispatcher + return nil, fmt.Errorf("problem initializing event dispatcher: %w", err) + } + + // Passes messages from the snowman engines to the network + snowmanMessageSender, err := sender.New( + ctx, + m.MsgCreator, + m.Net, + m.ManagerConfig.Router, + m.TimeoutManager, + p2p.EngineType_ENGINE_TYPE_SNOWMAN, + sb, + ) + if err != nil { + return nil, fmt.Errorf("couldn't initialize avalanche sender: %w", err) } - if err := m.VertexAcceptorGroup.RegisterAcceptor(ctx.ChainID, "gossip", messageSender, false); err != nil { // Set up the event dispatcher + if m.TracingEnabled { + snowmanMessageSender = sender.Trace(snowmanMessageSender, m.Tracer) + } + + err = m.BlockAcceptorGroup.RegisterAcceptor( + ctx.ChainID, + "gossip", + snowmanMessageSender, + false, + ) + if err != nil { // Set up the event dispatcher return nil, fmt.Errorf("problem initializing event dispatcher: %w", err) } @@ -661,6 +712,26 @@ func (m *manager) createAvalancheChain( }, ) + avalancheRegisterer := metrics.NewOptionalGatherer() + snowmanRegisterer := metrics.NewOptionalGatherer() + + registerer := metrics.NewMultiGatherer() + if err := registerer.Register("avalanche", avalancheRegisterer); err != nil { + return nil, err + } + if err := registerer.Register("", snowmanRegisterer); err != nil { + return nil, err + } + if err := ctx.Context.Metrics.Register(registerer); err != nil { + return nil, err + } + + ctx.Context.Metrics = avalancheRegisterer + + // The only difference between using avalancheMessageSender and + // snowmanMessageSender here is where the metrics will be placed. Because we + // end up using this sender after the linearization, we pass in + // snowmanMessageSender here. err = vm.Initialize( context.TODO(), ctx.Context, @@ -670,12 +741,70 @@ func (m *manager) createAvalancheChain( chainConfig.Config, msgChan, fxs, - messageSender, + snowmanMessageSender, ) if err != nil { return nil, fmt.Errorf("error during vm's Initialize: %w", err) } + // Initialize the ProposerVM and the vm wrapped inside it + minBlockDelay := proposervm.DefaultMinBlockDelay + if subnetCfg, ok := m.SubnetConfigs[ctx.SubnetID]; ok { + minBlockDelay = subnetCfg.ProposerMinBlockDelay + } + m.Log.Info("creating proposervm wrapper", + zap.Time("activationTime", m.ApricotPhase4Time), + zap.Uint64("minPChainHeight", m.ApricotPhase4MinPChainHeight), + zap.Duration("minBlockDelay", minBlockDelay), + ) + + chainAlias := m.PrimaryAliasOrDefault(ctx.ChainID) + + untracedVMWrappedInsideProposerVM := &linearizeOnInitializeVM{ + LinearizableVMWithEngine: vm, + } + + var vmWrappedInsideProposerVM block.ChainVM = untracedVMWrappedInsideProposerVM + if m.TracingEnabled { + vmWrappedInsideProposerVM = tracedvm.NewBlockVM(vmWrappedInsideProposerVM, chainAlias, m.Tracer) + } + + // Note: vmWrappingProposerVM is the VM that the Snowman engines should be + // using. + var vmWrappingProposerVM block.ChainVM = proposervm.New( + vmWrappedInsideProposerVM, + m.ApricotPhase4Time, + m.ApricotPhase4MinPChainHeight, + minBlockDelay, + m.StakingCert.PrivateKey.(crypto.Signer), + m.StakingCert.Leaf, + ) + + if m.MeterVMEnabled { + vmWrappingProposerVM = metervm.NewBlockVM(vmWrappingProposerVM) + } + if m.TracingEnabled { + vmWrappingProposerVM = tracedvm.NewBlockVM(vmWrappingProposerVM, "proposervm", m.Tracer) + } + + // Note: linearizableVM is the VM that the Avalanche engines should be + // using. + linearizableVM := &initializeOnLinearizeVM{ + DAGVM: vm, + vmToInitialize: vmWrappingProposerVM, + vmToLinearize: untracedVMWrappedInsideProposerVM, + + registerer: snowmanRegisterer, + ctx: ctx.Context, + dbManager: vmDBManager, + genesisBytes: genesisData, + upgradeBytes: chainConfig.Upgrade, + configBytes: chainConfig.Config, + toEngine: msgChan, + fxs: fxs, + appSender: snowmanMessageSender, + } + consensusParams := sb.Config().ConsensusParameters sampleK := consensusParams.K if uint64(sampleK) > bootstrapWeight { @@ -700,13 +829,79 @@ func (m *manager) createAvalancheChain( startupTracker := tracker.NewStartup(connectedPeers, (3*bootstrapWeight+3)/4) beacons.RegisterCallbackListener(startupTracker) - commonCfg := common.Config{ + snowmanCommonCfg := common.Config{ + Ctx: ctx, + Beacons: beacons, + SampleK: sampleK, + Alpha: bootstrapWeight/2 + 1, // must be > 50% + StartupTracker: startupTracker, + Sender: snowmanMessageSender, + BootstrapTracker: sb, + Timer: h, + RetryBootstrap: m.RetryBootstrap, + RetryBootstrapWarnFrequency: m.RetryBootstrapWarnFrequency, + MaxTimeGetAncestors: m.BootstrapMaxTimeGetAncestors, + AncestorsMaxContainersSent: m.BootstrapAncestorsMaxContainersSent, + AncestorsMaxContainersReceived: m.BootstrapAncestorsMaxContainersReceived, + SharedCfg: &common.SharedConfig{}, + } + snowGetHandler, err := snowgetter.New(vmWrappingProposerVM, snowmanCommonCfg) + if err != nil { + return nil, fmt.Errorf("couldn't initialize snow base message handler: %w", err) + } + + var snowmanConsensus smcon.Consensus = &smcon.Topological{} + if m.TracingEnabled { + snowmanConsensus = smcon.Trace(snowmanConsensus, m.Tracer) + } + + // Create engine, bootstrapper and state-syncer in this order, + // to make sure start callbacks are duly initialized + snowmanEngineConfig := smeng.Config{ + Ctx: snowmanCommonCfg.Ctx, + AllGetsServer: snowGetHandler, + VM: vmWrappingProposerVM, + Sender: snowmanCommonCfg.Sender, + Validators: vdrs, + Params: consensusParams.Parameters, + Consensus: snowmanConsensus, + } + snowmanEngine, err := smeng.New(snowmanEngineConfig) + if err != nil { + return nil, fmt.Errorf("error initializing snowman engine: %w", err) + } + + if m.TracingEnabled { + snowmanEngine = smeng.TraceEngine(snowmanEngine, m.Tracer) + } + + // create bootstrap gear + bootstrapCfg := smbootstrap.Config{ + Config: snowmanCommonCfg, + AllGetsServer: snowGetHandler, + Blocked: blockBlocker, + VM: vmWrappingProposerVM, + } + snowmanBootstrapper, err := smbootstrap.New( + context.TODO(), + bootstrapCfg, + snowmanEngine.Start, + ) + if err != nil { + return nil, fmt.Errorf("error initializing snowman bootstrapper: %w", err) + } + + if m.TracingEnabled { + snowmanBootstrapper = common.TraceBootstrapableEngine(snowmanBootstrapper, m.Tracer) + } + + avalancheCommonCfg := common.Config{ Ctx: ctx, Beacons: beacons, SampleK: sampleK, StartupTracker: startupTracker, Alpha: bootstrapWeight/2 + 1, // must be > 50% - Sender: messageSender, + Sender: avalancheMessageSender, BootstrapTracker: sb, Timer: h, RetryBootstrap: m.RetryBootstrap, @@ -717,70 +912,77 @@ func (m *manager) createAvalancheChain( SharedCfg: &common.SharedConfig{}, } - avaGetHandler, err := avagetter.New(vtxManager, commonCfg) + avaGetHandler, err := avagetter.New(vtxManager, avalancheCommonCfg) if err != nil { return nil, fmt.Errorf("couldn't initialize avalanche base message handler: %w", err) } - var consensus avcon.Consensus = &avcon.Topological{} + // create bootstrap gear + avalancheBootstrapperConfig := avbootstrap.Config{ + Config: avalancheCommonCfg, + AllGetsServer: avaGetHandler, + VtxBlocked: vtxBlocker, + TxBlocked: txBlocker, + Manager: vtxManager, + VM: linearizableVM, + } + + var avalancheConsensus avcon.Consensus = &avcon.Topological{} if m.TracingEnabled { - consensus = avcon.Trace(consensus, m.Tracer) + avalancheConsensus = avcon.Trace(avalancheConsensus, m.Tracer) } // create engine gear - engineConfig := aveng.Config{ + avalancheEngineConfig := aveng.Config{ Ctx: ctx, AllGetsServer: avaGetHandler, - VM: vm, + VM: linearizableVM, Manager: vtxManager, - Sender: messageSender, + Sender: avalancheMessageSender, Validators: vdrs, Params: consensusParams, - Consensus: consensus, + Consensus: avalancheConsensus, } - engine, err := aveng.New(engineConfig) + avalancheEngine, err := aveng.New( + avalancheEngineConfig, + snowmanEngine.Start, + ) if err != nil { return nil, fmt.Errorf("error initializing avalanche engine: %w", err) } if m.TracingEnabled { - engine = aveng.TraceEngine(engine, m.Tracer) + avalancheEngine = aveng.TraceEngine(avalancheEngine, m.Tracer) } - // create bootstrap gear - bootstrapperConfig := avbootstrap.Config{ - Config: commonCfg, - AllGetsServer: avaGetHandler, - VtxBlocked: vtxBlocker, - TxBlocked: txBlocker, - Manager: vtxManager, - VM: vm, - } - bootstrapper, err := avbootstrap.New( + avalancheBootstrapper, err := avbootstrap.New( context.TODO(), - bootstrapperConfig, - engine.Start, + avalancheBootstrapperConfig, + avalancheEngine.Start, + snowmanBootstrapper.Start, ) if err != nil { return nil, fmt.Errorf("error initializing avalanche bootstrapper: %w", err) } if m.TracingEnabled { - bootstrapper = common.TraceBootstrapableEngine(bootstrapper, m.Tracer) + avalancheBootstrapper = common.TraceBootstrapableEngine(avalancheBootstrapper, m.Tracer) } h.SetEngineManager(&handler.EngineManager{ Avalanche: &handler.Engine{ StateSyncer: nil, - Bootstrapper: bootstrapper, - Consensus: engine, + Bootstrapper: avalancheBootstrapper, + Consensus: avalancheEngine, + }, + Snowman: &handler.Engine{ + StateSyncer: nil, + Bootstrapper: snowmanBootstrapper, + Consensus: snowmanEngine, }, - Snowman: nil, }) // Register health check for this chain - chainAlias := m.PrimaryAliasOrDefault(ctx.ChainID) - if err := m.Health.RegisterHealthCheck(chainAlias, h); err != nil { return nil, fmt.Errorf("couldn't add health check for chain %s: %w", chainAlias, err) } @@ -817,10 +1019,10 @@ func (m *manager) createSnowmanChain( return nil, err } prefixDBManager := meterDBManager.NewPrefixDBManager(ctx.ChainID[:]) - vmDBManager := prefixDBManager.NewPrefixDBManager([]byte("vm")) + vmDBManager := prefixDBManager.NewPrefixDBManager(vmDBPrefix) db := prefixDBManager.Current() - bootstrappingDB := prefixdb.New([]byte("bs"), db.Database) + bootstrappingDB := prefixdb.New(bootstrappingDB, db.Database) blocked, err := queue.NewWithMissing(bootstrappingDB, "block", ctx.Registerer) if err != nil { @@ -849,7 +1051,13 @@ func (m *manager) createSnowmanChain( messageSender = sender.Trace(messageSender, m.Tracer) } - if err := m.BlockAcceptorGroup.RegisterAcceptor(ctx.ChainID, "gossip", messageSender, false); err != nil { // Set up the event dispatcher + err = m.BlockAcceptorGroup.RegisterAcceptor( + ctx.ChainID, + "gossip", + messageSender, + false, + ) + if err != nil { // Set up the event dispatcher return nil, fmt.Errorf("problem initializing event dispatcher: %w", err) } diff --git a/indexer/indexer.go b/indexer/indexer.go index 10563c4fbb2b..f591cc8a390e 100644 --- a/indexer/indexer.go +++ b/indexer/indexer.go @@ -264,6 +264,22 @@ func (i *indexer) RegisterChain(chainName string, ctx *snow.ConsensusContext, vm return } + index, err := i.registerChainHelper(chainID, blockPrefix, chainName, "block", i.blockAcceptorGroup) + if err != nil { + i.log.Fatal("failed to create index", + zap.String("chainName", chainName), + zap.String("endpoint", "block"), + zap.Error(err), + ) + if err := i.close(); err != nil { + i.log.Error("failed to close indexer", + zap.Error(err), + ) + } + return + } + i.blockIndices[chainID] = index + switch vm.(type) { case vertex.DAGVM: vtxIndex, err := i.registerChainHelper(chainID, vtxPrefix, chainName, "vtx", i.vertexAcceptorGroup) @@ -298,21 +314,6 @@ func (i *indexer) RegisterChain(chainName string, ctx *snow.ConsensusContext, vm } i.txIndices[chainID] = txIndex case block.ChainVM: - index, err := i.registerChainHelper(chainID, blockPrefix, chainName, "block", i.blockAcceptorGroup) - if err != nil { - i.log.Fatal("failed to create index", - zap.String("chainName", chainName), - zap.String("endpoint", "block"), - zap.Error(err), - ) - if err := i.close(); err != nil { - i.log.Error("failed to close indexer", - zap.Error(err), - ) - } - return - } - i.blockIndices[chainID] = index default: vmType := fmt.Sprintf("%T", vm) i.log.Error("got unexpected vm type", diff --git a/indexer/indexer_test.go b/indexer/indexer_test.go index 2ba1a8460279..7d3f860df805 100644 --- a/indexer/indexer_test.go +++ b/indexer/indexer_test.go @@ -134,6 +134,7 @@ func TestIndexer(t *testing.T) { baseDB := memdb.New() db := versiondb.New(baseDB) + server := &apiServerMock{} config := Config{ IndexingEnabled: true, AllowIncompleteIndex: false, @@ -142,7 +143,7 @@ func TestIndexer(t *testing.T) { BlockAcceptorGroup: snow.NewAcceptorGroup(logging.NoLog{}), TxAcceptorGroup: snow.NewAcceptorGroup(logging.NoLog{}), VertexAcceptorGroup: snow.NewAcceptorGroup(logging.NoLog{}), - APIServer: &apiServerMock{}, + APIServer: server, ShutdownF: func() {}, } @@ -173,7 +174,6 @@ func TestIndexer(t *testing.T) { previouslyIndexed, err = idxr.previouslyIndexed(chain1Ctx.ChainID) require.NoError(err) require.True(previouslyIndexed) - server := config.APIServer.(*apiServerMock) require.EqualValues(1, server.timesCalled) require.EqualValues("index/chain1", server.bases[0]) require.EqualValues("/block", server.endpoints[0]) @@ -257,6 +257,8 @@ func TestIndexer(t *testing.T) { container, err = blkIdx.GetLastAccepted() require.NoError(err) require.Equal(blkID, container.ID) + require.EqualValues(1, server.timesCalled) // block index for chain + require.Contains(server.endpoints, "/block") // Register a DAG chain chain2Ctx := snow.DefaultConsensusContextTest() @@ -267,15 +269,15 @@ func TestIndexer(t *testing.T) { previouslyIndexed, err = idxr.previouslyIndexed(chain2Ctx.ChainID) require.NoError(err) require.False(previouslyIndexed) - dagVM := vertex.NewMockDAGVM(ctrl) + dagVM := vertex.NewMockLinearizableVM(ctrl) idxr.RegisterChain("chain2", chain2Ctx, dagVM) require.NoError(err) - server = config.APIServer.(*apiServerMock) - require.EqualValues(3, server.timesCalled) // block index, vtx index, tx index + require.EqualValues(4, server.timesCalled) // block index for chain, block index for dag, vtx index, tx index require.Contains(server.bases, "index/chain2") + require.Contains(server.endpoints, "/block") require.Contains(server.endpoints, "/vtx") require.Contains(server.endpoints, "/tx") - require.Len(idxr.blockIndices, 1) + require.Len(idxr.blockIndices, 2) require.Len(idxr.txIndices, 1) require.Len(idxr.vtxIndices, 1) diff --git a/scripts/mocks.mockgen.txt b/scripts/mocks.mockgen.txt index 64fed91afe13..7ebfc3c70a26 100644 --- a/scripts/mocks.mockgen.txt +++ b/scripts/mocks.mockgen.txt @@ -6,7 +6,7 @@ github.com/ava-labs/avalanchego/message=OutboundMessage=message/mock_message.go github.com/ava-labs/avalanchego/message=OutboundMsgBuilder=message/mock_outbound_message_builder.go github.com/ava-labs/avalanchego/network/peer=GossipTracker=network/peer/mock_gossip_tracker.go github.com/ava-labs/avalanchego/snow/consensus/snowman=Block=snow/consensus/snowman/mock_block.go -github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex=DAGVM=snow/engine/avalanche/vertex/mock_vm.go +github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex=LinearizableVM=snow/engine/avalanche/vertex/mock_vm.go github.com/ava-labs/avalanchego/snow/engine/snowman/block=BuildBlockWithContextChainVM=snow/engine/snowman/block/mocks/build_block_with_context_vm.go github.com/ava-labs/avalanchego/snow/engine/snowman/block=ChainVM=snow/engine/snowman/block/mocks/chain_vm.go github.com/ava-labs/avalanchego/snow/engine/snowman/block=StateSyncableVM=snow/engine/snowman/block/mocks/state_syncable_vm.go diff --git a/snow/engine/avalanche/bootstrap/bootstrapper.go b/snow/engine/avalanche/bootstrap/bootstrapper.go index 5a48ba631945..6f7b98c4f24f 100644 --- a/snow/engine/avalanche/bootstrap/bootstrapper.go +++ b/snow/engine/avalanche/bootstrap/bootstrapper.go @@ -42,7 +42,12 @@ var ( errUnexpectedTimeout = errors.New("unexpected timeout fired") ) -func New(ctx context.Context, config Config, onFinished func(ctx context.Context, lastReqID uint32) error) (common.BootstrapableEngine, error) { +func New( + ctx context.Context, + config Config, + startAvalancheConsensus func(ctx context.Context, lastReqID uint32) error, + startSnowmanBootstrapping func(ctx context.Context, lastReqID uint32) error, +) (common.BootstrapableEngine, error) { b := &bootstrapper{ Config: config, @@ -53,8 +58,27 @@ func New(ctx context.Context, config Config, onFinished func(ctx context.Context ChitsHandler: common.NewNoOpChitsHandler(config.Ctx.Log), AppHandler: config.VM, - processedCache: &cache.LRU[ids.ID, struct{}]{Size: cacheSize}, - Fetcher: common.Fetcher{OnFinished: onFinished}, + processedCache: &cache.LRU[ids.ID, struct{}]{Size: cacheSize}, + Fetcher: common.Fetcher{ + OnFinished: func(ctx context.Context, lastReqID uint32) error { + linearized, err := config.Manager.StopVertexAccepted(ctx) + if err != nil { + return err + } + if !linearized { + return startAvalancheConsensus(ctx, lastReqID) + } + + // Invariant: edge will only be the stop vertex after its + // acceptance. + edge := config.Manager.Edge(ctx) + stopVertexID := edge[0] + if err := config.VM.Linearize(ctx, stopVertexID); err != nil { + return err + } + return startSnowmanBootstrapping(ctx, lastReqID) + }, + }, executedStateTransitions: math.MaxInt32, } diff --git a/snow/engine/avalanche/bootstrap/bootstrapper_test.go b/snow/engine/avalanche/bootstrap/bootstrapper_test.go index 28e1f4c7a82b..d10658fa2ea8 100644 --- a/snow/engine/avalanche/bootstrap/bootstrapper_test.go +++ b/snow/engine/avalanche/bootstrap/bootstrapper_test.go @@ -31,6 +31,10 @@ var ( errUnknownTx = errors.New("unknown tx") ) +func noopStarter(context.Context, uint32) error { + return nil +} + func newConfig(t *testing.T) (Config, ids.NodeID, *common.SenderTest, *vertex.TestManager, *vertex.TestVM) { ctx := snow.DefaultConsensusContextTest() @@ -152,6 +156,7 @@ func TestBootstrapperSingleFrontier(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) @@ -258,6 +263,7 @@ func TestBootstrapperByzantineResponses(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) @@ -439,6 +445,7 @@ func TestBootstrapperTxDependencies(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) @@ -586,6 +593,7 @@ func TestBootstrapperMissingTxDependency(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) @@ -710,6 +718,7 @@ func TestBootstrapperIncompleteAncestors(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) @@ -833,6 +842,7 @@ func TestBootstrapperFinalized(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) @@ -967,6 +977,7 @@ func TestBootstrapperAcceptsAncestorsParents(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) @@ -1137,6 +1148,7 @@ func TestRestartBootstrapping(t *testing.T) { }) return nil }, + noopStarter, ) if err != nil { t.Fatal(err) diff --git a/snow/engine/avalanche/bootstrap/config.go b/snow/engine/avalanche/bootstrap/config.go index ef65a1d253a7..9eb9c67fc16f 100644 --- a/snow/engine/avalanche/bootstrap/config.go +++ b/snow/engine/avalanche/bootstrap/config.go @@ -19,5 +19,5 @@ type Config struct { TxBlocked *queue.Jobs Manager vertex.Manager - VM vertex.DAGVM + VM vertex.LinearizableVM } diff --git a/snow/engine/avalanche/bootstrap/tx_job.go b/snow/engine/avalanche/bootstrap/tx_job.go index 029cdf9be076..8377176afaad 100644 --- a/snow/engine/avalanche/bootstrap/tx_job.go +++ b/snow/engine/avalanche/bootstrap/tx_job.go @@ -26,7 +26,7 @@ var errMissingTxDependenciesOnAccept = errors.New("attempting to accept a transa type txParser struct { log logging.Logger numAccepted, numDropped prometheus.Counter - vm vertex.DAGVM + vm vertex.LinearizableVM } func (p *txParser) Parse(ctx context.Context, txBytes []byte) (queue.Job, error) { diff --git a/snow/engine/avalanche/config.go b/snow/engine/avalanche/config.go index 8c716b63edcb..69b794d0bdd6 100644 --- a/snow/engine/avalanche/config.go +++ b/snow/engine/avalanche/config.go @@ -15,7 +15,7 @@ import ( type Config struct { Ctx *snow.ConsensusContext common.AllGetsServer - VM vertex.DAGVM + VM vertex.LinearizableVM Manager vertex.Manager Sender common.Sender Validators validators.Set diff --git a/snow/engine/avalanche/transitive.go b/snow/engine/avalanche/transitive.go index 1ffff44b10f2..916b13b4e4b3 100644 --- a/snow/engine/avalanche/transitive.go +++ b/snow/engine/avalanche/transitive.go @@ -30,8 +30,11 @@ import ( var _ Engine = (*Transitive)(nil) -func New(config Config) (Engine, error) { - return newTransitive(config) +func New( + config Config, + startSnowmanConsensus func(ctx context.Context, lastReqID uint32) error, +) (Engine, error) { + return newTransitive(config, startSnowmanConsensus) } // Transitive implements the Engine interface by attempting to fetch all @@ -75,13 +78,18 @@ type Transitive struct { // optimal number. pendingTxs []snowstorm.Tx + startSnowmanConsensus func(ctx context.Context, lastReqID uint32) error + // A uniform sampler without replacement uniformSampler sampler.Uniform errs wrappers.Errs } -func newTransitive(config Config) (*Transitive, error) { +func newTransitive( + config Config, + startSnowmanConsensus func(ctx context.Context, lastReqID uint32) error, +) (*Transitive, error) { config.Ctx.Log.Info("initializing consensus engine") acceptedFrontiers := tracker.NewAccepted() @@ -104,7 +112,8 @@ func newTransitive(config Config) (*Transitive, error) { "", config.Ctx.AvalancheRegisterer, ), - uniformSampler: sampler.NewUniform(), + startSnowmanConsensus: startSnowmanConsensus, + uniformSampler: sampler.NewUniform(), } return t, t.metrics.Initialize("", config.Ctx.AvalancheRegisterer) @@ -205,9 +214,6 @@ func (t *Transitive) GetFailed(ctx context.Context, nodeID ids.NodeID, requestID } func (t *Transitive) PullQuery(ctx context.Context, nodeID ids.NodeID, requestID uint32, vtxID ids.ID) error { - // Immediately respond to the query with the current consensus preferences. - t.Sender.SendChits(ctx, nodeID, requestID, t.Consensus.Preferences().List(), t.Manager.Edge(ctx)) - // If the chain is linearized, we don't care to attempt to issue any new // vertices. linearized, err := t.Manager.StopVertexAccepted(ctx) @@ -215,9 +221,18 @@ func (t *Transitive) PullQuery(ctx context.Context, nodeID ids.NodeID, requestID return err } if linearized { + // Immediately respond to the query with the stop vertex. + // + // Invariant: This is done here, because the Consensus instance may have + // never been initialized if bootstrapping accepted the stop vertex. + edge := t.Manager.Edge(ctx) + t.Sender.SendChits(ctx, nodeID, requestID, edge, edge) return nil } + // Immediately respond to the query with the current consensus preferences. + t.Sender.SendChits(ctx, nodeID, requestID, t.Consensus.Preferences().List(), t.Manager.Edge(ctx)) + // If we have [vtxID], attempt to put it into consensus, if we haven't // already. If we don't not have [vtxID], fetch it from [nodeID]. if _, err := t.issueFromByID(ctx, nodeID, vtxID); err != nil { @@ -228,9 +243,6 @@ func (t *Transitive) PullQuery(ctx context.Context, nodeID ids.NodeID, requestID } func (t *Transitive) PushQuery(ctx context.Context, nodeID ids.NodeID, requestID uint32, vtxBytes []byte) error { - // Immediately respond to the query with the current consensus preferences. - t.Sender.SendChits(ctx, nodeID, requestID, t.Consensus.Preferences().List(), t.Manager.Edge(ctx)) - // If the chain is linearized, we don't care to attempt to issue any new // vertices. linearized, err := t.Manager.StopVertexAccepted(ctx) @@ -238,9 +250,18 @@ func (t *Transitive) PushQuery(ctx context.Context, nodeID ids.NodeID, requestID return err } if linearized { + // Immediately respond to the query with the stop vertex. + // + // Invariant: This is done here, because the Consensus instance may have + // never been initialized if bootstrapping accepted the stop vertex. + edge := t.Manager.Edge(ctx) + t.Sender.SendChits(ctx, nodeID, requestID, edge, edge) return nil } + // Immediately respond to the query with the current consensus preferences. + t.Sender.SendChits(ctx, nodeID, requestID, t.Consensus.Preferences().List(), t.Manager.Edge(ctx)) + vtx, err := t.Manager.ParseVtx(ctx, vtxBytes) if err != nil { t.Ctx.Log.Debug("failed to parse vertex", diff --git a/snow/engine/avalanche/transitive_test.go b/snow/engine/avalanche/transitive_test.go index e53aec68634f..70e8c6026502 100644 --- a/snow/engine/avalanche/transitive_test.go +++ b/snow/engine/avalanche/transitive_test.go @@ -52,6 +52,10 @@ func (dh *dummyHandler) onDoneBootstrapping(ctx context.Context, lastReqID uint3 return dh.startEngineF(ctx, lastReqID) } +func noopStarter(context.Context, uint32) error { + return nil +} + func TestEngineShutdown(t *testing.T) { _, _, engCfg := DefaultConfig() @@ -64,7 +68,7 @@ func TestEngineShutdown(t *testing.T) { } engCfg.VM = vm - transitive, err := newTransitive(engCfg) + transitive, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -100,7 +104,7 @@ func TestEngineAdd(t *testing.T) { manager.CantEdge = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -245,7 +249,7 @@ func TestEngineQuery(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -553,7 +557,7 @@ func TestEngineMultipleQuery(t *testing.T) { TxsV: []snowstorm.Tx{tx0}, } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -713,7 +717,7 @@ func TestEngineBlockedIssue(t *testing.T) { TxsV: []snowstorm.Tx{tx0}, } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -787,7 +791,7 @@ func TestEngineAbandonResponse(t *testing.T) { return nil, errUnknownVertex } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -865,7 +869,7 @@ func TestEngineScheduleRepoll(t *testing.T) { sender.Default(true) sender.CantSendGetAcceptedFrontier = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -990,7 +994,7 @@ func TestEngineRejectDoubleSpendTx(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1084,7 +1088,7 @@ func TestEngineRejectDoubleSpendIssuedTx(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1169,7 +1173,7 @@ func TestEngineIssueRepoll(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1303,7 +1307,7 @@ func TestEngineReissue(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1460,7 +1464,7 @@ func TestEngineLargeIssue(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1541,7 +1545,7 @@ func TestEngineGetVertex(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1614,7 +1618,7 @@ func TestEngineInsufficientValidators(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1694,7 +1698,7 @@ func TestEnginePushGossip(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1784,7 +1788,7 @@ func TestEngineSingleQuery(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1876,7 +1880,7 @@ func TestEngineParentBlockingInsert(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -1964,7 +1968,7 @@ func TestEngineAbandonChit(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) require.NoError(err) err = te.Start(context.Background(), 0) @@ -2062,7 +2066,7 @@ func TestEngineAbandonChitWithUnexpectedPutVertex(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) require.NoError(err) err = te.Start(context.Background(), 0) @@ -2181,7 +2185,7 @@ func TestEngineBlockingChitRequest(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -2305,7 +2309,7 @@ func TestEngineBlockingChitResponse(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -2440,7 +2444,7 @@ func TestEngineMissingTx(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -2547,7 +2551,7 @@ func TestEngineIssueBlockingTx(t *testing.T) { TxsV: []snowstorm.Tx{tx0, tx1}, } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -2630,7 +2634,7 @@ func TestEngineReissueAbortedVertex(t *testing.T) { panic("Unknown vertex requested") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -2805,12 +2809,13 @@ func TestEngineBootstrappingIntoConsensus(t *testing.T) { context.Background(), bootCfg, dh.onDoneBootstrapping, + noopStarter, ) if err != nil { t.Fatal(err) } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -3066,6 +3071,7 @@ func TestEngineReBootstrapFails(t *testing.T) { context.Background(), bootCfg, dh.onDoneBootstrapping, + noopStarter, ) if err != nil { t.Fatal(err) @@ -3111,6 +3117,7 @@ func TestEngineReBootstrapFails(t *testing.T) { context.Background(), bootCfg, dh.onDoneBootstrapping, + noopStarter, ) if err != nil { t.Fatal(err) @@ -3244,12 +3251,13 @@ func TestEngineReBootstrappingIntoConsensus(t *testing.T) { context.Background(), bootCfg, dh.onDoneBootstrapping, + noopStarter, ) if err != nil { t.Fatal(err) } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -3473,7 +3481,7 @@ func TestEngineUndeclaredDependencyDeadlock(t *testing.T) { TxsV: []snowstorm.Tx{tx1}, } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -3568,7 +3576,7 @@ func TestEnginePartiallyValidVertex(t *testing.T) { TxsV: []snowstorm.Tx{tx0, tx1}, } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -3620,7 +3628,7 @@ func TestEngineGossip(t *testing.T) { StatusV: choices.Accepted, }} - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -3723,7 +3731,7 @@ func TestEngineInvalidVertexIgnoredFromUnexpectedPeer(t *testing.T) { BytesV: []byte{2}, } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -3867,7 +3875,7 @@ func TestEnginePushQueryRequestIDConflict(t *testing.T) { BytesV: []byte{2}, } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4011,7 +4019,7 @@ func TestEngineAggressivePolling(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4133,7 +4141,7 @@ func TestEngineDuplicatedIssuance(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4253,7 +4261,7 @@ func TestEngineDoubleChit(t *testing.T) { panic("Should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4417,7 +4425,7 @@ func TestEngineBubbleVotes(t *testing.T) { panic("should have errored") } - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4540,7 +4548,7 @@ func TestEngineIssue(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4642,7 +4650,7 @@ func TestAbandonTx(t *testing.T) { engCfg.VM = vm - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4774,7 +4782,7 @@ func TestSendMixedQuery(t *testing.T) { engCfg.Params.Alpha = 12 engCfg.Params.MixedQueryNumPushVdr = 12 engCfg.Params.MixedQueryNumPushNonVdr = 11 - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) if err != nil { t.Fatal(err) } @@ -4955,7 +4963,7 @@ func TestEngineApplyAcceptedFrontierInQueryFailed(t *testing.T) { } vm.CantSetState = false - te, err := newTransitive(engCfg) + te, err := newTransitive(engCfg, noopStarter) require.NoError(err) require.NoError(te.Start(context.Background(), 0)) diff --git a/snow/engine/avalanche/vertex/mock_vm.go b/snow/engine/avalanche/vertex/mock_vm.go index e790fd712b11..757e49cf3e6a 100644 --- a/snow/engine/avalanche/vertex/mock_vm.go +++ b/snow/engine/avalanche/vertex/mock_vm.go @@ -2,7 +2,7 @@ // See the file LICENSE for licensing terms. // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex (interfaces: DAGVM) +// Source: github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex (interfaces: LinearizableVM) // Package vertex is a generated GoMock package. package vertex @@ -22,31 +22,31 @@ import ( gomock "github.com/golang/mock/gomock" ) -// MockDAGVM is a mock of DAGVM interface. -type MockDAGVM struct { +// MockLinearizableVM is a mock of LinearizableVM interface. +type MockLinearizableVM struct { ctrl *gomock.Controller - recorder *MockDAGVMMockRecorder + recorder *MockLinearizableVMMockRecorder } -// MockDAGVMMockRecorder is the mock recorder for MockDAGVM. -type MockDAGVMMockRecorder struct { - mock *MockDAGVM +// MockLinearizableVMMockRecorder is the mock recorder for MockLinearizableVM. +type MockLinearizableVMMockRecorder struct { + mock *MockLinearizableVM } -// NewMockDAGVM creates a new mock instance. -func NewMockDAGVM(ctrl *gomock.Controller) *MockDAGVM { - mock := &MockDAGVM{ctrl: ctrl} - mock.recorder = &MockDAGVMMockRecorder{mock} +// NewMockLinearizableVM creates a new mock instance. +func NewMockLinearizableVM(ctrl *gomock.Controller) *MockLinearizableVM { + mock := &MockLinearizableVM{ctrl: ctrl} + mock.recorder = &MockLinearizableVMMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDAGVM) EXPECT() *MockDAGVMMockRecorder { +func (m *MockLinearizableVM) EXPECT() *MockLinearizableVMMockRecorder { return m.recorder } // AppGossip mocks base method. -func (m *MockDAGVM) AppGossip(arg0 context.Context, arg1 ids.NodeID, arg2 []byte) error { +func (m *MockLinearizableVM) AppGossip(arg0 context.Context, arg1 ids.NodeID, arg2 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AppGossip", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -54,13 +54,13 @@ func (m *MockDAGVM) AppGossip(arg0 context.Context, arg1 ids.NodeID, arg2 []byte } // AppGossip indicates an expected call of AppGossip. -func (mr *MockDAGVMMockRecorder) AppGossip(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) AppGossip(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppGossip", reflect.TypeOf((*MockDAGVM)(nil).AppGossip), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppGossip", reflect.TypeOf((*MockLinearizableVM)(nil).AppGossip), arg0, arg1, arg2) } // AppRequest mocks base method. -func (m *MockDAGVM) AppRequest(arg0 context.Context, arg1 ids.NodeID, arg2 uint32, arg3 time.Time, arg4 []byte) error { +func (m *MockLinearizableVM) AppRequest(arg0 context.Context, arg1 ids.NodeID, arg2 uint32, arg3 time.Time, arg4 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AppRequest", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(error) @@ -68,13 +68,13 @@ func (m *MockDAGVM) AppRequest(arg0 context.Context, arg1 ids.NodeID, arg2 uint3 } // AppRequest indicates an expected call of AppRequest. -func (mr *MockDAGVMMockRecorder) AppRequest(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) AppRequest(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppRequest", reflect.TypeOf((*MockDAGVM)(nil).AppRequest), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppRequest", reflect.TypeOf((*MockLinearizableVM)(nil).AppRequest), arg0, arg1, arg2, arg3, arg4) } // AppRequestFailed mocks base method. -func (m *MockDAGVM) AppRequestFailed(arg0 context.Context, arg1 ids.NodeID, arg2 uint32) error { +func (m *MockLinearizableVM) AppRequestFailed(arg0 context.Context, arg1 ids.NodeID, arg2 uint32) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AppRequestFailed", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -82,13 +82,13 @@ func (m *MockDAGVM) AppRequestFailed(arg0 context.Context, arg1 ids.NodeID, arg2 } // AppRequestFailed indicates an expected call of AppRequestFailed. -func (mr *MockDAGVMMockRecorder) AppRequestFailed(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) AppRequestFailed(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppRequestFailed", reflect.TypeOf((*MockDAGVM)(nil).AppRequestFailed), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppRequestFailed", reflect.TypeOf((*MockLinearizableVM)(nil).AppRequestFailed), arg0, arg1, arg2) } // AppResponse mocks base method. -func (m *MockDAGVM) AppResponse(arg0 context.Context, arg1 ids.NodeID, arg2 uint32, arg3 []byte) error { +func (m *MockLinearizableVM) AppResponse(arg0 context.Context, arg1 ids.NodeID, arg2 uint32, arg3 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AppResponse", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) @@ -96,13 +96,13 @@ func (m *MockDAGVM) AppResponse(arg0 context.Context, arg1 ids.NodeID, arg2 uint } // AppResponse indicates an expected call of AppResponse. -func (mr *MockDAGVMMockRecorder) AppResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) AppResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppResponse", reflect.TypeOf((*MockDAGVM)(nil).AppResponse), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppResponse", reflect.TypeOf((*MockLinearizableVM)(nil).AppResponse), arg0, arg1, arg2, arg3) } // BuildBlock mocks base method. -func (m *MockDAGVM) BuildBlock(arg0 context.Context) (snowman.Block, error) { +func (m *MockLinearizableVM) BuildBlock(arg0 context.Context) (snowman.Block, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BuildBlock", arg0) ret0, _ := ret[0].(snowman.Block) @@ -111,13 +111,13 @@ func (m *MockDAGVM) BuildBlock(arg0 context.Context) (snowman.Block, error) { } // BuildBlock indicates an expected call of BuildBlock. -func (mr *MockDAGVMMockRecorder) BuildBlock(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) BuildBlock(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildBlock", reflect.TypeOf((*MockDAGVM)(nil).BuildBlock), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildBlock", reflect.TypeOf((*MockLinearizableVM)(nil).BuildBlock), arg0) } // Connected mocks base method. -func (m *MockDAGVM) Connected(arg0 context.Context, arg1 ids.NodeID, arg2 *version.Application) error { +func (m *MockLinearizableVM) Connected(arg0 context.Context, arg1 ids.NodeID, arg2 *version.Application) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Connected", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -125,13 +125,13 @@ func (m *MockDAGVM) Connected(arg0 context.Context, arg1 ids.NodeID, arg2 *versi } // Connected indicates an expected call of Connected. -func (mr *MockDAGVMMockRecorder) Connected(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) Connected(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connected", reflect.TypeOf((*MockDAGVM)(nil).Connected), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connected", reflect.TypeOf((*MockLinearizableVM)(nil).Connected), arg0, arg1, arg2) } // CreateHandlers mocks base method. -func (m *MockDAGVM) CreateHandlers(arg0 context.Context) (map[string]*common.HTTPHandler, error) { +func (m *MockLinearizableVM) CreateHandlers(arg0 context.Context) (map[string]*common.HTTPHandler, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateHandlers", arg0) ret0, _ := ret[0].(map[string]*common.HTTPHandler) @@ -140,13 +140,13 @@ func (m *MockDAGVM) CreateHandlers(arg0 context.Context) (map[string]*common.HTT } // CreateHandlers indicates an expected call of CreateHandlers. -func (mr *MockDAGVMMockRecorder) CreateHandlers(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) CreateHandlers(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHandlers", reflect.TypeOf((*MockDAGVM)(nil).CreateHandlers), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHandlers", reflect.TypeOf((*MockLinearizableVM)(nil).CreateHandlers), arg0) } // CreateStaticHandlers mocks base method. -func (m *MockDAGVM) CreateStaticHandlers(arg0 context.Context) (map[string]*common.HTTPHandler, error) { +func (m *MockLinearizableVM) CreateStaticHandlers(arg0 context.Context) (map[string]*common.HTTPHandler, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateStaticHandlers", arg0) ret0, _ := ret[0].(map[string]*common.HTTPHandler) @@ -155,13 +155,13 @@ func (m *MockDAGVM) CreateStaticHandlers(arg0 context.Context) (map[string]*comm } // CreateStaticHandlers indicates an expected call of CreateStaticHandlers. -func (mr *MockDAGVMMockRecorder) CreateStaticHandlers(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) CreateStaticHandlers(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStaticHandlers", reflect.TypeOf((*MockDAGVM)(nil).CreateStaticHandlers), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStaticHandlers", reflect.TypeOf((*MockLinearizableVM)(nil).CreateStaticHandlers), arg0) } // CrossChainAppRequest mocks base method. -func (m *MockDAGVM) CrossChainAppRequest(arg0 context.Context, arg1 ids.ID, arg2 uint32, arg3 time.Time, arg4 []byte) error { +func (m *MockLinearizableVM) CrossChainAppRequest(arg0 context.Context, arg1 ids.ID, arg2 uint32, arg3 time.Time, arg4 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CrossChainAppRequest", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(error) @@ -169,13 +169,13 @@ func (m *MockDAGVM) CrossChainAppRequest(arg0 context.Context, arg1 ids.ID, arg2 } // CrossChainAppRequest indicates an expected call of CrossChainAppRequest. -func (mr *MockDAGVMMockRecorder) CrossChainAppRequest(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) CrossChainAppRequest(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CrossChainAppRequest", reflect.TypeOf((*MockDAGVM)(nil).CrossChainAppRequest), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CrossChainAppRequest", reflect.TypeOf((*MockLinearizableVM)(nil).CrossChainAppRequest), arg0, arg1, arg2, arg3, arg4) } // CrossChainAppRequestFailed mocks base method. -func (m *MockDAGVM) CrossChainAppRequestFailed(arg0 context.Context, arg1 ids.ID, arg2 uint32) error { +func (m *MockLinearizableVM) CrossChainAppRequestFailed(arg0 context.Context, arg1 ids.ID, arg2 uint32) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CrossChainAppRequestFailed", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -183,13 +183,13 @@ func (m *MockDAGVM) CrossChainAppRequestFailed(arg0 context.Context, arg1 ids.ID } // CrossChainAppRequestFailed indicates an expected call of CrossChainAppRequestFailed. -func (mr *MockDAGVMMockRecorder) CrossChainAppRequestFailed(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) CrossChainAppRequestFailed(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CrossChainAppRequestFailed", reflect.TypeOf((*MockDAGVM)(nil).CrossChainAppRequestFailed), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CrossChainAppRequestFailed", reflect.TypeOf((*MockLinearizableVM)(nil).CrossChainAppRequestFailed), arg0, arg1, arg2) } // CrossChainAppResponse mocks base method. -func (m *MockDAGVM) CrossChainAppResponse(arg0 context.Context, arg1 ids.ID, arg2 uint32, arg3 []byte) error { +func (m *MockLinearizableVM) CrossChainAppResponse(arg0 context.Context, arg1 ids.ID, arg2 uint32, arg3 []byte) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CrossChainAppResponse", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) @@ -197,13 +197,13 @@ func (m *MockDAGVM) CrossChainAppResponse(arg0 context.Context, arg1 ids.ID, arg } // CrossChainAppResponse indicates an expected call of CrossChainAppResponse. -func (mr *MockDAGVMMockRecorder) CrossChainAppResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) CrossChainAppResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CrossChainAppResponse", reflect.TypeOf((*MockDAGVM)(nil).CrossChainAppResponse), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CrossChainAppResponse", reflect.TypeOf((*MockLinearizableVM)(nil).CrossChainAppResponse), arg0, arg1, arg2, arg3) } // Disconnected mocks base method. -func (m *MockDAGVM) Disconnected(arg0 context.Context, arg1 ids.NodeID) error { +func (m *MockLinearizableVM) Disconnected(arg0 context.Context, arg1 ids.NodeID) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Disconnected", arg0, arg1) ret0, _ := ret[0].(error) @@ -211,13 +211,13 @@ func (m *MockDAGVM) Disconnected(arg0 context.Context, arg1 ids.NodeID) error { } // Disconnected indicates an expected call of Disconnected. -func (mr *MockDAGVMMockRecorder) Disconnected(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) Disconnected(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Disconnected", reflect.TypeOf((*MockDAGVM)(nil).Disconnected), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Disconnected", reflect.TypeOf((*MockLinearizableVM)(nil).Disconnected), arg0, arg1) } // GetBlock mocks base method. -func (m *MockDAGVM) GetBlock(arg0 context.Context, arg1 ids.ID) (snowman.Block, error) { +func (m *MockLinearizableVM) GetBlock(arg0 context.Context, arg1 ids.ID) (snowman.Block, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetBlock", arg0, arg1) ret0, _ := ret[0].(snowman.Block) @@ -226,13 +226,13 @@ func (m *MockDAGVM) GetBlock(arg0 context.Context, arg1 ids.ID) (snowman.Block, } // GetBlock indicates an expected call of GetBlock. -func (mr *MockDAGVMMockRecorder) GetBlock(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) GetBlock(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlock", reflect.TypeOf((*MockDAGVM)(nil).GetBlock), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlock", reflect.TypeOf((*MockLinearizableVM)(nil).GetBlock), arg0, arg1) } // GetTx mocks base method. -func (m *MockDAGVM) GetTx(arg0 context.Context, arg1 ids.ID) (snowstorm.Tx, error) { +func (m *MockLinearizableVM) GetTx(arg0 context.Context, arg1 ids.ID) (snowstorm.Tx, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTx", arg0, arg1) ret0, _ := ret[0].(snowstorm.Tx) @@ -241,13 +241,13 @@ func (m *MockDAGVM) GetTx(arg0 context.Context, arg1 ids.ID) (snowstorm.Tx, erro } // GetTx indicates an expected call of GetTx. -func (mr *MockDAGVMMockRecorder) GetTx(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) GetTx(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTx", reflect.TypeOf((*MockDAGVM)(nil).GetTx), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTx", reflect.TypeOf((*MockLinearizableVM)(nil).GetTx), arg0, arg1) } // HealthCheck mocks base method. -func (m *MockDAGVM) HealthCheck(arg0 context.Context) (interface{}, error) { +func (m *MockLinearizableVM) HealthCheck(arg0 context.Context) (interface{}, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "HealthCheck", arg0) ret0, _ := ret[0].(interface{}) @@ -256,13 +256,13 @@ func (m *MockDAGVM) HealthCheck(arg0 context.Context) (interface{}, error) { } // HealthCheck indicates an expected call of HealthCheck. -func (mr *MockDAGVMMockRecorder) HealthCheck(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) HealthCheck(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HealthCheck", reflect.TypeOf((*MockDAGVM)(nil).HealthCheck), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HealthCheck", reflect.TypeOf((*MockLinearizableVM)(nil).HealthCheck), arg0) } // Initialize mocks base method. -func (m *MockDAGVM) Initialize(arg0 context.Context, arg1 *snow.Context, arg2 manager.Manager, arg3, arg4, arg5 []byte, arg6 chan<- common.Message, arg7 []*common.Fx, arg8 common.AppSender) error { +func (m *MockLinearizableVM) Initialize(arg0 context.Context, arg1 *snow.Context, arg2 manager.Manager, arg3, arg4, arg5 []byte, arg6 chan<- common.Message, arg7 []*common.Fx, arg8 common.AppSender) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Initialize", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) ret0, _ := ret[0].(error) @@ -270,13 +270,13 @@ func (m *MockDAGVM) Initialize(arg0 context.Context, arg1 *snow.Context, arg2 ma } // Initialize indicates an expected call of Initialize. -func (mr *MockDAGVMMockRecorder) Initialize(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) Initialize(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Initialize", reflect.TypeOf((*MockDAGVM)(nil).Initialize), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Initialize", reflect.TypeOf((*MockLinearizableVM)(nil).Initialize), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) } // LastAccepted mocks base method. -func (m *MockDAGVM) LastAccepted(arg0 context.Context) (ids.ID, error) { +func (m *MockLinearizableVM) LastAccepted(arg0 context.Context) (ids.ID, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "LastAccepted", arg0) ret0, _ := ret[0].(ids.ID) @@ -285,13 +285,13 @@ func (m *MockDAGVM) LastAccepted(arg0 context.Context) (ids.ID, error) { } // LastAccepted indicates an expected call of LastAccepted. -func (mr *MockDAGVMMockRecorder) LastAccepted(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) LastAccepted(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastAccepted", reflect.TypeOf((*MockDAGVM)(nil).LastAccepted), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastAccepted", reflect.TypeOf((*MockLinearizableVM)(nil).LastAccepted), arg0) } // Linearize mocks base method. -func (m *MockDAGVM) Linearize(arg0 context.Context, arg1 ids.ID) error { +func (m *MockLinearizableVM) Linearize(arg0 context.Context, arg1 ids.ID) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Linearize", arg0, arg1) ret0, _ := ret[0].(error) @@ -299,13 +299,13 @@ func (m *MockDAGVM) Linearize(arg0 context.Context, arg1 ids.ID) error { } // Linearize indicates an expected call of Linearize. -func (mr *MockDAGVMMockRecorder) Linearize(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) Linearize(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Linearize", reflect.TypeOf((*MockDAGVM)(nil).Linearize), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Linearize", reflect.TypeOf((*MockLinearizableVM)(nil).Linearize), arg0, arg1) } // ParseBlock mocks base method. -func (m *MockDAGVM) ParseBlock(arg0 context.Context, arg1 []byte) (snowman.Block, error) { +func (m *MockLinearizableVM) ParseBlock(arg0 context.Context, arg1 []byte) (snowman.Block, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ParseBlock", arg0, arg1) ret0, _ := ret[0].(snowman.Block) @@ -314,13 +314,13 @@ func (m *MockDAGVM) ParseBlock(arg0 context.Context, arg1 []byte) (snowman.Block } // ParseBlock indicates an expected call of ParseBlock. -func (mr *MockDAGVMMockRecorder) ParseBlock(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) ParseBlock(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParseBlock", reflect.TypeOf((*MockDAGVM)(nil).ParseBlock), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParseBlock", reflect.TypeOf((*MockLinearizableVM)(nil).ParseBlock), arg0, arg1) } // ParseTx mocks base method. -func (m *MockDAGVM) ParseTx(arg0 context.Context, arg1 []byte) (snowstorm.Tx, error) { +func (m *MockLinearizableVM) ParseTx(arg0 context.Context, arg1 []byte) (snowstorm.Tx, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ParseTx", arg0, arg1) ret0, _ := ret[0].(snowstorm.Tx) @@ -329,13 +329,13 @@ func (m *MockDAGVM) ParseTx(arg0 context.Context, arg1 []byte) (snowstorm.Tx, er } // ParseTx indicates an expected call of ParseTx. -func (mr *MockDAGVMMockRecorder) ParseTx(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) ParseTx(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParseTx", reflect.TypeOf((*MockDAGVM)(nil).ParseTx), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParseTx", reflect.TypeOf((*MockLinearizableVM)(nil).ParseTx), arg0, arg1) } // PendingTxs mocks base method. -func (m *MockDAGVM) PendingTxs(arg0 context.Context) []snowstorm.Tx { +func (m *MockLinearizableVM) PendingTxs(arg0 context.Context) []snowstorm.Tx { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PendingTxs", arg0) ret0, _ := ret[0].([]snowstorm.Tx) @@ -343,13 +343,13 @@ func (m *MockDAGVM) PendingTxs(arg0 context.Context) []snowstorm.Tx { } // PendingTxs indicates an expected call of PendingTxs. -func (mr *MockDAGVMMockRecorder) PendingTxs(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) PendingTxs(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingTxs", reflect.TypeOf((*MockDAGVM)(nil).PendingTxs), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingTxs", reflect.TypeOf((*MockLinearizableVM)(nil).PendingTxs), arg0) } // SetPreference mocks base method. -func (m *MockDAGVM) SetPreference(arg0 context.Context, arg1 ids.ID) error { +func (m *MockLinearizableVM) SetPreference(arg0 context.Context, arg1 ids.ID) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SetPreference", arg0, arg1) ret0, _ := ret[0].(error) @@ -357,13 +357,13 @@ func (m *MockDAGVM) SetPreference(arg0 context.Context, arg1 ids.ID) error { } // SetPreference indicates an expected call of SetPreference. -func (mr *MockDAGVMMockRecorder) SetPreference(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) SetPreference(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPreference", reflect.TypeOf((*MockDAGVM)(nil).SetPreference), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPreference", reflect.TypeOf((*MockLinearizableVM)(nil).SetPreference), arg0, arg1) } // SetState mocks base method. -func (m *MockDAGVM) SetState(arg0 context.Context, arg1 snow.State) error { +func (m *MockLinearizableVM) SetState(arg0 context.Context, arg1 snow.State) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SetState", arg0, arg1) ret0, _ := ret[0].(error) @@ -371,13 +371,13 @@ func (m *MockDAGVM) SetState(arg0 context.Context, arg1 snow.State) error { } // SetState indicates an expected call of SetState. -func (mr *MockDAGVMMockRecorder) SetState(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) SetState(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetState", reflect.TypeOf((*MockDAGVM)(nil).SetState), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetState", reflect.TypeOf((*MockLinearizableVM)(nil).SetState), arg0, arg1) } // Shutdown mocks base method. -func (m *MockDAGVM) Shutdown(arg0 context.Context) error { +func (m *MockLinearizableVM) Shutdown(arg0 context.Context) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Shutdown", arg0) ret0, _ := ret[0].(error) @@ -385,13 +385,13 @@ func (m *MockDAGVM) Shutdown(arg0 context.Context) error { } // Shutdown indicates an expected call of Shutdown. -func (mr *MockDAGVMMockRecorder) Shutdown(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) Shutdown(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Shutdown", reflect.TypeOf((*MockDAGVM)(nil).Shutdown), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Shutdown", reflect.TypeOf((*MockLinearizableVM)(nil).Shutdown), arg0) } // Version mocks base method. -func (m *MockDAGVM) Version(arg0 context.Context) (string, error) { +func (m *MockLinearizableVM) Version(arg0 context.Context) (string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Version", arg0) ret0, _ := ret[0].(string) @@ -400,7 +400,7 @@ func (m *MockDAGVM) Version(arg0 context.Context) (string, error) { } // Version indicates an expected call of Version. -func (mr *MockDAGVMMockRecorder) Version(arg0 interface{}) *gomock.Call { +func (mr *MockLinearizableVMMockRecorder) Version(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockDAGVM)(nil).Version), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockLinearizableVM)(nil).Version), arg0) } diff --git a/snow/engine/avalanche/vertex/test_vm.go b/snow/engine/avalanche/vertex/test_vm.go index 235df05c43eb..d83154e12167 100644 --- a/snow/engine/avalanche/vertex/test_vm.go +++ b/snow/engine/avalanche/vertex/test_vm.go @@ -16,7 +16,7 @@ var ( errPending = errors.New("unexpectedly called Pending") errLinearize = errors.New("unexpectedly called Linearize") - _ DAGVM = (*TestVM)(nil) + _ LinearizableVM = (*TestVM)(nil) ) type TestVM struct { diff --git a/snow/engine/avalanche/vertex/vm.go b/snow/engine/avalanche/vertex/vm.go index f7993c7a484b..467c2624d7aa 100644 --- a/snow/engine/avalanche/vertex/vm.go +++ b/snow/engine/avalanche/vertex/vm.go @@ -8,26 +8,55 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/consensus/snowstorm" + "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" ) -// DAGVM defines the minimum functionality that an avalanche VM must -// implement -type DAGVM interface { - block.ChainVM - Getter +type LinearizableVMWithEngine interface { + DAGVM // Linearize is called after [Initialize] and after the DAG has been // finalized. After Linearize is called: + // // - PendingTxs will never be called again // - GetTx will never be called again // - ParseTx may still be called // - All the block based functions of the [block.ChainVM] must work as // expected. + // + // Linearize is part of the VM initialization, and will be called at most + // once per VM instantiation. This means that Linearize should be called + // every time the chain restarts after the DAG has finalized. + Linearize( + ctx context.Context, + stopVertexID ids.ID, + toEngine chan<- common.Message, + ) error +} + +type LinearizableVM interface { + DAGVM + + // Linearize is called after [Initialize] and after the DAG has been + // finalized. After Linearize is called: + // + // - PendingTxs will never be called again + // - GetTx will never be called again + // - ParseTx may still be called + // - All the block based functions of the [block.ChainVM] must work as + // expected. + // // Linearize is part of the VM initialization, and will be called at most // once per VM instantiation. This means that Linearize should be called // every time the chain restarts after the DAG has finalized. Linearize(ctx context.Context, stopVertexID ids.ID) error +} + +// DAGVM defines the minimum functionality that an avalanche VM must +// implement +type DAGVM interface { + block.ChainVM + Getter // Return any transactions that have not been sent to consensus yet PendingTxs(ctx context.Context) []snowstorm.Tx diff --git a/snow/engine/avalanche/voter.go b/snow/engine/avalanche/voter.go index 0632178cc93e..7b8104305cd5 100644 --- a/snow/engine/avalanche/voter.go +++ b/snow/engine/avalanche/voter.go @@ -49,6 +49,12 @@ func (v *voter) Update(ctx context.Context) { return } + previouslyLinearized, err := v.t.Manager.StopVertexAccepted(ctx) + if err != nil { + v.t.errs.Add(err) + return + } + for _, result := range results { result := result v.t.Ctx.Log.Debug("filtering poll results", @@ -70,6 +76,38 @@ func (v *voter) Update(ctx context.Context) { } } + linearized, err := v.t.Manager.StopVertexAccepted(ctx) + if err != nil { + v.t.errs.Add(err) + return + } + + if linearized { + // We guard here to ensure we only call the underlying vm.Linearize and + // startSnowmanConsensus calls once. + if !previouslyLinearized { + // After the chain has been linearized, we will not be issuing any new + // vertices. + v.t.pendingTxs = nil + v.t.metrics.pendingTxs.Set(0) + + // Invariant: The edge should only be the stop vertex after the + // linearization. + edge := v.t.Manager.Edge(ctx) + stopVertexID := edge[0] + if err := v.t.VM.Linearize(ctx, stopVertexID); err != nil { + v.t.errs.Add(err) + return + } + if err := v.t.startSnowmanConsensus(ctx, v.t.RequestID); err != nil { + v.t.errs.Add(err) + } + } + // If the chain has been linearized, there can't be any orphans, so we + // can exit here. + return + } + orphans := v.t.Consensus.Orphans() txs := make([]snowstorm.Tx, 0, orphans.Len()) for orphanID := range orphans { diff --git a/snow/engine/avalanche/voter_test.go b/snow/engine/avalanche/voter_test.go index c87a052d5ac8..46f63a3a2d95 100644 --- a/snow/engine/avalanche/voter_test.go +++ b/snow/engine/avalanche/voter_test.go @@ -19,7 +19,7 @@ func TestVotingFinishesWithAbandonedDep(t *testing.T) { _, _, engCfg := DefaultConfig() mngr := vertex.NewTestManager(t) engCfg.Manager = mngr - transitive, err := newTransitive(engCfg) + transitive, err := newTransitive(engCfg, noopStarter) require.NoError(t, err) require.NoError(t, transitive.Start(context.Background(), 0 /*=startReqID*/)) @@ -110,7 +110,7 @@ func TestVotingFinishesWithAbandonDepMiddleRequest(t *testing.T) { _, _, engCfg := DefaultConfig() mngr := vertex.NewTestManager(t) engCfg.Manager = mngr - transitive, err := newTransitive(engCfg) + transitive, err := newTransitive(engCfg, noopStarter) require.NoError(t, err) require.NoError(t, transitive.Start(context.Background(), 0 /*=startReqID*/)) @@ -244,7 +244,7 @@ func TestSharedDependency(t *testing.T) { _, _, engCfg := DefaultConfig() mngr := vertex.NewTestManager(t) engCfg.Manager = mngr - transitive, err := newTransitive(engCfg) + transitive, err := newTransitive(engCfg, noopStarter) require.NoError(t, err) require.NoError(t, transitive.Start(context.Background(), 0 /*=startReqID*/)) diff --git a/tests/e2e/x/whitelist-vtx/suites.go b/tests/e2e/x/whitelist-vtx/suites.go index 7f59d99ab2e0..9a8f34899092 100644 --- a/tests/e2e/x/whitelist-vtx/suites.go +++ b/tests/e2e/x/whitelist-vtx/suites.go @@ -242,7 +242,7 @@ var _ = e2e.DescribeXChain("[WhitelistTx]", func() { } }) - ginkgo.By("issue regular, virtuous X-Chain tx, after whitelist vtx, should fail", func() { + ginkgo.By("issue regular, virtuous X-Chain tx, after whitelist vtx, should pass", func() { balances, err := wallets[0].X().Builder().GetFTBalance() gomega.Expect(err).Should(gomega.BeNil()) @@ -270,16 +270,7 @@ var _ = e2e.DescribeXChain("[WhitelistTx]", func() { common.WithContext(ctx), ) cancel() - gomega.Expect(err.Error()).Should(gomega.ContainSubstring(context.DeadlineExceeded.Error())) - - ep := uris[0] + "/ext/metrics" - mm, err := tests.GetMetricsValue(ep, allMetrics...) gomega.Expect(err).Should(gomega.BeNil()) - - // regular, virtuous transaction should not change whitelist vtx metrics - prev := curMetrics[uris[0]] - gomega.Expect(mm).Should(gomega.Equal(prev)) - curMetrics[uris[0]] = mm }) }) }) diff --git a/vms/avm/vm.go b/vms/avm/vm.go index e7907b521701..aeef4c485023 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -68,7 +68,7 @@ var ( errGenesisAssetMustHaveState = errors.New("genesis asset must have non-empty state") errBootstrapping = errors.New("chain is currently bootstrapping") - _ vertex.DAGVM = (*VM)(nil) + _ vertex.LinearizableVMWithEngine = (*VM)(nil) ) type VM struct { @@ -420,14 +420,14 @@ func (vm *VM) LastAccepted(context.Context) (ids.ID, error) { ****************************************************************************** */ -func (vm *VM) Linearize(_ context.Context, stopVertexID ids.ID) error { +func (vm *VM) Linearize(_ context.Context, stopVertexID ids.ID, toEngine chan<- common.Message) error { time := version.GetCortinaTime(vm.ctx.NetworkID) err := vm.state.InitializeChainState(stopVertexID, time) if err != nil { return err } - mempool, err := mempool.New("mempool", vm.registerer, vm.toEngine) + mempool, err := mempool.New("mempool", vm.registerer, toEngine) if err != nil { return fmt.Errorf("failed to create mempool: %w", err) } diff --git a/vms/metervm/vertex_vm.go b/vms/metervm/vertex_vm.go index 504d2f7294e0..e1f98191d0d5 100644 --- a/vms/metervm/vertex_vm.go +++ b/vms/metervm/vertex_vm.go @@ -19,18 +19,18 @@ import ( ) var ( - _ vertex.DAGVM = (*vertexVM)(nil) - _ snowstorm.Tx = (*meterTx)(nil) + _ vertex.LinearizableVMWithEngine = (*vertexVM)(nil) + _ snowstorm.Tx = (*meterTx)(nil) ) -func NewVertexVM(vm vertex.DAGVM) vertex.DAGVM { +func NewVertexVM(vm vertex.LinearizableVMWithEngine) vertex.LinearizableVMWithEngine { return &vertexVM{ - DAGVM: vm, + LinearizableVMWithEngine: vm, } } type vertexVM struct { - vertex.DAGVM + vertex.LinearizableVMWithEngine vertexMetrics clock mockable.Clock } @@ -64,7 +64,7 @@ func (vm *vertexVM) Initialize( } chainCtx.Metrics = optionalGatherer - return vm.DAGVM.Initialize( + return vm.LinearizableVMWithEngine.Initialize( ctx, chainCtx, db, @@ -79,7 +79,7 @@ func (vm *vertexVM) Initialize( func (vm *vertexVM) PendingTxs(ctx context.Context) []snowstorm.Tx { start := vm.clock.Time() - txs := vm.DAGVM.PendingTxs(ctx) + txs := vm.LinearizableVMWithEngine.PendingTxs(ctx) end := vm.clock.Time() vm.vertexMetrics.pending.Observe(float64(end.Sub(start))) return txs @@ -87,7 +87,7 @@ func (vm *vertexVM) PendingTxs(ctx context.Context) []snowstorm.Tx { func (vm *vertexVM) ParseTx(ctx context.Context, b []byte) (snowstorm.Tx, error) { start := vm.clock.Time() - tx, err := vm.DAGVM.ParseTx(ctx, b) + tx, err := vm.LinearizableVMWithEngine.ParseTx(ctx, b) end := vm.clock.Time() duration := float64(end.Sub(start)) if err != nil { @@ -103,7 +103,7 @@ func (vm *vertexVM) ParseTx(ctx context.Context, b []byte) (snowstorm.Tx, error) func (vm *vertexVM) GetTx(ctx context.Context, txID ids.ID) (snowstorm.Tx, error) { start := vm.clock.Time() - tx, err := vm.DAGVM.GetTx(ctx, txID) + tx, err := vm.LinearizableVMWithEngine.GetTx(ctx, txID) end := vm.clock.Time() duration := float64(end.Sub(start)) if err != nil { diff --git a/vms/tracedvm/vertex_vm.go b/vms/tracedvm/vertex_vm.go index 46c47ad32ba5..9c6c223af30a 100644 --- a/vms/tracedvm/vertex_vm.go +++ b/vms/tracedvm/vertex_vm.go @@ -19,17 +19,17 @@ import ( "github.com/ava-labs/avalanchego/trace" ) -var _ vertex.DAGVM = (*vertexVM)(nil) +var _ vertex.LinearizableVMWithEngine = (*vertexVM)(nil) type vertexVM struct { - vertex.DAGVM + vertex.LinearizableVMWithEngine tracer trace.Tracer } -func NewVertexVM(vm vertex.DAGVM, tracer trace.Tracer) vertex.DAGVM { +func NewVertexVM(vm vertex.LinearizableVMWithEngine, tracer trace.Tracer) vertex.LinearizableVMWithEngine { return &vertexVM{ - DAGVM: vm, - tracer: tracer, + LinearizableVMWithEngine: vm, + tracer: tracer, } } @@ -47,7 +47,7 @@ func (vm *vertexVM) Initialize( ctx, span := vm.tracer.Start(ctx, "vertexVM.Initialize") defer span.End() - return vm.DAGVM.Initialize( + return vm.LinearizableVMWithEngine.Initialize( ctx, chainCtx, db, @@ -64,7 +64,7 @@ func (vm *vertexVM) PendingTxs(ctx context.Context) []snowstorm.Tx { ctx, span := vm.tracer.Start(ctx, "vertexVM.PendingTxs") defer span.End() - return vm.DAGVM.PendingTxs(ctx) + return vm.LinearizableVMWithEngine.PendingTxs(ctx) } func (vm *vertexVM) ParseTx(ctx context.Context, txBytes []byte) (snowstorm.Tx, error) { @@ -73,7 +73,7 @@ func (vm *vertexVM) ParseTx(ctx context.Context, txBytes []byte) (snowstorm.Tx, )) defer span.End() - tx, err := vm.DAGVM.ParseTx(ctx, txBytes) + tx, err := vm.LinearizableVMWithEngine.ParseTx(ctx, txBytes) return &tracedTx{ Tx: tx, tracer: vm.tracer, @@ -86,7 +86,7 @@ func (vm *vertexVM) GetTx(ctx context.Context, txID ids.ID) (snowstorm.Tx, error )) defer span.End() - tx, err := vm.DAGVM.GetTx(ctx, txID) + tx, err := vm.LinearizableVMWithEngine.GetTx(ctx, txID) return &tracedTx{ Tx: tx, tracer: vm.tracer,