github.com/MetalBlockchain/metalgo@v1.11.9/vms/proposervm/post_fork_option.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package proposervm
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	"go.uber.org/zap"
    11  
    12  	"github.com/MetalBlockchain/metalgo/ids"
    13  	"github.com/MetalBlockchain/metalgo/snow/choices"
    14  	"github.com/MetalBlockchain/metalgo/vms/proposervm/block"
    15  )
    16  
    17  var _ PostForkBlock = (*postForkOption)(nil)
    18  
    19  // The parent of a *postForkOption must be a *postForkBlock.
    20  type postForkOption struct {
    21  	block.Block
    22  	postForkCommonComponents
    23  
    24  	timestamp time.Time
    25  }
    26  
    27  func (b *postForkOption) Timestamp() time.Time {
    28  	if b.Status() == choices.Accepted {
    29  		return b.vm.lastAcceptedTime
    30  	}
    31  	return b.timestamp
    32  }
    33  
    34  func (b *postForkOption) Accept(ctx context.Context) error {
    35  	if err := b.acceptOuterBlk(); err != nil {
    36  		return err
    37  	}
    38  	return b.acceptInnerBlk(ctx)
    39  }
    40  
    41  func (b *postForkOption) acceptOuterBlk() error {
    42  	// Update in-memory references
    43  	b.status = choices.Accepted
    44  
    45  	return b.vm.acceptPostForkBlock(b)
    46  }
    47  
    48  func (b *postForkOption) acceptInnerBlk(ctx context.Context) error {
    49  	// mark the inner block as accepted and all conflicting inner blocks as
    50  	// rejected
    51  	return b.vm.Tree.Accept(ctx, b.innerBlk)
    52  }
    53  
    54  func (b *postForkOption) Reject(context.Context) error {
    55  	// we do not reject the inner block here because that block may be contained
    56  	// in the proposer block that causing this block to be rejected.
    57  
    58  	delete(b.vm.verifiedBlocks, b.ID())
    59  	b.status = choices.Rejected
    60  	return nil
    61  }
    62  
    63  func (b *postForkOption) Status() choices.Status {
    64  	if b.status == choices.Accepted && b.Height() > b.vm.lastAcceptedHeight {
    65  		return choices.Processing
    66  	}
    67  	return b.status
    68  }
    69  
    70  func (b *postForkOption) Parent() ids.ID {
    71  	return b.ParentID()
    72  }
    73  
    74  // If Verify returns nil, Accept or Reject is eventually called on [b] and
    75  // [b.innerBlk].
    76  func (b *postForkOption) Verify(ctx context.Context) error {
    77  	parent, err := b.vm.getBlock(ctx, b.ParentID())
    78  	if err != nil {
    79  		return err
    80  	}
    81  	b.timestamp = parent.Timestamp()
    82  	return parent.verifyPostForkOption(ctx, b)
    83  }
    84  
    85  func (*postForkOption) verifyPreForkChild(context.Context, *preForkBlock) error {
    86  	// A *preForkBlock's parent must be a *preForkBlock
    87  	return errUnsignedChild
    88  }
    89  
    90  func (b *postForkOption) verifyPostForkChild(ctx context.Context, child *postForkBlock) error {
    91  	parentTimestamp := b.Timestamp()
    92  	parentPChainHeight, err := b.pChainHeight(ctx)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	return b.postForkCommonComponents.Verify(
    97  		ctx,
    98  		parentTimestamp,
    99  		parentPChainHeight,
   100  		child,
   101  	)
   102  }
   103  
   104  func (*postForkOption) verifyPostForkOption(context.Context, *postForkOption) error {
   105  	// A *postForkOption's parent can't be a *postForkOption
   106  	return errUnexpectedBlockType
   107  }
   108  
   109  func (b *postForkOption) buildChild(ctx context.Context) (Block, error) {
   110  	parentID := b.ID()
   111  	parentPChainHeight, err := b.pChainHeight(ctx)
   112  	if err != nil {
   113  		b.vm.ctx.Log.Error("unexpected build block failure",
   114  			zap.String("reason", "failed to fetch parent's P-chain height"),
   115  			zap.Stringer("parentID", parentID),
   116  			zap.Error(err),
   117  		)
   118  		return nil, err
   119  	}
   120  	return b.postForkCommonComponents.buildChild(
   121  		ctx,
   122  		parentID,
   123  		b.Timestamp(),
   124  		parentPChainHeight,
   125  	)
   126  }
   127  
   128  // This block's P-Chain height is its parent's P-Chain height
   129  func (b *postForkOption) pChainHeight(ctx context.Context) (uint64, error) {
   130  	parent, err := b.vm.getBlock(ctx, b.ParentID())
   131  	if err != nil {
   132  		return 0, err
   133  	}
   134  	return parent.pChainHeight(ctx)
   135  }
   136  
   137  func (b *postForkOption) setStatus(status choices.Status) {
   138  	b.status = status
   139  }
   140  
   141  func (b *postForkOption) getStatelessBlk() block.Block {
   142  	return b.Block
   143  }