github.com/MetalBlockchain/metalgo@v1.11.9/vms/proposervm/post_fork_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 proposervm
     5  
     6  import (
     7  	"context"
     8  
     9  	"github.com/MetalBlockchain/metalgo/ids"
    10  	"github.com/MetalBlockchain/metalgo/snow/choices"
    11  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowman"
    12  	"github.com/MetalBlockchain/metalgo/vms/proposervm/block"
    13  )
    14  
    15  var _ PostForkBlock = (*postForkBlock)(nil)
    16  
    17  type postForkBlock struct {
    18  	block.SignedBlock
    19  	postForkCommonComponents
    20  
    21  	// slot of the proposer that produced this block.
    22  	// It is populated in verifyPostDurangoBlockDelay.
    23  	// It is used to report metrics during Accept.
    24  	slot *uint64
    25  }
    26  
    27  // Accept:
    28  // 1) Sets this blocks status to Accepted.
    29  // 2) Persists this block in storage
    30  // 3) Calls Reject() on siblings of this block and their descendants.
    31  func (b *postForkBlock) Accept(ctx context.Context) error {
    32  	if err := b.acceptOuterBlk(); err != nil {
    33  		return err
    34  	}
    35  	if err := b.acceptInnerBlk(ctx); err != nil {
    36  		return err
    37  	}
    38  	if b.slot != nil {
    39  		b.vm.acceptedBlocksSlotHistogram.Observe(float64(*b.slot))
    40  	}
    41  	return nil
    42  }
    43  
    44  func (b *postForkBlock) acceptOuterBlk() error {
    45  	// Update in-memory references
    46  	b.status = choices.Accepted
    47  	b.vm.lastAcceptedTime = b.Timestamp()
    48  
    49  	return b.vm.acceptPostForkBlock(b)
    50  }
    51  
    52  func (b *postForkBlock) acceptInnerBlk(ctx context.Context) error {
    53  	// mark the inner block as accepted and all conflicting inner blocks as
    54  	// rejected
    55  	return b.vm.Tree.Accept(ctx, b.innerBlk)
    56  }
    57  
    58  func (b *postForkBlock) Reject(context.Context) error {
    59  	// We do not reject the inner block here because it may be accepted later
    60  	delete(b.vm.verifiedBlocks, b.ID())
    61  	b.status = choices.Rejected
    62  	return nil
    63  }
    64  
    65  func (b *postForkBlock) Status() choices.Status {
    66  	if b.status == choices.Accepted && b.Height() > b.vm.lastAcceptedHeight {
    67  		return choices.Processing
    68  	}
    69  	return b.status
    70  }
    71  
    72  // Return this block's parent, or a *missing.Block if
    73  // we don't have the parent.
    74  func (b *postForkBlock) Parent() ids.ID {
    75  	return b.ParentID()
    76  }
    77  
    78  // If Verify() returns nil, Accept() or Reject() will eventually be called on
    79  // [b] and [b.innerBlk]
    80  func (b *postForkBlock) Verify(ctx context.Context) error {
    81  	parent, err := b.vm.getBlock(ctx, b.ParentID())
    82  	if err != nil {
    83  		return err
    84  	}
    85  	return parent.verifyPostForkChild(ctx, b)
    86  }
    87  
    88  // Return the two options for the block that follows [b]
    89  func (b *postForkBlock) Options(ctx context.Context) ([2]snowman.Block, error) {
    90  	innerOracleBlk, ok := b.innerBlk.(snowman.OracleBlock)
    91  	if !ok {
    92  		// [b]'s innerBlk isn't an oracle block
    93  		return [2]snowman.Block{}, snowman.ErrNotOracle
    94  	}
    95  
    96  	// The inner block's child options
    97  	innerOptions, err := innerOracleBlk.Options(ctx)
    98  	if err != nil {
    99  		return [2]snowman.Block{}, err
   100  	}
   101  
   102  	parentID := b.ID()
   103  	outerOptions := [2]snowman.Block{}
   104  	for i, innerOption := range innerOptions {
   105  		// Wrap the inner block's child option
   106  		statelessOuterOption, err := block.BuildOption(
   107  			parentID,
   108  			innerOption.Bytes(),
   109  		)
   110  		if err != nil {
   111  			return [2]snowman.Block{}, err
   112  		}
   113  
   114  		outerOptions[i] = &postForkOption{
   115  			Block: statelessOuterOption,
   116  			postForkCommonComponents: postForkCommonComponents{
   117  				vm:       b.vm,
   118  				innerBlk: innerOption,
   119  				status:   innerOption.Status(),
   120  			},
   121  		}
   122  	}
   123  	return outerOptions, nil
   124  }
   125  
   126  // A post-fork block can never have a pre-fork child
   127  func (*postForkBlock) verifyPreForkChild(context.Context, *preForkBlock) error {
   128  	return errUnsignedChild
   129  }
   130  
   131  func (b *postForkBlock) verifyPostForkChild(ctx context.Context, child *postForkBlock) error {
   132  	parentTimestamp := b.Timestamp()
   133  	parentPChainHeight := b.PChainHeight()
   134  	return b.postForkCommonComponents.Verify(
   135  		ctx,
   136  		parentTimestamp,
   137  		parentPChainHeight,
   138  		child,
   139  	)
   140  }
   141  
   142  func (b *postForkBlock) verifyPostForkOption(ctx context.Context, child *postForkOption) error {
   143  	if err := verifyIsOracleBlock(ctx, b.innerBlk); err != nil {
   144  		return err
   145  	}
   146  
   147  	// Make sure [b]'s inner block is the parent of [child]'s inner block
   148  	expectedInnerParentID := b.innerBlk.ID()
   149  	innerParentID := child.innerBlk.Parent()
   150  	if innerParentID != expectedInnerParentID {
   151  		return errInnerParentMismatch
   152  	}
   153  
   154  	return child.vm.verifyAndRecordInnerBlk(ctx, nil, child)
   155  }
   156  
   157  // Return the child (a *postForkBlock) of this block
   158  func (b *postForkBlock) buildChild(ctx context.Context) (Block, error) {
   159  	return b.postForkCommonComponents.buildChild(
   160  		ctx,
   161  		b.ID(),
   162  		b.Timestamp(),
   163  		b.PChainHeight(),
   164  	)
   165  }
   166  
   167  func (b *postForkBlock) pChainHeight(context.Context) (uint64, error) {
   168  	return b.PChainHeight(), nil
   169  }
   170  
   171  func (b *postForkBlock) setStatus(status choices.Status) {
   172  	b.status = status
   173  }
   174  
   175  func (b *postForkBlock) getStatelessBlk() block.Block {
   176  	return b.SignedBlock
   177  }