release, all: integrate the release service into geth
This commit is contained in:
		| @@ -47,7 +47,8 @@ type ContractCaller interface { | |||||||
| // used when the user does not provide some needed values, but rather leaves it up | // used when the user does not provide some needed values, but rather leaves it up | ||||||
| // to the transactor to decide. | // to the transactor to decide. | ||||||
| type ContractTransactor interface { | type ContractTransactor interface { | ||||||
| 	// Nonce retrieves the current pending nonce associated with an account. | 	// PendingAccountNonce retrieves the current pending nonce associated with an | ||||||
|  | 	// account. | ||||||
| 	PendingAccountNonce(account common.Address) (uint64, error) | 	PendingAccountNonce(account common.Address) (uint64, error) | ||||||
|  |  | ||||||
| 	// SuggestGasPrice retrieves the currently suggested gas price to allow a timely | 	// SuggestGasPrice retrieves the currently suggested gas price to allow a timely | ||||||
| @@ -62,7 +63,7 @@ type ContractTransactor interface { | |||||||
| 	EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) | 	EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) | ||||||
|  |  | ||||||
| 	// SendTransaction injects the transaction into the pending pool for execution. | 	// SendTransaction injects the transaction into the pending pool for execution. | ||||||
| 	SendTransaction(*types.Transaction) error | 	SendTransaction(tx *types.Transaction) error | ||||||
| } | } | ||||||
|  |  | ||||||
| // ContractBackend defines the methods needed to allow operating with contract | // ContractBackend defines the methods needed to allow operating with contract | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/hex" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"os" | 	"os" | ||||||
| @@ -41,31 +42,48 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/metrics" | 	"github.com/ethereum/go-ethereum/metrics" | ||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/params" | 	"github.com/ethereum/go-ethereum/params" | ||||||
|  | 	"github.com/ethereum/go-ethereum/release" | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	ClientIdentifier = "Geth" | 	clientIdentifier = "Geth"     // Client identifier to advertise over the network | ||||||
| 	Version          = "1.5.0-unstable" | 	versionMajor     = 1          // Major version component of the current release | ||||||
| 	VersionMajor     = 1 | 	versionMinor     = 5          // Minor version component of the current release | ||||||
| 	VersionMinor     = 5 | 	versionPatch     = 0          // Patch version component of the current release | ||||||
| 	VersionPatch     = 0 | 	versionMeta      = "unstable" // Version metadata to append to the version string | ||||||
|  |  | ||||||
|  | 	versionOracle = "0x48a117313039b73ab02fb9f73e04a66defe123ec" // Ethereum address of the Geth release oracle | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	gitCommit       string // set via linker flagg | 	gitCommit string         // Git SHA1 commit hash of the release (set via linker flags) | ||||||
| 	nodeNameVersion string | 	verString string         // Combined textual representation of all the version components | ||||||
| 	app             *cli.App | 	relConfig release.Config // Structured version information and release oracle config | ||||||
|  | 	app       *cli.App | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| 	if gitCommit == "" { | 	// Construct the textual version string from the individual components | ||||||
| 		nodeNameVersion = Version | 	verString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPatch) | ||||||
| 	} else { | 	if versionMeta != "" { | ||||||
| 		nodeNameVersion = Version + "-" + gitCommit[:8] | 		verString += "-" + versionMeta | ||||||
| 	} | 	} | ||||||
|  | 	if gitCommit != "" { | ||||||
|  | 		verString += "-" + gitCommit[:8] | ||||||
|  | 	} | ||||||
|  | 	// Construct the version release oracle configuration | ||||||
|  | 	relConfig.Oracle = common.HexToAddress(versionOracle) | ||||||
|  |  | ||||||
| 	app = utils.NewApp(Version, "the go-ethereum command line interface") | 	relConfig.Major = uint32(versionMajor) | ||||||
|  | 	relConfig.Minor = uint32(versionMinor) | ||||||
|  | 	relConfig.Patch = uint32(versionPatch) | ||||||
|  |  | ||||||
|  | 	commit, _ := hex.DecodeString(gitCommit) | ||||||
|  | 	copy(relConfig.Commit[:], commit) | ||||||
|  |  | ||||||
|  | 	// Initialize the CLI app and start Geth | ||||||
|  | 	app = utils.NewApp(verString, "the go-ethereum command line interface") | ||||||
| 	app.Action = geth | 	app.Action = geth | ||||||
| 	app.HideVersion = true // we have a command to print the version | 	app.HideVersion = true // we have a command to print the version | ||||||
| 	app.Commands = []cli.Command{ | 	app.Commands = []cli.Command{ | ||||||
| @@ -257,7 +275,7 @@ func makeDefaultExtra() []byte { | |||||||
| 		Name      string | 		Name      string | ||||||
| 		GoVersion string | 		GoVersion string | ||||||
| 		Os        string | 		Os        string | ||||||
| 	}{uint(VersionMajor<<16 | VersionMinor<<8 | VersionPatch), ClientIdentifier, runtime.Version(), runtime.GOOS} | 	}{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS} | ||||||
| 	extra, err := rlp.EncodeToBytes(clientInfo) | 	extra, err := rlp.EncodeToBytes(clientInfo) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err) | 		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err) | ||||||
| @@ -275,7 +293,7 @@ func makeDefaultExtra() []byte { | |||||||
| // It creates a default node based on the command line arguments and runs it in | // It creates a default node based on the command line arguments and runs it in | ||||||
| // blocking mode, waiting for it to be shut down. | // blocking mode, waiting for it to be shut down. | ||||||
| func geth(ctx *cli.Context) { | func geth(ctx *cli.Context) { | ||||||
| 	node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) | 	node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx) | ||||||
| 	startNode(ctx, node) | 	startNode(ctx, node) | ||||||
| 	node.Wait() | 	node.Wait() | ||||||
| } | } | ||||||
| @@ -339,7 +357,7 @@ func initGenesis(ctx *cli.Context) { | |||||||
| // same time. | // same time. | ||||||
| func console(ctx *cli.Context) { | func console(ctx *cli.Context) { | ||||||
| 	// Create and start the node based on the CLI flags | 	// Create and start the node based on the CLI flags | ||||||
| 	node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) | 	node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx) | ||||||
| 	startNode(ctx, node) | 	startNode(ctx, node) | ||||||
|  |  | ||||||
| 	// Attach to the newly started node, and either execute script or become interactive | 	// Attach to the newly started node, and either execute script or become interactive | ||||||
| @@ -372,7 +390,7 @@ func console(ctx *cli.Context) { | |||||||
| // of the JavaScript files specified as command arguments. | // of the JavaScript files specified as command arguments. | ||||||
| func execScripts(ctx *cli.Context) { | func execScripts(ctx *cli.Context) { | ||||||
| 	// Create and start the node based on the CLI flags | 	// Create and start the node based on the CLI flags | ||||||
| 	node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) | 	node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx) | ||||||
| 	startNode(ctx, node) | 	startNode(ctx, node) | ||||||
| 	defer node.Stop() | 	defer node.Stop() | ||||||
|  |  | ||||||
| @@ -488,11 +506,8 @@ func gpubench(ctx *cli.Context) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func version(c *cli.Context) { | func version(c *cli.Context) { | ||||||
| 	fmt.Println(ClientIdentifier) | 	fmt.Println(clientIdentifier) | ||||||
| 	fmt.Println("Version:", Version) | 	fmt.Println("Version:", version) | ||||||
| 	if gitCommit != "" { |  | ||||||
| 		fmt.Println("Git Commit:", gitCommit) |  | ||||||
| 	} |  | ||||||
| 	fmt.Println("Protocol Versions:", eth.ProtocolVersions) | 	fmt.Println("Protocol Versions:", eth.ProtocolVersions) | ||||||
| 	fmt.Println("Network Id:", c.GlobalInt(utils.NetworkIdFlag.Name)) | 	fmt.Println("Network Id:", c.GlobalInt(utils.NetworkIdFlag.Name)) | ||||||
| 	fmt.Println("Go Version:", runtime.Version()) | 	fmt.Println("Go Version:", runtime.Version()) | ||||||
|   | |||||||
| @@ -34,7 +34,6 @@ import ( | |||||||
| 	"github.com/ethereum/ethash" | 	"github.com/ethereum/ethash" | ||||||
| 	"github.com/ethereum/go-ethereum/accounts" | 	"github.com/ethereum/go-ethereum/accounts" | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/versions" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core" | 	"github.com/ethereum/go-ethereum/core" | ||||||
| 	"github.com/ethereum/go-ethereum/core/state" | 	"github.com/ethereum/go-ethereum/core/state" | ||||||
| 	"github.com/ethereum/go-ethereum/crypto" | 	"github.com/ethereum/go-ethereum/crypto" | ||||||
| @@ -49,6 +48,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/p2p/nat" | 	"github.com/ethereum/go-ethereum/p2p/nat" | ||||||
| 	"github.com/ethereum/go-ethereum/params" | 	"github.com/ethereum/go-ethereum/params" | ||||||
| 	"github.com/ethereum/go-ethereum/pow" | 	"github.com/ethereum/go-ethereum/pow" | ||||||
|  | 	"github.com/ethereum/go-ethereum/release" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/ethereum/go-ethereum/whisper" | 	"github.com/ethereum/go-ethereum/whisper" | ||||||
| ) | ) | ||||||
| @@ -642,7 +642,7 @@ func MakePasswordList(ctx *cli.Context) []string { | |||||||
|  |  | ||||||
| // MakeSystemNode sets up a local node, configures the services to launch and | // MakeSystemNode sets up a local node, configures the services to launch and | ||||||
| // assembles the P2P protocol stack. | // assembles the P2P protocol stack. | ||||||
| func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node.Node { | func MakeSystemNode(name, version string, relconf release.Config, extra []byte, ctx *cli.Context) *node.Node { | ||||||
| 	// Avoid conflicting network flags | 	// Avoid conflicting network flags | ||||||
| 	networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag} | 	networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag} | ||||||
| 	for _, flag := range netFlags { | 	for _, flag := range netFlags { | ||||||
| @@ -773,12 +773,10 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. | |||||||
| 			Fatalf("Failed to register the Whisper service: %v", err) | 			Fatalf("Failed to register the Whisper service: %v", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { | ||||||
| 	err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { | 		return release.NewReleaseService(ctx, relconf) | ||||||
| 		return versions.NewVersionCheck(ctx) | 	}); err != nil { | ||||||
| 	}) | 		Fatalf("Failed to register the Geth release oracle service: %v", err) | ||||||
| 	if err != nil { |  | ||||||
| 		Fatalf("Failed to register the Version Check service: %v", err) |  | ||||||
| 	} | 	} | ||||||
| 	return stack | 	return stack | ||||||
| } | } | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										30
									
								
								eth/api.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								eth/api.go
									
									
									
									
									
								
							| @@ -52,14 +52,14 @@ import ( | |||||||
| 	"golang.org/x/net/context" | 	"golang.org/x/net/context" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ErrNoCode is returned by call and transact operations for which the requested | // errNoCode is returned by call and transact operations for which the requested | ||||||
| // recipient contract to operate on does not exist in the state db or does not | // recipient contract to operate on does not exist in the state db or does not | ||||||
| // have any code associated with it (i.e. suicided). | // have any code associated with it (i.e. suicided). | ||||||
| // | // | ||||||
| // Please note, this error string is part of the RPC API and is expected by the | // Please note, this error string is part of the RPC API and is expected by the | ||||||
| // native contract bindings to signal this particular error. Do not change this | // native contract bindings to signal this particular error. Do not change this | ||||||
| // as it will break all dependent code! | // as it will break all dependent code! | ||||||
| var ErrNoCode = errors.New("no contract code at given address") | var errNoCode = errors.New("no contract code at given address") | ||||||
|  |  | ||||||
| const defaultGas = uint64(90000) | const defaultGas = uint64(90000) | ||||||
|  |  | ||||||
| @@ -107,8 +107,11 @@ type PublicEthereumAPI struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| // NewPublicEthereumAPI creates a new Ethereum protocol API. | // NewPublicEthereumAPI creates a new Ethereum protocol API. | ||||||
| func NewPublicEthereumAPI(e *Ethereum, gpo *GasPriceOracle) *PublicEthereumAPI { | func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI { | ||||||
| 	return &PublicEthereumAPI{e, gpo} | 	return &PublicEthereumAPI{ | ||||||
|  | 		e:   e, | ||||||
|  | 		gpo: e.gpo, | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // GasPrice returns a suggestion for a gas price. | // GasPrice returns a suggestion for a gas price. | ||||||
| @@ -717,7 +720,7 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st | |||||||
| 	// If there's no code to interact with, respond with an appropriate error | 	// If there's no code to interact with, respond with an appropriate error | ||||||
| 	if args.To != nil { | 	if args.To != nil { | ||||||
| 		if code := stateDb.GetCode(*args.To); len(code) == 0 { | 		if code := stateDb.GetCode(*args.To); len(code) == 0 { | ||||||
| 			return "0x", nil, ErrNoCode | 			return "0x", nil, errNoCode | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	// Retrieve the account state object to interact with | 	// Retrieve the account state object to interact with | ||||||
| @@ -914,18 +917,17 @@ type PublicTransactionPoolAPI struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. | // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. | ||||||
| func NewPublicTransactionPoolAPI(e *Ethereum, gpo *GasPriceOracle) *PublicTransactionPoolAPI { | func NewPublicTransactionPoolAPI(e *Ethereum) *PublicTransactionPoolAPI { | ||||||
| 	api := &PublicTransactionPoolAPI{ | 	api := &PublicTransactionPoolAPI{ | ||||||
| 		eventMux:      e.EventMux(), | 		eventMux:      e.eventMux, | ||||||
| 		gpo:           gpo, | 		gpo:           e.gpo, | ||||||
| 		chainDb:       e.ChainDb(), | 		chainDb:       e.chainDb, | ||||||
| 		bc:            e.BlockChain(), | 		bc:            e.blockchain, | ||||||
| 		am:            e.AccountManager(), | 		am:            e.accountManager, | ||||||
| 		txPool:        e.TxPool(), | 		txPool:        e.txPool, | ||||||
| 		miner:         e.Miner(), | 		miner:         e.miner, | ||||||
| 		pendingTxSubs: make(map[string]rpc.Subscription), | 		pendingTxSubs: make(map[string]rpc.Subscription), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	go api.subscriptionLoop() | 	go api.subscriptionLoop() | ||||||
|  |  | ||||||
| 	return api | 	return api | ||||||
|   | |||||||
| @@ -119,6 +119,7 @@ type Ethereum struct { | |||||||
| 	protocolManager *ProtocolManager | 	protocolManager *ProtocolManager | ||||||
| 	SolcPath        string | 	SolcPath        string | ||||||
| 	solc            *compiler.Solidity | 	solc            *compiler.Solidity | ||||||
|  | 	gpo             *GasPriceOracle | ||||||
|  |  | ||||||
| 	GpoMinGasPrice          *big.Int | 	GpoMinGasPrice          *big.Int | ||||||
| 	GpoMaxGasPrice          *big.Int | 	GpoMaxGasPrice          *big.Int | ||||||
| @@ -260,6 +261,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { | |||||||
| 		} | 		} | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	eth.gpo = NewGasPriceOracle(eth) | ||||||
|  |  | ||||||
| 	newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) | 	newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) | ||||||
| 	eth.txPool = newPool | 	eth.txPool = newPool | ||||||
|  |  | ||||||
| @@ -276,34 +279,31 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { | |||||||
| // APIs returns the collection of RPC services the ethereum package offers. | // APIs returns the collection of RPC services the ethereum package offers. | ||||||
| // NOTE, some of these services probably need to be moved to somewhere else. | // NOTE, some of these services probably need to be moved to somewhere else. | ||||||
| func (s *Ethereum) APIs() []rpc.API { | func (s *Ethereum) APIs() []rpc.API { | ||||||
| 	// share gas price oracle in API's |  | ||||||
| 	gpo := NewGasPriceOracle(s) |  | ||||||
|  |  | ||||||
| 	return []rpc.API{ | 	return []rpc.API{ | ||||||
| 		{ | 		{ | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPublicEthereumAPI(s, gpo), | 			Service:   NewPublicEthereumAPI(s), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPublicAccountAPI(s.AccountManager()), | 			Service:   NewPublicAccountAPI(s.accountManager), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "personal", | 			Namespace: "personal", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPrivateAccountAPI(s.AccountManager()), | 			Service:   NewPrivateAccountAPI(s.accountManager), | ||||||
| 			Public:    false, | 			Public:    false, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPublicBlockChainAPI(s.chainConfig, s.BlockChain(), s.Miner(), s.ChainDb(), gpo, s.EventMux(), s.AccountManager()), | 			Service:   NewPublicBlockChainAPI(s.chainConfig, s.blockchain, s.miner, s.chainDb, s.gpo, s.eventMux, s.accountManager), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPublicTransactionPoolAPI(s, gpo), | 			Service:   NewPublicTransactionPoolAPI(s), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| @@ -313,7 +313,7 @@ func (s *Ethereum) APIs() []rpc.API { | |||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   downloader.NewPublicDownloaderAPI(s.Downloader(), s.EventMux()), | 			Service:   downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "miner", | 			Namespace: "miner", | ||||||
| @@ -328,7 +328,7 @@ func (s *Ethereum) APIs() []rpc.API { | |||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   filters.NewPublicFilterAPI(s.ChainDb(), s.EventMux()), | 			Service:   filters.NewPublicFilterAPI(s.chainDb, s.eventMux), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "admin", | 			Namespace: "admin", | ||||||
| @@ -351,7 +351,7 @@ func (s *Ethereum) APIs() []rpc.API { | |||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "admin", | 			Namespace: "admin", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   ethreg.NewPrivateRegistarAPI(s.chainConfig, s.BlockChain(), s.ChainDb(), s.TxPool(), s.AccountManager()), | 			Service:   ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager), | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										110
									
								
								eth/bind.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								eth/bind.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | |||||||
|  | // Copyright 2016 The go-ethereum Authors | ||||||
|  | // This file is part of the go-ethereum library. | ||||||
|  | // | ||||||
|  | // The go-ethereum library is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU Lesser General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // (at your option) any later version. | ||||||
|  | // | ||||||
|  | // The go-ethereum library is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU Lesser General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU Lesser General Public License | ||||||
|  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | package eth | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"math/big" | ||||||
|  |  | ||||||
|  | 	"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ContractBackend implements bind.ContractBackend with direct calls to Ethereum | ||||||
|  | // internals to support operating on contracts within subprotocols like eth and | ||||||
|  | // swarm. | ||||||
|  | // | ||||||
|  | // Internally this backend uses the already exposed API endpoints of the Ethereum | ||||||
|  | // object. These should be rewritten to internal Go method calls when the Go API | ||||||
|  | // is refactored to support a clean library use. | ||||||
|  | type ContractBackend struct { | ||||||
|  | 	eapi  *PublicEthereumAPI        // Wrapper around the Ethereum object to access metadata | ||||||
|  | 	bcapi *PublicBlockChainAPI      // Wrapper around the blockchain to access chain data | ||||||
|  | 	txapi *PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewContractBackend creates a new native contract backend using an existing | ||||||
|  | // Etheruem object. | ||||||
|  | func NewContractBackend(eth *Ethereum) *ContractBackend { | ||||||
|  | 	return &ContractBackend{ | ||||||
|  | 		eapi:  NewPublicEthereumAPI(eth), | ||||||
|  | 		bcapi: NewPublicBlockChainAPI(eth.chainConfig, eth.blockchain, eth.miner, eth.chainDb, eth.gpo, eth.eventMux, eth.accountManager), | ||||||
|  | 		txapi: NewPublicTransactionPoolAPI(eth), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContractCall implements bind.ContractCaller executing an Ethereum contract | ||||||
|  | // call with the specified data as the input. The pending flag requests execution | ||||||
|  | // against the pending block, not the stable head of the chain. | ||||||
|  | func (b *ContractBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) { | ||||||
|  | 	// Convert the input args to the API spec | ||||||
|  | 	args := CallArgs{ | ||||||
|  | 		To:   &contract, | ||||||
|  | 		Data: common.ToHex(data), | ||||||
|  | 	} | ||||||
|  | 	block := rpc.LatestBlockNumber | ||||||
|  | 	if pending { | ||||||
|  | 		block = rpc.PendingBlockNumber | ||||||
|  | 	} | ||||||
|  | 	// Execute the call and convert the output back to Go types | ||||||
|  | 	out, err := b.bcapi.Call(args, block) | ||||||
|  | 	if err == errNoCode { | ||||||
|  | 		err = bind.ErrNoCode | ||||||
|  | 	} | ||||||
|  | 	return common.FromHex(out), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PendingAccountNonce implements bind.ContractTransactor retrieving the current | ||||||
|  | // pending nonce associated with an account. | ||||||
|  | func (b *ContractBackend) PendingAccountNonce(account common.Address) (uint64, error) { | ||||||
|  | 	out, err := b.txapi.GetTransactionCount(account, rpc.PendingBlockNumber) | ||||||
|  | 	return out.Uint64(), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SuggestGasPrice implements bind.ContractTransactor retrieving the currently | ||||||
|  | // suggested gas price to allow a timely execution of a transaction. | ||||||
|  | func (b *ContractBackend) SuggestGasPrice() (*big.Int, error) { | ||||||
|  | 	return b.eapi.GasPrice(), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // EstimateGasLimit implements bind.ContractTransactor triing to estimate the gas | ||||||
|  | // needed to execute a specific transaction based on the current pending state of | ||||||
|  | // the backend blockchain. There is no guarantee that this is the true gas limit | ||||||
|  | // requirement as other transactions may be added or removed by miners, but it | ||||||
|  | // should provide a basis for setting a reasonable default. | ||||||
|  | func (b *ContractBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) { | ||||||
|  | 	out, err := b.bcapi.EstimateGas(CallArgs{ | ||||||
|  | 		From:  sender, | ||||||
|  | 		To:    contract, | ||||||
|  | 		Value: *rpc.NewHexNumber(value), | ||||||
|  | 		Data:  common.ToHex(data), | ||||||
|  | 	}) | ||||||
|  | 	if err == errNoCode { | ||||||
|  | 		err = bind.ErrNoCode | ||||||
|  | 	} | ||||||
|  | 	return out.BigInt(), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SendTransaction implements bind.ContractTransactor injects the transaction | ||||||
|  | // into the pending pool for execution. | ||||||
|  | func (b *ContractBackend) SendTransaction(tx *types.Transaction) error { | ||||||
|  | 	raw, _ := rlp.EncodeToBytes(tx) | ||||||
|  | 	_, err := b.txapi.SendRawTransaction(common.ToHex(raw)) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
| @@ -311,7 +311,7 @@ func (n *Node) startIPC(apis []rpc.API) error { | |||||||
| 				glog.V(logger.Error).Infof("IPC accept failed: %v", err) | 				glog.V(logger.Error).Infof("IPC accept failed: %v", err) | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation | rpc.OptionSubscriptions) | 			go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions) | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| 	// All listeners booted successfully | 	// All listeners booted successfully | ||||||
| @@ -530,7 +530,6 @@ func (n *Node) Server() *p2p.Server { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Service retrieves a currently running service registered of a specific type. | // Service retrieves a currently running service registered of a specific type. | ||||||
| // NOTE: must be called with double pointer to service |  | ||||||
| func (n *Node) Service(service interface{}) error { | func (n *Node) Service(service interface{}) error { | ||||||
| 	n.lock.RLock() | 	n.lock.RLock() | ||||||
| 	defer n.lock.RUnlock() | 	defer n.lock.RUnlock() | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ type ServiceConstructor func(ctx *ServiceContext) (Service, error) | |||||||
| //  - Restart logic is not required as the node will create a fresh instance | //  - Restart logic is not required as the node will create a fresh instance | ||||||
| //    every time a service is started. | //    every time a service is started. | ||||||
| type Service interface { | type Service interface { | ||||||
| 	// Protocol retrieves the P2P protocols the service wishes to start. | 	// Protocols retrieves the P2P protocols the service wishes to start. | ||||||
| 	Protocols() []p2p.Protocol | 	Protocols() []p2p.Protocol | ||||||
|  |  | ||||||
| 	// APIs retrieves the list of RPC descriptors the service provides | 	// APIs retrieves the list of RPC descriptors the service provides | ||||||
|   | |||||||
							
								
								
									
										432
									
								
								release/contract.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								release/contract.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -19,7 +19,7 @@ | |||||||
| // check for new releases automatically without the need to consult a central | // check for new releases automatically without the need to consult a central | ||||||
| // repository. | // repository. | ||||||
| // | // | ||||||
| // The contract takes a vote based approach on both assigning authorized signers | // The contract takes a vote based approach on both assigning authorised signers | ||||||
| // as well as signing off on new Geth releases. | // as well as signing off on new Geth releases. | ||||||
| // | // | ||||||
| // Note, when a signer is demoted, the currently pending release is auto-nuked. | // Note, when a signer is demoted, the currently pending release is auto-nuked. | ||||||
| @@ -45,8 +45,8 @@ contract ReleaseOracle { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Oracle authorization details |   // Oracle authorization details | ||||||
|   mapping(address => bool) authorized; // Set of accounts allowed to vote on updating the contract |   mapping(address => bool) authorised; // Set of accounts allowed to vote on updating the contract | ||||||
|   address[]                signers;    // List of addresses currently accepted as signers |   address[]                voters;     // List of addresses currently accepted as signers | ||||||
| 
 | 
 | ||||||
|   // Various proposals being voted on |   // Various proposals being voted on | ||||||
|   mapping(address => Votes) authProps; // Currently running user authorization proposals |   mapping(address => Votes) authProps; // Currently running user authorization proposals | ||||||
| @@ -57,38 +57,47 @@ contract ReleaseOracle { | |||||||
| 
 | 
 | ||||||
|   // isSigner is a modifier to authorize contract transactions. |   // isSigner is a modifier to authorize contract transactions. | ||||||
|   modifier isSigner() { |   modifier isSigner() { | ||||||
|     if (authorized[msg.sender]) { |     if (authorised[msg.sender]) { | ||||||
|       _ |       _ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Constructor to assign the creator as the sole valid signer. |   // Constructor to assign the initial set of signers. | ||||||
|   function ReleaseOracle() { |   function ReleaseOracle(address[] signers) { | ||||||
|     authorized[msg.sender] = true; |     // If no signers were specified, assign the creator as the sole signer | ||||||
|     signers.push(msg.sender); |     if (signers.length == 0) { | ||||||
|  |       authorised[msg.sender] = true; | ||||||
|  |       voters.push(msg.sender); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     // Otherwise assign the individual signers one by one | ||||||
|  |     for (uint i = 0; i < signers.length; i++) { | ||||||
|  |       authorised[signers[i]] = true; | ||||||
|  |       voters.push(signers[i]); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Signers is an accessor method to retrieve all te signers (public accessor |   // signers is an accessor method to retrieve all te signers (public accessor | ||||||
|   // generates an indexed one, not a retreive-all version). |   // generates an indexed one, not a retreive-all version). | ||||||
|   function Signers() constant returns(address[]) { |   function signers() constant returns(address[]) { | ||||||
|     return signers; |     return voters; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // AuthProposals retrieves the list of addresses that authorization proposals |   // authProposals retrieves the list of addresses that authorization proposals | ||||||
|   // are currently being voted on. |   // are currently being voted on. | ||||||
|   function AuthProposals() constant returns(address[]) { |   function authProposals() constant returns(address[]) { | ||||||
|     return authPend; |     return authPend; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // AuthVotes retrieves the current authorization votes for a particular user |   // authVotes retrieves the current authorization votes for a particular user | ||||||
|   // to promote him into the list of signers, or demote him from there. |   // to promote him into the list of signers, or demote him from there. | ||||||
|   function AuthVotes(address user) constant returns(address[] promote, address[] demote) { |   function authVotes(address user) constant returns(address[] promote, address[] demote) { | ||||||
|     return (authProps[user].pass, authProps[user].fail); |     return (authProps[user].pass, authProps[user].fail); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // CurrentVersion retrieves the semantic version, commit hash and release time |   // currentVersion retrieves the semantic version, commit hash and release time | ||||||
|   // of the currently votec active release. |   // of the currently votec active release. | ||||||
|   function CurrentVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, uint time) { |   function currentVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, uint time) { | ||||||
|     if (releases.length == 0) { |     if (releases.length == 0) { | ||||||
|       return (0, 0, 0, 0, 0); |       return (0, 0, 0, 0, 0); | ||||||
|     } |     } | ||||||
| @@ -97,38 +106,38 @@ contract ReleaseOracle { | |||||||
|     return (release.major, release.minor, release.patch, release.commit, release.time); |     return (release.major, release.minor, release.patch, release.commit, release.time); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // ProposedVersion retrieves the semantic version, commit hash and the current |   // proposedVersion retrieves the semantic version, commit hash and the current | ||||||
|   // votes for the next proposed release. |   // votes for the next proposed release. | ||||||
|   function ProposedVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, address[] pass, address[] fail) { |   function proposedVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, address[] pass, address[] fail) { | ||||||
|     return (verProp.major, verProp.minor, verProp.patch, verProp.commit, verProp.votes.pass, verProp.votes.fail); |     return (verProp.major, verProp.minor, verProp.patch, verProp.commit, verProp.votes.pass, verProp.votes.fail); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Promote pitches in on a voting campaign to promote a new user to a signer |   // promote pitches in on a voting campaign to promote a new user to a signer | ||||||
|   // position. |   // position. | ||||||
|   function Promote(address user) { |   function promote(address user) { | ||||||
|     updateSigner(user, true); |     updateSigner(user, true); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Demote pitches in on a voting campaign to demote an authorized user from |   // demote pitches in on a voting campaign to demote an authorised user from | ||||||
|   // its signer position. |   // its signer position. | ||||||
|   function Demote(address user) { |   function demote(address user) { | ||||||
|     updateSigner(user, false); |     updateSigner(user, false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Release votes for a particular version to be included as the next release. |   // release votes for a particular version to be included as the next release. | ||||||
|   function Release(uint32 major, uint32 minor, uint32 patch, bytes20 commit) { |   function release(uint32 major, uint32 minor, uint32 patch, bytes20 commit) { | ||||||
|     updateRelease(major, minor, patch, commit, true); |     updateRelease(major, minor, patch, commit, true); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Nuke votes for the currently proposed version to not be included as the next |   // nuke votes for the currently proposed version to not be included as the next | ||||||
|   // release. Nuking doesn't require a specific version number for simplicity. |   // release. Nuking doesn't require a specific version number for simplicity. | ||||||
|   function Nuke() { |   function nuke() { | ||||||
|     updateRelease(0, 0, 0, 0, false); |     updateRelease(0, 0, 0, 0, false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // updateSigner marks a vote for changing the status of an Ethereum user, either |   // updateSigner marks a vote for changing the status of an Ethereum user, either | ||||||
|   // for or against the user being an authorized signer. |   // for or against the user being an authorised signer. | ||||||
|   function updateSigner(address user, bool authorize) isSigner { |   function updateSigner(address user, bool authorize) internal isSigner { | ||||||
|     // Gather the current votes and ensure we don't double vote |     // Gather the current votes and ensure we don't double vote | ||||||
|     Votes votes = authProps[user]; |     Votes votes = authProps[user]; | ||||||
|     for (uint i = 0; i < votes.pass.length; i++) { |     for (uint i = 0; i < votes.pass.length; i++) { | ||||||
| @@ -148,26 +157,26 @@ contract ReleaseOracle { | |||||||
|     // Cast the vote and return if the proposal cannot be resolved yet |     // Cast the vote and return if the proposal cannot be resolved yet | ||||||
|     if (authorize) { |     if (authorize) { | ||||||
|       votes.pass.push(msg.sender); |       votes.pass.push(msg.sender); | ||||||
|       if (votes.pass.length <= signers.length / 2) { |       if (votes.pass.length <= voters.length / 2) { | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       votes.fail.push(msg.sender); |       votes.fail.push(msg.sender); | ||||||
|       if (votes.fail.length <= signers.length / 2) { |       if (votes.fail.length <= voters.length / 2) { | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     // Proposal resolved in our favor, execute whatever we voted on |     // Proposal resolved in our favor, execute whatever we voted on | ||||||
|     if (authorize && !authorized[user]) { |     if (authorize && !authorised[user]) { | ||||||
|       authorized[user] = true; |       authorised[user] = true; | ||||||
|       signers.push(user); |       voters.push(user); | ||||||
|     } else if (!authorize && authorized[user]) { |     } else if (!authorize && authorised[user]) { | ||||||
|       authorized[user] = false; |       authorised[user] = false; | ||||||
| 
 | 
 | ||||||
|       for (i = 0; i < signers.length; i++) { |       for (i = 0; i < voters.length; i++) { | ||||||
|         if (signers[i] == user) { |         if (voters[i] == user) { | ||||||
|           signers[i] = signers[signers.length - 1]; |           voters[i] = voters[voters.length - 1]; | ||||||
|           signers.length--; |           voters.length--; | ||||||
| 
 | 
 | ||||||
|           delete verProp; // Nuke any version proposal (no suprise releases!) |           delete verProp; // Nuke any version proposal (no suprise releases!) | ||||||
|           break; |           break; | ||||||
| @@ -188,7 +197,7 @@ contract ReleaseOracle { | |||||||
| 
 | 
 | ||||||
|   // updateRelease votes for a particular version to be included as the next release, |   // updateRelease votes for a particular version to be included as the next release, | ||||||
|   // or for the currently proposed release to be nuked out. |   // or for the currently proposed release to be nuked out. | ||||||
|   function updateRelease(uint32 major, uint32 minor, uint32 patch, bytes20 commit, bool release) isSigner { |   function updateRelease(uint32 major, uint32 minor, uint32 patch, bytes20 commit, bool release) internal isSigner { | ||||||
|     // Skip nuke votes if no proposal is pending |     // Skip nuke votes if no proposal is pending | ||||||
|     if (!release && verProp.votes.pass.length == 0) { |     if (!release && verProp.votes.pass.length == 0) { | ||||||
|       return; |       return; | ||||||
| @@ -219,12 +228,12 @@ contract ReleaseOracle { | |||||||
|     // Cast the vote and return if the proposal cannot be resolved yet |     // Cast the vote and return if the proposal cannot be resolved yet | ||||||
|     if (release) { |     if (release) { | ||||||
|       votes.pass.push(msg.sender); |       votes.pass.push(msg.sender); | ||||||
|       if (votes.pass.length <= signers.length / 2) { |       if (votes.pass.length <= voters.length / 2) { | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       votes.fail.push(msg.sender); |       votes.fail.push(msg.sender); | ||||||
|       if (votes.fail.length <= signers.length / 2) { |       if (votes.fail.length <= voters.length / 2) { | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -42,7 +42,7 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat | |||||||
| 	sim := backends.NewSimulatedBackend(accounts...) | 	sim := backends.NewSimulatedBackend(accounts...) | ||||||
| 
 | 
 | ||||||
| 	// Deploy a version oracle contract, commit and return | 	// Deploy a version oracle contract, commit and return | ||||||
| 	_, _, oracle, err := DeployReleaseOracle(auth, sim) | 	_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("Failed to deploy version contract: %v", err) | 		t.Fatalf("Failed to deploy version contract: %v", err) | ||||||
| 	} | 	} | ||||||
| @@ -239,7 +239,7 @@ func TestVersionRelease(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 		// Propose release with half voters and check that the release does not yet go through | 		// Propose release with half voters and check that the release does not yet go through | ||||||
| 		for j := 0; j < (i+1)/2; j++ { | 		for j := 0; j < (i+1)/2; j++ { | ||||||
| 			if _, err = oracle.Release(bind.NewKeyedTransactor(keys[j]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{}); err != nil { | 			if _, err = oracle.Release(bind.NewKeyedTransactor(keys[j]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}); err != nil { | ||||||
| 				t.Fatalf("Iter #%d: failed valid release attempt: %v", i, err) | 				t.Fatalf("Iter #%d: failed valid release attempt: %v", i, err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -254,8 +254,8 @@ func TestVersionRelease(t *testing.T) { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Pass the release and check that it became the next version | 		// Pass the release and check that it became the next version | ||||||
| 		verMajor, verMinor, verPatch, verCommit = uint32(i), uint32(i+1), uint32(i+2), [20]byte{} | 		verMajor, verMinor, verPatch, verCommit = uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)} | ||||||
| 		if _, err = oracle.Release(bind.NewKeyedTransactor(keys[(i+1)/2]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{}); err != nil { | 		if _, err = oracle.Release(bind.NewKeyedTransactor(keys[(i+1)/2]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}); err != nil { | ||||||
| 			t.Fatalf("Iter #%d: failed valid release completion attempt: %v", i, err) | 			t.Fatalf("Iter #%d: failed valid release completion attempt: %v", i, err) | ||||||
| 		} | 		} | ||||||
| 		sim.Commit() | 		sim.Commit() | ||||||
| @@ -293,7 +293,7 @@ func TestVersionNuking(t *testing.T) { | |||||||
| 	for i := 1; i < (len(keys)+1)/2; i++ { | 	for i := 1; i < (len(keys)+1)/2; i++ { | ||||||
| 		// Propose release with an initial set of signers | 		// Propose release with an initial set of signers | ||||||
| 		for j := 0; j < i; j++ { | 		for j := 0; j < i; j++ { | ||||||
| 			if _, err := oracle.Release(bind.NewKeyedTransactor(keys[j]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{}); err != nil { | 			if _, err := oracle.Release(bind.NewKeyedTransactor(keys[j]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}); err != nil { | ||||||
| 				t.Fatalf("Iter #%d: failed valid proposal attempt: %v", i, err) | 				t.Fatalf("Iter #%d: failed valid proposal attempt: %v", i, err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -344,7 +344,7 @@ func TestVersionAutoNuke(t *testing.T) { | |||||||
| 		sim.Commit() | 		sim.Commit() | ||||||
| 	} | 	} | ||||||
| 	// Make a release proposal and check it's existence | 	// Make a release proposal and check it's existence | ||||||
| 	if _, err := oracle.Release(bind.NewKeyedTransactor(keys[0]), 1, 2, 3, [20]byte{}); err != nil { | 	if _, err := oracle.Release(bind.NewKeyedTransactor(keys[0]), 1, 2, 3, [20]byte{4}); err != nil { | ||||||
| 		t.Fatalf("Failed valid proposal attempt: %v", err) | 		t.Fatalf("Failed valid proposal attempt: %v", err) | ||||||
| 	} | 	} | ||||||
| 	sim.Commit() | 	sim.Commit() | ||||||
							
								
								
									
										147
									
								
								release/release.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								release/release.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  | // Copyright 2016 The go-ethereum Authors | ||||||
|  | // This file is part of the go-ethereum library. | ||||||
|  | // | ||||||
|  | // The go-ethereum library is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU Lesser General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // (at your option) any later version. | ||||||
|  | // | ||||||
|  | // The go-ethereum library is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU Lesser General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU Lesser General Public License | ||||||
|  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | // Package release contains the node service that tracks client releases. | ||||||
|  | package release | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
|  | 	"github.com/ethereum/go-ethereum/eth" | ||||||
|  | 	"github.com/ethereum/go-ethereum/logger" | ||||||
|  | 	"github.com/ethereum/go-ethereum/logger/glog" | ||||||
|  | 	"github.com/ethereum/go-ethereum/node" | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Interval to check for new releases | ||||||
|  | const releaseRecheckInterval = time.Hour | ||||||
|  |  | ||||||
|  | // Config contains the configurations of the release service. | ||||||
|  | type Config struct { | ||||||
|  | 	Oracle common.Address // Ethereum address of the release oracle | ||||||
|  | 	Major  uint32         // Major version component of the release | ||||||
|  | 	Minor  uint32         // Minor version component of the release | ||||||
|  | 	Patch  uint32         // Patch version component of the release | ||||||
|  | 	Commit [20]byte       // Git SHA1 commit hash of the release | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReleaseService is a node service that periodically checks the blockchain for | ||||||
|  | // newly released versions of the client being run and issues a warning to the | ||||||
|  | // user about it. | ||||||
|  | type ReleaseService struct { | ||||||
|  | 	config Config          // Current version to check releases against | ||||||
|  | 	oracle *ReleaseOracle  // Native binding to the release oracle contract | ||||||
|  | 	quit   chan chan error // Quit channel to terminate the version checker | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewReleaseService creates a new service to periodically check for new client | ||||||
|  | // releases and notify the user of such. | ||||||
|  | func NewReleaseService(ctx *node.ServiceContext, config Config) (node.Service, error) { | ||||||
|  | 	// Retrieve the Ethereum service dependency to access the blockchain | ||||||
|  | 	var ethereum *eth.Ethereum | ||||||
|  | 	if err := ctx.Service(ðereum); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	// Construct the release service | ||||||
|  | 	contract, err := NewReleaseOracle(config.Oracle, eth.NewContractBackend(ethereum)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &ReleaseService{ | ||||||
|  | 		config: config, | ||||||
|  | 		oracle: contract, | ||||||
|  | 		quit:   make(chan chan error), | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Protocols returns an empty list of P2P protocols as the release service does | ||||||
|  | // not have a networking component. | ||||||
|  | func (r *ReleaseService) Protocols() []p2p.Protocol { return nil } | ||||||
|  |  | ||||||
|  | // APIs returns an empty list of RPC descriptors as the release service does not | ||||||
|  | // expose any functioanlity to the outside world. | ||||||
|  | func (r *ReleaseService) APIs() []rpc.API { return nil } | ||||||
|  |  | ||||||
|  | // Start spawns the periodic version checker goroutine | ||||||
|  | func (r *ReleaseService) Start(server *p2p.Server) error { | ||||||
|  | 	go r.checker() | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Stop terminates all goroutines belonging to the service, blocking until they | ||||||
|  | // are all terminated. | ||||||
|  | func (r *ReleaseService) Stop() error { | ||||||
|  | 	errc := make(chan error) | ||||||
|  | 	r.quit <- errc | ||||||
|  | 	return <-errc | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // checker runs indefinitely in the background, periodically checking for new | ||||||
|  | // client releases. | ||||||
|  | func (r *ReleaseService) checker() { | ||||||
|  | 	// Set up the timers to periodically check for releases | ||||||
|  | 	timer := time.NewTimer(0) // Immediately fire a version check | ||||||
|  | 	defer timer.Stop() | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		select { | ||||||
|  | 		// If the time arrived, check for a new release | ||||||
|  | 		case <-timer.C: | ||||||
|  | 			// Rechedule the timer before continuing | ||||||
|  | 			timer.Reset(releaseRecheckInterval) | ||||||
|  |  | ||||||
|  | 			// Retrieve the current version, and handle missing contracts gracefully | ||||||
|  | 			version, err := r.oracle.CurrentVersion(nil) | ||||||
|  | 			if err != nil { | ||||||
|  | 				if err == bind.ErrNoCode { | ||||||
|  | 					glog.V(logger.Debug).Infof("Release oracle not found at %x", r.config.Oracle) | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 				glog.V(logger.Error).Infof("Failed to retrieve current release: %v", err) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			// Version was successfully retrieved, notify if newer than ours | ||||||
|  | 			if version.Major > r.config.Major || | ||||||
|  | 				(version.Major == r.config.Major && version.Minor > r.config.Minor) || | ||||||
|  | 				(version.Major == r.config.Major && version.Minor == r.config.Minor && version.Patch > r.config.Patch) { | ||||||
|  |  | ||||||
|  | 				warning := fmt.Sprintf("Client v%d.%d.%d-%x seems older than the latest upstream release v%d.%d.%d-%x", | ||||||
|  | 					r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4]) | ||||||
|  | 				howtofix := fmt.Sprintf("Please check https://github.com/ethereum/go-ethereum/releases for new releases") | ||||||
|  | 				separator := strings.Repeat("-", len(warning)) | ||||||
|  |  | ||||||
|  | 				glog.V(logger.Warn).Info(separator) | ||||||
|  | 				glog.V(logger.Warn).Info(warning) | ||||||
|  | 				glog.V(logger.Warn).Info(howtofix) | ||||||
|  | 				glog.V(logger.Warn).Info(separator) | ||||||
|  | 			} else { | ||||||
|  | 				glog.V(logger.Debug).Infof("Client v%d.%d.%d-%x seems up to date with upstream v%d.%d.%d-%x", | ||||||
|  | 					r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4]) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		// If termination was requested, return | ||||||
|  | 		case errc := <-r.quit: | ||||||
|  | 			errc <- nil | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user