github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/state/fork/terminals.go (about) 1 package fork 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/flow-go/model/flow" 7 "github.com/onflow/flow-go/storage" 8 ) 9 10 // IncludingBlock returns a Terminal implementation where we explicitly 11 // specify the ID of the lowest block that should be visited 12 type IncludingBlock flow.Identifier 13 14 // LowestHeightToVisit computes the height of the lowest block that should be visited 15 func (t IncludingBlock) LowestHeightToVisit(headers storage.Headers) (uint64, error) { 16 terminalHeader, err := headers.ByBlockID(flow.Identifier(t)) 17 if err != nil { 18 return 0, fmt.Errorf("failed to retrieve header of terminal block %x: %w", flow.Identifier(t), err) 19 } 20 return terminalHeader.Height, nil 21 } 22 23 // ConfirmTerminalReached is a self-consistency check that the lowest visited block is 24 // in fact the expected terminal. 25 func (t IncludingBlock) ConfirmTerminalReached(headers storage.Headers, lowestVisitedBlock *flow.Header) error { 26 if lowestVisitedBlock.ID() != flow.Identifier(t) { 27 return fmt.Errorf("last visited block has ID %x but expecting %x", lowestVisitedBlock.ID(), flow.Identifier(t)) 28 } 29 return nil 30 } 31 32 // ExcludingBlock returns a Terminal implementation where we explicitly 33 // specify the ID of the lowest block that should _not_ be visited anymore 34 type ExcludingBlock flow.Identifier 35 36 // LowestHeightToVisit computes the height of the lowest block that should be visited 37 func (t ExcludingBlock) LowestHeightToVisit(headers storage.Headers) (uint64, error) { 38 id := flow.Identifier(t) 39 terminalHeader, err := headers.ByBlockID(id) 40 if err != nil { 41 return 0, fmt.Errorf("failed to retrieve header of terminal block %x: %w", id, err) 42 } 43 return terminalHeader.Height + 1, nil 44 } 45 46 // ConfirmTerminalReached is a self-consistency check that the lowest visited block is 47 // in fact the expected terminal. 48 func (t ExcludingBlock) ConfirmTerminalReached(headers storage.Headers, lowestVisitedBlock *flow.Header) error { 49 if lowestVisitedBlock.ParentID != flow.Identifier(t) { 50 return fmt.Errorf("parent of last visited block has ID %x but expecting %x", lowestVisitedBlock.ParentID, flow.Identifier(t)) 51 } 52 return nil 53 } 54 55 // IncludingHeight returns a Terminal implementation where we 56 // specify the height of the lowest block that should be visited 57 type IncludingHeight uint64 58 59 // LowestHeightToVisit computes the height of the lowest block that should be visited 60 func (t IncludingHeight) LowestHeightToVisit(storage.Headers) (uint64, error) { 61 return uint64(t), nil 62 } 63 64 // ConfirmTerminalReached is a self-consistency check that the lowest visited block is 65 // in fact the expected terminal. 66 func (t IncludingHeight) ConfirmTerminalReached(headers storage.Headers, lowestVisitedBlock *flow.Header) error { 67 if lowestVisitedBlock.Height != uint64(t) { 68 return fmt.Errorf("expecting terminal block with height %d but got %d", uint64(t), lowestVisitedBlock.Height) 69 } 70 return nil 71 } 72 73 // ExcludingHeight returns a Terminal implementation where we 74 // specify the Height of the lowest block that should _not_ be visited anymore 75 type ExcludingHeight uint64 76 77 // LowestHeightToVisit computes the height of the lowest block that should be visited 78 func (t ExcludingHeight) LowestHeightToVisit(storage.Headers) (uint64, error) { 79 return uint64(t) + 1, nil 80 } 81 82 // ConfirmTerminalReached is a self-consistency check that the lowest visited block is 83 // in fact the expected terminal. 84 func (t ExcludingHeight) ConfirmTerminalReached(headers storage.Headers, lowestVisitedBlock *flow.Header) error { 85 if lowestVisitedBlock.Height != uint64(t)+1 { 86 return fmt.Errorf("expecting terminal block with height %d but got %d", uint64(t)+1, lowestVisitedBlock.Height) 87 } 88 return nil 89 }