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 }