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 | ||||
| // to the transactor to decide. | ||||
| 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) | ||||
|  | ||||
| 	// 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) | ||||
|  | ||||
| 	// 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 | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| @@ -41,31 +42,48 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/metrics" | ||||
| 	"github.com/ethereum/go-ethereum/node" | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| 	"github.com/ethereum/go-ethereum/release" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	ClientIdentifier = "Geth" | ||||
| 	Version          = "1.5.0-unstable" | ||||
| 	VersionMajor     = 1 | ||||
| 	VersionMinor     = 5 | ||||
| 	VersionPatch     = 0 | ||||
| 	clientIdentifier = "Geth"     // Client identifier to advertise over the network | ||||
| 	versionMajor     = 1          // Major version component of the current release | ||||
| 	versionMinor     = 5          // Minor version component of the current release | ||||
| 	versionPatch     = 0          // Patch version component of the current release | ||||
| 	versionMeta      = "unstable" // Version metadata to append to the version string | ||||
|  | ||||
| 	versionOracle = "0x48a117313039b73ab02fb9f73e04a66defe123ec" // Ethereum address of the Geth release oracle | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	gitCommit       string // set via linker flagg | ||||
| 	nodeNameVersion string | ||||
| 	app             *cli.App | ||||
| 	gitCommit string         // Git SHA1 commit hash of the release (set via linker flags) | ||||
| 	verString string         // Combined textual representation of all the version components | ||||
| 	relConfig release.Config // Structured version information and release oracle config | ||||
| 	app       *cli.App | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	if gitCommit == "" { | ||||
| 		nodeNameVersion = Version | ||||
| 	} else { | ||||
| 		nodeNameVersion = Version + "-" + gitCommit[:8] | ||||
| 	// Construct the textual version string from the individual components | ||||
| 	verString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPatch) | ||||
| 	if versionMeta != "" { | ||||
| 		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.HideVersion = true // we have a command to print the version | ||||
| 	app.Commands = []cli.Command{ | ||||
| @@ -257,7 +275,7 @@ func makeDefaultExtra() []byte { | ||||
| 		Name      string | ||||
| 		GoVersion 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) | ||||
| 	if err != nil { | ||||
| 		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 | ||||
| // blocking mode, waiting for it to be shut down. | ||||
| func geth(ctx *cli.Context) { | ||||
| 	node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) | ||||
| 	node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx) | ||||
| 	startNode(ctx, node) | ||||
| 	node.Wait() | ||||
| } | ||||
| @@ -339,7 +357,7 @@ func initGenesis(ctx *cli.Context) { | ||||
| // same time. | ||||
| func console(ctx *cli.Context) { | ||||
| 	// 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) | ||||
|  | ||||
| 	// 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. | ||||
| func execScripts(ctx *cli.Context) { | ||||
| 	// 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) | ||||
| 	defer node.Stop() | ||||
|  | ||||
| @@ -488,11 +506,8 @@ func gpubench(ctx *cli.Context) { | ||||
| } | ||||
|  | ||||
| func version(c *cli.Context) { | ||||
| 	fmt.Println(ClientIdentifier) | ||||
| 	fmt.Println("Version:", Version) | ||||
| 	if gitCommit != "" { | ||||
| 		fmt.Println("Git Commit:", gitCommit) | ||||
| 	} | ||||
| 	fmt.Println(clientIdentifier) | ||||
| 	fmt.Println("Version:", version) | ||||
| 	fmt.Println("Protocol Versions:", eth.ProtocolVersions) | ||||
| 	fmt.Println("Network Id:", c.GlobalInt(utils.NetworkIdFlag.Name)) | ||||
| 	fmt.Println("Go Version:", runtime.Version()) | ||||
|   | ||||
| @@ -34,7 +34,6 @@ import ( | ||||
| 	"github.com/ethereum/ethash" | ||||
| 	"github.com/ethereum/go-ethereum/accounts" | ||||
| 	"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/state" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| @@ -49,6 +48,7 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/p2p/nat" | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| 	"github.com/ethereum/go-ethereum/pow" | ||||
| 	"github.com/ethereum/go-ethereum/release" | ||||
| 	"github.com/ethereum/go-ethereum/rpc" | ||||
| 	"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 | ||||
| // 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 | ||||
| 	networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag} | ||||
| 	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) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { | ||||
| 		return versions.NewVersionCheck(ctx) | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		Fatalf("Failed to register the Version Check service: %v", err) | ||||
| 	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { | ||||
| 		return release.NewReleaseService(ctx, relconf) | ||||
| 	}); err != nil { | ||||
| 		Fatalf("Failed to register the Geth release oracle service: %v", err) | ||||
| 	} | ||||
| 	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" | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
| // 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 | ||||
| // native contract bindings to signal this particular error. Do not change this | ||||
| // 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) | ||||
|  | ||||
| @@ -107,8 +107,11 @@ type PublicEthereumAPI struct { | ||||
| } | ||||
|  | ||||
| // NewPublicEthereumAPI creates a new Ethereum protocol API. | ||||
| func NewPublicEthereumAPI(e *Ethereum, gpo *GasPriceOracle) *PublicEthereumAPI { | ||||
| 	return &PublicEthereumAPI{e, gpo} | ||||
| func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI { | ||||
| 	return &PublicEthereumAPI{ | ||||
| 		e:   e, | ||||
| 		gpo: e.gpo, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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 args.To != nil { | ||||
| 		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 | ||||
| @@ -914,18 +917,17 @@ type PublicTransactionPoolAPI struct { | ||||
| } | ||||
|  | ||||
| // 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{ | ||||
| 		eventMux:      e.EventMux(), | ||||
| 		gpo:           gpo, | ||||
| 		chainDb:       e.ChainDb(), | ||||
| 		bc:            e.BlockChain(), | ||||
| 		am:            e.AccountManager(), | ||||
| 		txPool:        e.TxPool(), | ||||
| 		miner:         e.Miner(), | ||||
| 		eventMux:      e.eventMux, | ||||
| 		gpo:           e.gpo, | ||||
| 		chainDb:       e.chainDb, | ||||
| 		bc:            e.blockchain, | ||||
| 		am:            e.accountManager, | ||||
| 		txPool:        e.txPool, | ||||
| 		miner:         e.miner, | ||||
| 		pendingTxSubs: make(map[string]rpc.Subscription), | ||||
| 	} | ||||
|  | ||||
| 	go api.subscriptionLoop() | ||||
|  | ||||
| 	return api | ||||
|   | ||||
| @@ -119,6 +119,7 @@ type Ethereum struct { | ||||
| 	protocolManager *ProtocolManager | ||||
| 	SolcPath        string | ||||
| 	solc            *compiler.Solidity | ||||
| 	gpo             *GasPriceOracle | ||||
|  | ||||
| 	GpoMinGasPrice          *big.Int | ||||
| 	GpoMaxGasPrice          *big.Int | ||||
| @@ -260,6 +261,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	eth.gpo = NewGasPriceOracle(eth) | ||||
|  | ||||
| 	newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) | ||||
| 	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. | ||||
| // NOTE, some of these services probably need to be moved to somewhere else. | ||||
| func (s *Ethereum) APIs() []rpc.API { | ||||
| 	// share gas price oracle in API's | ||||
| 	gpo := NewGasPriceOracle(s) | ||||
|  | ||||
| 	return []rpc.API{ | ||||
| 		{ | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   NewPublicEthereumAPI(s, gpo), | ||||
| 			Service:   NewPublicEthereumAPI(s), | ||||
| 			Public:    true, | ||||
| 		}, { | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   NewPublicAccountAPI(s.AccountManager()), | ||||
| 			Service:   NewPublicAccountAPI(s.accountManager), | ||||
| 			Public:    true, | ||||
| 		}, { | ||||
| 			Namespace: "personal", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   NewPrivateAccountAPI(s.AccountManager()), | ||||
| 			Service:   NewPrivateAccountAPI(s.accountManager), | ||||
| 			Public:    false, | ||||
| 		}, { | ||||
| 			Namespace: "eth", | ||||
| 			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, | ||||
| 		}, { | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   NewPublicTransactionPoolAPI(s, gpo), | ||||
| 			Service:   NewPublicTransactionPoolAPI(s), | ||||
| 			Public:    true, | ||||
| 		}, { | ||||
| 			Namespace: "eth", | ||||
| @@ -313,7 +313,7 @@ func (s *Ethereum) APIs() []rpc.API { | ||||
| 		}, { | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   downloader.NewPublicDownloaderAPI(s.Downloader(), s.EventMux()), | ||||
| 			Service:   downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), | ||||
| 			Public:    true, | ||||
| 		}, { | ||||
| 			Namespace: "miner", | ||||
| @@ -328,7 +328,7 @@ func (s *Ethereum) APIs() []rpc.API { | ||||
| 		}, { | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   filters.NewPublicFilterAPI(s.ChainDb(), s.EventMux()), | ||||
| 			Service:   filters.NewPublicFilterAPI(s.chainDb, s.eventMux), | ||||
| 			Public:    true, | ||||
| 		}, { | ||||
| 			Namespace: "admin", | ||||
| @@ -351,7 +351,7 @@ func (s *Ethereum) APIs() []rpc.API { | ||||
| 		}, { | ||||
| 			Namespace: "admin", | ||||
| 			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) | ||||
| 				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 | ||||
| @@ -530,7 +530,6 @@ func (n *Node) Server() *p2p.Server { | ||||
| } | ||||
|  | ||||
| // 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 { | ||||
| 	n.lock.RLock() | ||||
| 	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 | ||||
| //    every time a service is started. | ||||
| 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 | ||||
|  | ||||
| 	// 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 | ||||
| // 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. | ||||
| // | ||||
| // Note, when a signer is demoted, the currently pending release is auto-nuked. | ||||
| @@ -45,8 +45,8 @@ contract ReleaseOracle { | ||||
|   } | ||||
| 
 | ||||
|   // Oracle authorization details | ||||
|   mapping(address => bool) authorized; // Set of accounts allowed to vote on updating the contract | ||||
|   address[]                signers;    // List of addresses currently accepted as signers | ||||
|   mapping(address => bool) authorised; // Set of accounts allowed to vote on updating the contract | ||||
|   address[]                voters;     // List of addresses currently accepted as signers | ||||
| 
 | ||||
|   // Various proposals being voted on | ||||
|   mapping(address => Votes) authProps; // Currently running user authorization proposals | ||||
| @@ -57,38 +57,47 @@ contract ReleaseOracle { | ||||
| 
 | ||||
|   // isSigner is a modifier to authorize contract transactions. | ||||
|   modifier isSigner() { | ||||
|     if (authorized[msg.sender]) { | ||||
|     if (authorised[msg.sender]) { | ||||
|       _ | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Constructor to assign the creator as the sole valid signer. | ||||
|   function ReleaseOracle() { | ||||
|     authorized[msg.sender] = true; | ||||
|     signers.push(msg.sender); | ||||
|   // Constructor to assign the initial set of signers. | ||||
|   function ReleaseOracle(address[] signers) { | ||||
|     // If no signers were specified, assign the creator as the sole signer | ||||
|     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). | ||||
|   function Signers() constant returns(address[]) { | ||||
|     return signers; | ||||
|   function signers() constant returns(address[]) { | ||||
|     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. | ||||
|   function AuthProposals() constant returns(address[]) { | ||||
|   function authProposals() constant returns(address[]) { | ||||
|     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. | ||||
|   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); | ||||
|   } | ||||
| 
 | ||||
|   // 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. | ||||
|   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) { | ||||
|       return (0, 0, 0, 0, 0); | ||||
|     } | ||||
| @@ -97,38 +106,38 @@ contract ReleaseOracle { | ||||
|     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. | ||||
|   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); | ||||
|   } | ||||
| 
 | ||||
|   // 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. | ||||
|   function Promote(address user) { | ||||
|   function promote(address user) { | ||||
|     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. | ||||
|   function Demote(address user) { | ||||
|   function demote(address user) { | ||||
|     updateSigner(user, false); | ||||
|   } | ||||
| 
 | ||||
|   // Release votes for a particular version to be included as the next release. | ||||
|   function Release(uint32 major, uint32 minor, uint32 patch, bytes20 commit) { | ||||
|   // release votes for a particular version to be included as the next release. | ||||
|   function release(uint32 major, uint32 minor, uint32 patch, bytes20 commit) { | ||||
|     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. | ||||
|   function Nuke() { | ||||
|   function nuke() { | ||||
|     updateRelease(0, 0, 0, 0, false); | ||||
|   } | ||||
| 
 | ||||
|   // updateSigner marks a vote for changing the status of an Ethereum user, either | ||||
|   // for or against the user being an authorized signer. | ||||
|   function updateSigner(address user, bool authorize) isSigner { | ||||
|   // for or against the user being an authorised signer. | ||||
|   function updateSigner(address user, bool authorize) internal isSigner { | ||||
|     // Gather the current votes and ensure we don't double vote | ||||
|     Votes votes = authProps[user]; | ||||
|     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 | ||||
|     if (authorize) { | ||||
|       votes.pass.push(msg.sender); | ||||
|       if (votes.pass.length <= signers.length / 2) { | ||||
|       if (votes.pass.length <= voters.length / 2) { | ||||
|         return; | ||||
|       } | ||||
|     } else { | ||||
|       votes.fail.push(msg.sender); | ||||
|       if (votes.fail.length <= signers.length / 2) { | ||||
|       if (votes.fail.length <= voters.length / 2) { | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|     // Proposal resolved in our favor, execute whatever we voted on | ||||
|     if (authorize && !authorized[user]) { | ||||
|       authorized[user] = true; | ||||
|       signers.push(user); | ||||
|     } else if (!authorize && authorized[user]) { | ||||
|       authorized[user] = false; | ||||
|     if (authorize && !authorised[user]) { | ||||
|       authorised[user] = true; | ||||
|       voters.push(user); | ||||
|     } else if (!authorize && authorised[user]) { | ||||
|       authorised[user] = false; | ||||
| 
 | ||||
|       for (i = 0; i < signers.length; i++) { | ||||
|         if (signers[i] == user) { | ||||
|           signers[i] = signers[signers.length - 1]; | ||||
|           signers.length--; | ||||
|       for (i = 0; i < voters.length; i++) { | ||||
|         if (voters[i] == user) { | ||||
|           voters[i] = voters[voters.length - 1]; | ||||
|           voters.length--; | ||||
| 
 | ||||
|           delete verProp; // Nuke any version proposal (no suprise releases!) | ||||
|           break; | ||||
| @@ -188,7 +197,7 @@ contract ReleaseOracle { | ||||
| 
 | ||||
|   // updateRelease votes for a particular version to be included as the next release, | ||||
|   // 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 | ||||
|     if (!release && verProp.votes.pass.length == 0) { | ||||
|       return; | ||||
| @@ -219,12 +228,12 @@ contract ReleaseOracle { | ||||
|     // Cast the vote and return if the proposal cannot be resolved yet | ||||
|     if (release) { | ||||
|       votes.pass.push(msg.sender); | ||||
|       if (votes.pass.length <= signers.length / 2) { | ||||
|       if (votes.pass.length <= voters.length / 2) { | ||||
|         return; | ||||
|       } | ||||
|     } else { | ||||
|       votes.fail.push(msg.sender); | ||||
|       if (votes.fail.length <= signers.length / 2) { | ||||
|       if (votes.fail.length <= voters.length / 2) { | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
| @@ -42,7 +42,7 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat | ||||
| 	sim := backends.NewSimulatedBackend(accounts...) | ||||
| 
 | ||||
| 	// 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 { | ||||
| 		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 | ||||
| 		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) | ||||
| 			} | ||||
| 		} | ||||
| @@ -254,8 +254,8 @@ func TestVersionRelease(t *testing.T) { | ||||
| 		} | ||||
| 
 | ||||
| 		// 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{} | ||||
| 		if _, err = oracle.Release(bind.NewKeyedTransactor(keys[(i+1)/2]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{}); err != nil { | ||||
| 		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{byte(i + 3)}); err != nil { | ||||
| 			t.Fatalf("Iter #%d: failed valid release completion attempt: %v", i, err) | ||||
| 		} | ||||
| 		sim.Commit() | ||||
| @@ -293,7 +293,7 @@ func TestVersionNuking(t *testing.T) { | ||||
| 	for i := 1; i < (len(keys)+1)/2; i++ { | ||||
| 		// Propose release with an initial set of signers | ||||
| 		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) | ||||
| 			} | ||||
| 		} | ||||
| @@ -344,7 +344,7 @@ func TestVersionAutoNuke(t *testing.T) { | ||||
| 		sim.Commit() | ||||
| 	} | ||||
| 	// 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) | ||||
| 	} | ||||
| 	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