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 }