github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/block/executor/block.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package executor
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	"go.uber.org/zap"
    11  
    12  	"github.com/MetalBlockchain/metalgo/database"
    13  	"github.com/MetalBlockchain/metalgo/snow/choices"
    14  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowman"
    15  	"github.com/MetalBlockchain/metalgo/vms/platformvm/block"
    16  )
    17  
    18  var (
    19  	_ snowman.Block       = (*Block)(nil)
    20  	_ snowman.OracleBlock = (*Block)(nil)
    21  )
    22  
    23  // Exported for testing in platformvm package.
    24  type Block struct {
    25  	block.Block
    26  	manager *manager
    27  }
    28  
    29  func (b *Block) Verify(context.Context) error {
    30  	blkID := b.ID()
    31  	if _, ok := b.manager.blkIDToState[blkID]; ok {
    32  		// This block has already been verified.
    33  		return nil
    34  	}
    35  
    36  	return b.Visit(b.manager.verifier)
    37  }
    38  
    39  func (b *Block) Accept(context.Context) error {
    40  	return b.Visit(b.manager.acceptor)
    41  }
    42  
    43  func (b *Block) Reject(context.Context) error {
    44  	return b.Visit(b.manager.rejector)
    45  }
    46  
    47  func (b *Block) Status() choices.Status {
    48  	blkID := b.ID()
    49  	// If this block is an accepted Proposal block with no accepted children, it
    50  	// will be in [blkIDToState], but we should return accepted, not processing,
    51  	// so we do this check.
    52  	if b.manager.lastAccepted == blkID {
    53  		return choices.Accepted
    54  	}
    55  	// Check if the block is in memory. If so, it's processing.
    56  	if _, ok := b.manager.blkIDToState[blkID]; ok {
    57  		return choices.Processing
    58  	}
    59  	// Block isn't in memory. Check in the database.
    60  	_, err := b.manager.state.GetStatelessBlock(blkID)
    61  	switch err {
    62  	case nil:
    63  		return choices.Accepted
    64  
    65  	case database.ErrNotFound:
    66  		// choices.Unknown means we don't have the bytes of the block.
    67  		// In this case, we do, so we return choices.Processing.
    68  		return choices.Processing
    69  
    70  	default:
    71  		// TODO: correctly report this error to the consensus engine.
    72  		b.manager.ctx.Log.Error(
    73  			"dropping unhandled database error",
    74  			zap.Error(err),
    75  		)
    76  		return choices.Processing
    77  	}
    78  }
    79  
    80  func (b *Block) Timestamp() time.Time {
    81  	return b.manager.getTimestamp(b.ID())
    82  }
    83  
    84  func (b *Block) Options(context.Context) ([2]snowman.Block, error) {
    85  	options := options{
    86  		log:                     b.manager.ctx.Log,
    87  		primaryUptimePercentage: b.manager.txExecutorBackend.Config.UptimePercentage,
    88  		uptimes:                 b.manager.txExecutorBackend.Uptimes,
    89  		state:                   b.manager.backend.state,
    90  	}
    91  	if err := b.Block.Visit(&options); err != nil {
    92  		return [2]snowman.Block{}, err
    93  	}
    94  
    95  	return [2]snowman.Block{
    96  		b.manager.NewBlock(options.preferredBlock),
    97  		b.manager.NewBlock(options.alternateBlock),
    98  	}, nil
    99  }