github.com/MetalBlockchain/metalgo@v1.11.9/version/compatibility.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package version
     5  
     6  import (
     7  	"errors"
     8  	"time"
     9  
    10  	"github.com/MetalBlockchain/metalgo/utils/timer/mockable"
    11  )
    12  
    13  var (
    14  	errIncompatible = errors.New("peers version is incompatible")
    15  
    16  	_ Compatibility = (*compatibility)(nil)
    17  )
    18  
    19  // Compatibility a utility for checking the compatibility of peer versions
    20  type Compatibility interface {
    21  	// Returns the local version
    22  	Version() *Application
    23  
    24  	// Returns nil if the provided version is compatible with the local version.
    25  	// This means that the version is connectable and that consensus messages
    26  	// can be made to them.
    27  	Compatible(*Application) error
    28  }
    29  
    30  type compatibility struct {
    31  	version *Application
    32  
    33  	minCompatible     *Application
    34  	minCompatibleTime time.Time
    35  	prevMinCompatible *Application
    36  
    37  	clock mockable.Clock
    38  }
    39  
    40  // NewCompatibility returns a compatibility checker with the provided options
    41  func NewCompatibility(
    42  	version *Application,
    43  	minCompatible *Application,
    44  	minCompatibleTime time.Time,
    45  	prevMinCompatible *Application,
    46  ) Compatibility {
    47  	return &compatibility{
    48  		version:           version,
    49  		minCompatible:     minCompatible,
    50  		minCompatibleTime: minCompatibleTime,
    51  		prevMinCompatible: prevMinCompatible,
    52  	}
    53  }
    54  
    55  func (c *compatibility) Version() *Application {
    56  	return c.version
    57  }
    58  
    59  func (c *compatibility) Compatible(peer *Application) error {
    60  	if err := c.version.Compatible(peer); err != nil {
    61  		return err
    62  	}
    63  
    64  	if !peer.Before(c.minCompatible) {
    65  		// The peer is at least the minimum compatible version.
    66  		return nil
    67  	}
    68  
    69  	// The peer is going to be marked as incompatible at [c.minCompatibleTime].
    70  	now := c.clock.Time()
    71  	if !now.Before(c.minCompatibleTime) {
    72  		return errIncompatible
    73  	}
    74  
    75  	// The minCompatible check isn't being enforced yet.
    76  	if !peer.Before(c.prevMinCompatible) {
    77  		// The peer is at least the previous minimum compatible version.
    78  		return nil
    79  	}
    80  	return errIncompatible
    81  }