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 }