github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/contracts/release/release.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package release contains the node service that tracks client releases.
    18  package release
    19  
    20  //go:generate abigen --sol ./contract.sol --pkg release --out ./contract.go
    21  
    22  import (
    23  	"fmt"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/atheioschain/go-atheios/accounts/abi/bind"
    28  	"github.com/atheioschain/go-atheios/common"
    29  	"github.com/atheioschain/go-atheios/eth"
    30  	"github.com/atheioschain/go-atheios/internal/ethapi"
    31  	"github.com/atheioschain/go-atheios/les"
    32  	"github.com/atheioschain/go-atheios/logger"
    33  	"github.com/atheioschain/go-atheios/logger/glog"
    34  	"github.com/atheioschain/go-atheios/node"
    35  	"github.com/atheioschain/go-atheios/p2p"
    36  	"github.com/atheioschain/go-atheios/rpc"
    37  	"golang.org/x/net/context"
    38  )
    39  
    40  // Interval to check for new releases
    41  const releaseRecheckInterval = time.Hour
    42  
    43  // Config contains the configurations of the release service.
    44  type Config struct {
    45  	Oracle common.Address // Ethereum address of the release oracle
    46  	Major  uint32         // Major version component of the release
    47  	Minor  uint32         // Minor version component of the release
    48  	Patch  uint32         // Patch version component of the release
    49  	Commit [20]byte       // Git SHA1 commit hash of the release
    50  }
    51  
    52  // ReleaseService is a node service that periodically checks the blockchain for
    53  // newly released versions of the client being run and issues a warning to the
    54  // user about it.
    55  type ReleaseService struct {
    56  	config Config          // Current version to check releases against
    57  	oracle *ReleaseOracle  // Native binding to the release oracle contract
    58  	quit   chan chan error // Quit channel to terminate the version checker
    59  }
    60  
    61  // NewReleaseService creates a new service to periodically check for new client
    62  // releases and notify the user of such.
    63  func NewReleaseService(ctx *node.ServiceContext, config Config) (node.Service, error) {
    64  	// Retrieve the Ethereum service dependency to access the blockchain
    65  	var apiBackend ethapi.Backend
    66  	var ethereum *eth.Ethereum
    67  	if err := ctx.Service(&ethereum); err == nil {
    68  		apiBackend = ethereum.ApiBackend
    69  	} else {
    70  		var ethereum *les.LightEthereum
    71  		if err := ctx.Service(&ethereum); err == nil {
    72  			apiBackend = ethereum.ApiBackend
    73  		} else {
    74  			return nil, err
    75  		}
    76  	}
    77  	// Construct the release service
    78  	contract, err := NewReleaseOracle(config.Oracle, eth.NewContractBackend(apiBackend))
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return &ReleaseService{
    83  		config: config,
    84  		oracle: contract,
    85  		quit:   make(chan chan error),
    86  	}, nil
    87  }
    88  
    89  // Protocols returns an empty list of P2P protocols as the release service does
    90  // not have a networking component.
    91  func (r *ReleaseService) Protocols() []p2p.Protocol { return nil }
    92  
    93  // APIs returns an empty list of RPC descriptors as the release service does not
    94  // expose any functioanlity to the outside world.
    95  func (r *ReleaseService) APIs() []rpc.API { return nil }
    96  
    97  // Start spawns the periodic version checker goroutine
    98  func (r *ReleaseService) Start(server *p2p.Server) error {
    99  	go r.checker()
   100  	return nil
   101  }
   102  
   103  // Stop terminates all goroutines belonging to the service, blocking until they
   104  // are all terminated.
   105  func (r *ReleaseService) Stop() error {
   106  	errc := make(chan error)
   107  	r.quit <- errc
   108  	return <-errc
   109  }
   110  
   111  // checker runs indefinitely in the background, periodically checking for new
   112  // client releases.
   113  func (r *ReleaseService) checker() {
   114  	// Set up the timers to periodically check for releases
   115  	timer := time.NewTimer(0) // Immediately fire a version check
   116  	defer timer.Stop()
   117  
   118  	for {
   119  		select {
   120  		// If the time arrived, check for a new release
   121  		case <-timer.C:
   122  			// Rechedule the timer before continuing
   123  			timer.Reset(releaseRecheckInterval)
   124  
   125  			// Retrieve the current version, and handle missing contracts gracefully
   126  			ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
   127  			opts := &bind.CallOpts{Context: ctx}
   128  			version, err := r.oracle.CurrentVersion(opts)
   129  			if err != nil {
   130  				if err == bind.ErrNoCode {
   131  					glog.V(logger.Debug).Infof("Release oracle not found at %x", r.config.Oracle)
   132  					continue
   133  				}
   134  				glog.V(logger.Error).Infof("Failed to retrieve current release: %v", err)
   135  				continue
   136  			}
   137  			// Version was successfully retrieved, notify if newer than ours
   138  			if version.Major > r.config.Major ||
   139  				(version.Major == r.config.Major && version.Minor > r.config.Minor) ||
   140  				(version.Major == r.config.Major && version.Minor == r.config.Minor && version.Patch > r.config.Patch) {
   141  
   142  				warning := fmt.Sprintf("Client v%d.%d.%d-%x seems older than the latest upstream release v%d.%d.%d-%x",
   143  					r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4])
   144  				howtofix := fmt.Sprintf("Please check https://github.com/atheioschain/go-atheios/releases for new releases")
   145  				separator := strings.Repeat("-", len(warning))
   146  
   147  				glog.V(logger.Warn).Info(separator)
   148  				glog.V(logger.Warn).Info(warning)
   149  				glog.V(logger.Warn).Info(howtofix)
   150  				glog.V(logger.Warn).Info(separator)
   151  			} else {
   152  				glog.V(logger.Debug).Infof("Client v%d.%d.%d-%x seems up to date with upstream v%d.%d.%d-%x",
   153  					r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4])
   154  			}
   155  
   156  		// If termination was requested, return
   157  		case errc := <-r.quit:
   158  			errc <- nil
   159  			return
   160  		}
   161  	}
   162  }