github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/avalanche/bootstrap/vertex_job.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package bootstrap
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  
    11  	"github.com/prometheus/client_golang/prometheus"
    12  	"go.uber.org/zap"
    13  
    14  	"github.com/MetalBlockchain/metalgo/ids"
    15  	"github.com/MetalBlockchain/metalgo/snow/choices"
    16  	"github.com/MetalBlockchain/metalgo/snow/consensus/avalanche"
    17  	"github.com/MetalBlockchain/metalgo/snow/engine/avalanche/bootstrap/queue"
    18  	"github.com/MetalBlockchain/metalgo/snow/engine/avalanche/vertex"
    19  	"github.com/MetalBlockchain/metalgo/utils/logging"
    20  	"github.com/MetalBlockchain/metalgo/utils/set"
    21  )
    22  
    23  var (
    24  	errMissingVtxDependenciesOnAccept = errors.New("attempting to execute blocked vertex")
    25  	errTxNotAcceptedInVtxOnAccept     = errors.New("attempting to execute vertex with non-accepted transaction")
    26  )
    27  
    28  type vtxParser struct {
    29  	log         logging.Logger
    30  	numAccepted prometheus.Counter
    31  	manager     vertex.Manager
    32  }
    33  
    34  func (p *vtxParser) Parse(ctx context.Context, vtxBytes []byte) (queue.Job, error) {
    35  	vtx, err := p.manager.ParseVtx(ctx, vtxBytes)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	return &vertexJob{
    40  		log:         p.log,
    41  		numAccepted: p.numAccepted,
    42  		vtx:         vtx,
    43  	}, nil
    44  }
    45  
    46  type vertexJob struct {
    47  	log         logging.Logger
    48  	numAccepted prometheus.Counter
    49  	vtx         avalanche.Vertex
    50  }
    51  
    52  func (v *vertexJob) ID() ids.ID {
    53  	return v.vtx.ID()
    54  }
    55  
    56  func (v *vertexJob) MissingDependencies(context.Context) (set.Set[ids.ID], error) {
    57  	missing := set.Set[ids.ID]{}
    58  	parents, err := v.vtx.Parents()
    59  	if err != nil {
    60  		return missing, err
    61  	}
    62  	for _, parent := range parents {
    63  		if parent.Status() != choices.Accepted {
    64  			missing.Add(parent.ID())
    65  		}
    66  	}
    67  	return missing, nil
    68  }
    69  
    70  // Returns true if this vertex job has at least 1 missing dependency
    71  func (v *vertexJob) HasMissingDependencies(context.Context) (bool, error) {
    72  	parents, err := v.vtx.Parents()
    73  	if err != nil {
    74  		return false, err
    75  	}
    76  	for _, parent := range parents {
    77  		if parent.Status() != choices.Accepted {
    78  			return true, nil
    79  		}
    80  	}
    81  	return false, nil
    82  }
    83  
    84  func (v *vertexJob) Execute(ctx context.Context) error {
    85  	hasMissingDependencies, err := v.HasMissingDependencies(ctx)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	if hasMissingDependencies {
    90  		return errMissingVtxDependenciesOnAccept
    91  	}
    92  	txs, err := v.vtx.Txs(ctx)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	for _, tx := range txs {
    97  		if tx.Status() != choices.Accepted {
    98  			return errTxNotAcceptedInVtxOnAccept
    99  		}
   100  	}
   101  	status := v.vtx.Status()
   102  	switch status {
   103  	case choices.Unknown, choices.Rejected:
   104  		return fmt.Errorf("attempting to execute vertex with status %s", status)
   105  	case choices.Processing:
   106  		v.numAccepted.Inc()
   107  		v.log.Trace("accepting vertex in bootstrapping",
   108  			zap.Stringer("vtxID", v.vtx.ID()),
   109  		)
   110  		if err := v.vtx.Accept(ctx); err != nil {
   111  			return fmt.Errorf("failed to accept vertex in bootstrapping: %w", err)
   112  		}
   113  	}
   114  	return nil
   115  }
   116  
   117  func (v *vertexJob) Bytes() []byte {
   118  	return v.vtx.Bytes()
   119  }