From 45a259f1053f41457aa62b59b2a4666e5fae6072 Mon Sep 17 00:00:00 2001 From: Dan Turner Date: Sun, 15 May 2016 16:08:45 +1000 Subject: [PATCH 1/9] Conditional mining using events --- miner/miner.go | 58 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index 7cc25cdf7f..b4a7657d50 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -49,6 +49,8 @@ type Miner struct { canStart int32 // can start indicates whether we can start the mining operation shouldStart int32 // should start indicates whether we should start after sync + + sub event.Subscription } func New(eth core.Backend, config *core.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner { @@ -100,31 +102,55 @@ func (m *Miner) SetGasPrice(price *big.Int) { } func (self *Miner) Start(coinbase common.Address, threads int) { - atomic.StoreInt32(&self.shouldStart, 1) - self.threads = threads - self.worker.coinbase = coinbase - self.coinbase = coinbase + self.sub = self.mux.Subscribe(core.TxPreEvent{}, core.NewBlockEvent{}, core.NewMinedBlockEvent{}) + go self.filterLoop(coinbase, threads) +} - if atomic.LoadInt32(&self.canStart) == 0 { - glog.V(logger.Info).Infoln("Can not start mining operation due to network sync (starts when finished)") - return - } +func (self *Miner) filterLoop(coinbase common.Address, threads int) { + for event := range self.sub.Chan() { + switch event.Data.(type) { + case core.TxPreEvent: + glog.V(logger.Info).Infoln("New pending tranny yo, start mining!") + self.actuallyStart(coinbase, threads) + case core.NewBlockEvent: + glog.V(logger.Info).Infoln("New block event") + self.Stop() + self.Start(coinbase, threads) + case core.NewMinedBlockEvent: + glog.V(logger.Info).Infoln("New MINED block event") + self.Stop() + self.Start(coinbase, threads) + } + } +} - atomic.StoreInt32(&self.mining, 1) +func (self *Miner) actuallyStart(coinbase common.Address, threads int) { + atomic.StoreInt32(&self.shouldStart, 1) + self.threads = threads + self.worker.coinbase = coinbase + self.coinbase = coinbase - for i := 0; i < threads; i++ { - self.worker.register(NewCpuAgent(i, self.pow)) - } + if atomic.LoadInt32(&self.canStart) == 0 { + glog.V(logger.Info).Infoln("Can not start mining operation due to network sync (starts when finished)") + return + } - glog.V(logger.Info).Infof("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents)) + atomic.StoreInt32(&self.mining, 1) - self.worker.start() + for i := 0; i < threads; i++ { + self.worker.register(NewCpuAgent(i, self.pow)) + } - self.worker.commitNewWork() + glog.V(logger.Info).Infof("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents)) + + self.worker.start() + + self.worker.commitNewWork() } func (self *Miner) Stop() { - self.worker.stop() + self.sub.Unsubscribe(); + self.worker.stop() atomic.StoreInt32(&self.mining, 0) atomic.StoreInt32(&self.shouldStart, 0) } From 7d3f06b9820b40eda53cf81434c97b2d9942a3a7 Mon Sep 17 00:00:00 2001 From: Dan Turner Date: Sun, 15 May 2016 17:05:28 +1000 Subject: [PATCH 2/9] Implement fixed difficulty flag --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 9 ++++++++- core/block_validator.go | 5 ++++- core/chain_makers.go | 2 +- core/config.go | 2 ++ eth/backend.go | 4 ++++ miner/miner.go | 4 +++- wercker.yml | 19 +++++++++++++++++++ 8 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 wercker.yml diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 5a2fc62873..f42b030ead 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -233,6 +233,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.GpobaseStepUpFlag, utils.GpobaseCorrectionFactorFlag, utils.ExtraDataFlag, + utils.FixedDifficultyFlag, } app.Flags = append(app.Flags, debug.Flags...) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 43dbc37f74..b00076904d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -392,6 +392,11 @@ var ( Usage: "Suggested gas price base correction factor (%)", Value: 110, } + FixedDifficultyFlag = cli.IntFlag{ + Name: "difficulty", + Usage: "Specify a fixed difficulty.", + Value: -1, + } ) // MustMakeDataDir retrieves the currently requested data directory, terminating @@ -801,7 +806,9 @@ func MustMakeChainConfig(ctx *cli.Context) *core.ChainConfig { db := MakeChainDatabase(ctx) defer db.Close() - return MustMakeChainConfigFromDb(ctx, db) + config := MustMakeChainConfigFromDb(ctx, db) + config.FixedDifficulty = ctx.GlobalInt(FixedDifficultyFlag.Name) + return config } // MustMakeChainConfigFromDb reads the chain configuration from the given database. diff --git a/core/block_validator.go b/core/block_validator.go index 801d2572b6..0e58bf54e0 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -254,7 +254,10 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare // the difficulty that a new block should have when created at time // given the parent block's time and difficulty. func CalcDifficulty(config *ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { - if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) { + if config.FixedDifficulty != -1 { + return big.NewInt(int64(config.FixedDifficulty)) + } + if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) { return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff) } else { return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff) diff --git a/core/chain_makers.go b/core/chain_makers.go index ef0ac66d1b..42328ee745 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -35,7 +35,7 @@ import ( // MakeChainConfig returns a new ChainConfig with the ethereum default chain settings. func MakeChainConfig() *ChainConfig { - return &ChainConfig{HomesteadBlock: big.NewInt(0)} + return &ChainConfig{HomesteadBlock: big.NewInt(0), FixedDifficulty: -1} } // FakePow is a non-validating proof of work implementation. diff --git a/core/config.go b/core/config.go index 81ca76aa31..506ba7ccc1 100644 --- a/core/config.go +++ b/core/config.go @@ -34,6 +34,8 @@ type ChainConfig struct { HomesteadBlock *big.Int // homestead switch block VmConfig vm.Config `json:"-"` + + FixedDifficulty int } // IsHomestead returns whether num is either equal to the homestead block or greater. diff --git a/eth/backend.go b/eth/backend.go index f43dea7775..96d22cd01e 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -100,6 +100,8 @@ type Config struct { TestGenesisBlock *types.Block // Genesis block to seed the chain database with (testing only!) TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!) + + FixedDifficulty int } type Ethereum struct { @@ -142,6 +144,8 @@ type Ethereum struct { etherbase common.Address netVersionId int netRPCService *PublicNetAPI + + fixedDifficulty int } func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { diff --git a/miner/miner.go b/miner/miner.go index b4a7657d50..68b90956ae 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -149,7 +149,9 @@ func (self *Miner) actuallyStart(coinbase common.Address, threads int) { } func (self *Miner) Stop() { - self.sub.Unsubscribe(); + if(self.sub != nil) { + self.sub.Unsubscribe(); + } self.worker.stop() atomic.StoreInt32(&self.mining, 0) atomic.StoreInt32(&self.shouldStart, 0) diff --git a/wercker.yml b/wercker.yml new file mode 100644 index 0000000000..8e265f92e9 --- /dev/null +++ b/wercker.yml @@ -0,0 +1,19 @@ +box: golang +build: + steps: + - setup-go-workspace + - script: + name: go build + code: | + make geth + BIN=/pipeline/source/build/bin/$WERCKER_GIT_BRANCH/`cat VERSION` + mkdir -p $BIN + cp build/bin/geth $BIN/geth +deploy: + steps: + - s3sync: + source_dir: build/bin + delete-removed: false + bucket-url: $AWS_BUCKET_URL + key-id: $AWS_ACCESS_KEY_ID + key-secret: $AWS_SECRET_ACCESS_KEY From 26d69d69c5e44626254b1e920fb57659be1bad5c Mon Sep 17 00:00:00 2001 From: Luke Williams Date: Tue, 3 May 2016 16:16:34 +1000 Subject: [PATCH 3/9] Allow up to 128 bytes in block `extraData` --- params/protocol_params.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/protocol_params.go b/params/protocol_params.go index 2dfc251b63..d6108501e9 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -22,7 +22,7 @@ package params import "math/big" var ( - MaximumExtraDataSize = big.NewInt(32) // Maximum size extra data may be after Genesis. + MaximumExtraDataSize = big.NewInt(128) // Maximum size extra data may be after Genesis. ExpByteGas = big.NewInt(10) // Times ceil(log256(exponent)) for the EXP instruction. SloadGas = big.NewInt(50) // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. CallValueTransferGas = big.NewInt(9000) // Paid for CALL when the value transfer is non-zero. From 1a6fbacb648589875493ef596b16fd60b9bd1828 Mon Sep 17 00:00:00 2001 From: Luke Williams Date: Tue, 3 May 2016 16:30:48 +1000 Subject: [PATCH 4/9] Enforce that `Extra` field on block matches a preset value --- core/block_validator.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/block_validator.go b/core/block_validator.go index 0e58bf54e0..2c8dbc4052 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -17,6 +17,7 @@ package core import ( + "bytes" "fmt" "math/big" "time" @@ -34,6 +35,7 @@ var ( ExpDiffPeriod = big.NewInt(100000) big10 = big.NewInt(10) bigMinus99 = big.NewInt(-99) + needExtraData = []byte("hello!") ) // BlockValidator is responsible for validating block headers, uncles and @@ -197,6 +199,9 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b if v.bc.HasHeader(header.Hash()) { return nil } + if !bytes.Equal(parent.Extra, needExtraData) { + return ValidationError("Invalid extraData field in block header!") + } return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false) } From b2d29f9e9af6b1076059a12b5974042fa6e10409 Mon Sep 17 00:00:00 2001 From: Luke Williams Date: Fri, 3 Jun 2016 15:03:09 +1000 Subject: [PATCH 5/9] Implement block signing --- cmd/geth/main.go | 3 ++- cmd/utils/bootnodes.go | 22 ++++++++--------- cmd/utils/flags.go | 20 +++++++++------ core/block_validator.go | 54 +++++++++++++++++++++++++++++++++++------ core/types.go | 1 + eth/backend.go | 14 +++++++---- miner/worker.go | 27 ++++++++++++++++++++- 7 files changed, 109 insertions(+), 32 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index f42b030ead..65338be8a3 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -233,7 +233,8 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.GpobaseStepUpFlag, utils.GpobaseCorrectionFactorFlag, utils.ExtraDataFlag, - utils.FixedDifficultyFlag, + utils.FixedDifficultyFlag, + utils.MinerPassphraseFlag, } app.Flags = append(app.Flags, debug.Flags...) diff --git a/cmd/utils/bootnodes.go b/cmd/utils/bootnodes.go index fbbaa1f227..8ac635fdfb 100644 --- a/cmd/utils/bootnodes.go +++ b/cmd/utils/bootnodes.go @@ -21,21 +21,21 @@ import "github.com/ethereum/go-ethereum/p2p/discover" // FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on // the Frontier network. var FrontierBootNodes = []*discover.Node{ - // ETH/DEV Go Bootnodes - discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE - discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR - discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG - - // ETH/DEV Cpp Bootnodes - discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"), +// ETH/DEV Go Bootnodes +// discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE +// discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR +// discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG +// +// // ETH/DEV Cpp Bootnodes +// discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"), } // TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the // Morden test network. var TestNetBootNodes = []*discover.Node{ - // ETH/DEV Go Bootnodes - discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"), - discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"), +// ETH/DEV Go Bootnodes +// discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"), +// discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"), - // ETH/DEV Cpp Bootnodes +// ETH/DEV Cpp Bootnodes } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b00076904d..4b14b113ef 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -392,11 +392,16 @@ var ( Usage: "Suggested gas price base correction factor (%)", Value: 110, } - FixedDifficultyFlag = cli.IntFlag{ - Name: "difficulty", - Usage: "Specify a fixed difficulty.", - Value: -1, - } + FixedDifficultyFlag = cli.IntFlag{ + Name: "difficulty", + Usage: "Specify a fixed difficulty.", + Value: -1, + } + MinerPassphraseFlag = cli.StringFlag{ + Name: "minerpass", + Usage: "Passphrase used to unlock key for signing blocks.", + Value: "", + } ) // MustMakeDataDir retrieves the currently requested data directory, terminating @@ -717,6 +722,7 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte, GpobaseCorrectionFactor: ctx.GlobalInt(GpobaseCorrectionFactorFlag.Name), SolcPath: ctx.GlobalString(SolcPathFlag.Name), AutoDAG: ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name), + MinerPassphrase: ctx.GlobalString(MinerPassphraseFlag.Name), } // Configure the Whisper service shhEnable := ctx.GlobalBool(WhisperEnabledFlag.Name) @@ -807,8 +813,8 @@ func MustMakeChainConfig(ctx *cli.Context) *core.ChainConfig { defer db.Close() config := MustMakeChainConfigFromDb(ctx, db) - config.FixedDifficulty = ctx.GlobalInt(FixedDifficultyFlag.Name) - return config + config.FixedDifficulty = ctx.GlobalInt(FixedDifficultyFlag.Name) + return config } // MustMakeChainConfigFromDb reads the chain configuration from the given database. diff --git a/core/block_validator.go b/core/block_validator.go index 2c8dbc4052..d3dd72e746 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/pow" @@ -35,7 +36,6 @@ var ( ExpDiffPeriod = big.NewInt(100000) big10 = big.NewInt(10) bigMinus99 = big.NewInt(-99) - needExtraData = []byte("hello!") ) // BlockValidator is responsible for validating block headers, uncles and @@ -199,12 +199,47 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b if v.bc.HasHeader(header.Hash()) { return nil } - if !bytes.Equal(parent.Extra, needExtraData) { - return ValidationError("Invalid extraData field in block header!") - } return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false) } +func ValidateHeaderSignature(header, parent *types.Header) error { + if header.Coinbase != parent.Coinbase { + return ValidationError("Block signature validation error: coinbase does not match parent.") + } + + validator := parent.Coinbase + hash := HashOfHashes(header) + sig := header.Extra + + if sig == nil || len(sig) == 0 { + return ValidationError("Rejecting unsigned block") + } + + pub, err := crypto.SigToPub(hash.Bytes(), sig) + + if err != nil { + return ValidationError(fmt.Sprintf("Block signature validation error: %s", err)) + } + addr := crypto.PubkeyToAddress(*pub) + + if addr != validator { + return ValidationError("Block signature check failed.") + } + return nil +} + +func HashOfHashes(header *types.Header) common.Hash { + hashes := [][]byte{ + header.ParentHash.Bytes(), + header.UncleHash.Bytes(), + header.Root.Bytes(), + header.TxHash.Bytes(), + header.ReceiptHash.Bytes(), + } + hash := crypto.Keccak256Hash(bytes.Join(hashes, []byte(""))) + return hash +} + // Validates a header. Returns an error if the header is invalid. // // See YP section 4.3.4. "Block Header Validity" @@ -213,6 +248,11 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare return fmt.Errorf("Header extra data too long (%d)", len(header.Extra)) } + sigResult := ValidateHeaderSignature(header, parent) + if sigResult != nil { + return sigResult + } + if uncle { if header.Time.Cmp(common.MaxBig) == 1 { return BlockTSTooBigErr @@ -260,9 +300,9 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare // given the parent block's time and difficulty. func CalcDifficulty(config *ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { if config.FixedDifficulty != -1 { - return big.NewInt(int64(config.FixedDifficulty)) - } - if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) { + return big.NewInt(int64(config.FixedDifficulty)) + } + if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) { return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff) } else { return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff) diff --git a/core/types.go b/core/types.go index 20f33a153f..021f168f3a 100644 --- a/core/types.go +++ b/core/types.go @@ -75,4 +75,5 @@ type Backend interface { ChainDb() ethdb.Database DappDb() ethdb.Database EventMux() *event.TypeMux + MinerPassphrase() string } diff --git a/eth/backend.go b/eth/backend.go index 96d22cd01e..6a8c6fd24b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -101,7 +101,8 @@ type Config struct { TestGenesisBlock *types.Block // Genesis block to seed the chain database with (testing only!) TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!) - FixedDifficulty int + FixedDifficulty int + MinerPassphrase string } type Ethereum struct { @@ -145,7 +146,8 @@ type Ethereum struct { netVersionId int netRPCService *PublicNetAPI - fixedDifficulty int + fixedDifficulty int + minerPassphrase string } func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { @@ -222,6 +224,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { GpobaseStepUp: config.GpobaseStepUp, GpobaseCorrectionFactor: config.GpobaseCorrectionFactor, httpclient: httpclient.New(config.DocRoot), + minerPassphrase: config.MinerPassphrase, } switch { case config.PowTest: @@ -382,9 +385,10 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) { self.miner.SetEtherbase(etherbase) } -func (s *Ethereum) StopMining() { s.miner.Stop() } -func (s *Ethereum) IsMining() bool { return s.miner.Mining() } -func (s *Ethereum) Miner() *miner.Miner { return s.miner } +func (s *Ethereum) StopMining() { s.miner.Stop() } +func (s *Ethereum) IsMining() bool { return s.miner.Mining() } +func (s *Ethereum) Miner() *miner.Miner { return s.miner } +func (s *Ethereum) MinerPassphrase() string { return s.minerPassphrase } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } diff --git a/miner/worker.go b/miner/worker.go index fe759560c2..79449e91e0 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -548,7 +548,16 @@ func (self *worker) commitNewWork() { } // create the new block whose nonce will be mined. - work.Block = types.NewBlock(header, work.txs, uncles, work.receipts) + newBlock := types.NewBlock(header, work.txs, uncles, work.receipts) + sig, signError := self.signBlock(newBlock) + if signError != nil { + glog.V(logger.Info).Infoln(fmt.Sprintf("Error signing block: %s.", signError)) + return + } + newHeader := newBlock.Header() + newHeader.Extra = sig + signedBlock := types.NewBlock(newHeader, work.txs, uncles, work.receipts) + work.Block = signedBlock // We only care about logging if we're actually mining. if atomic.LoadInt32(&self.mining) == 1 { @@ -558,6 +567,22 @@ func (self *worker) commitNewWork() { self.push(work) } +func (self *worker) signBlock(block *types.Block) ([]byte, error) { + addr := block.Coinbase() + header := block.Header() + hash := core.HashOfHashes(header) + acct := accounts.Account{Address: addr} + unlockErr := self.eth.AccountManager().Unlock(acct, self.eth.MinerPassphrase()) + if unlockErr != nil { + return nil, unlockErr + } + sig, err := self.eth.AccountManager().Sign(addr, hash.Bytes()) + if err != nil { + return nil, err + } + return sig, nil +} + func (self *worker) commitUncle(work *Work, uncle *types.Header) error { hash := uncle.Hash() if work.uncles.Has(hash) { From 5b0255f05d9df20d3f68f173758b616c471a2d7a Mon Sep 17 00:00:00 2001 From: Luke Williams Date: Tue, 21 Jun 2016 18:43:38 +1000 Subject: [PATCH 6/9] Poll-based miner --- miner/miner.go | 92 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index 68b90956ae..9ec8e59c34 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -21,6 +21,7 @@ import ( "fmt" "math/big" "sync/atomic" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -50,7 +51,7 @@ type Miner struct { canStart int32 // can start indicates whether we can start the mining operation shouldStart int32 // should start indicates whether we should start after sync - sub event.Subscription + sub event.Subscription } func New(eth core.Backend, config *core.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner { @@ -103,56 +104,75 @@ func (m *Miner) SetGasPrice(price *big.Int) { func (self *Miner) Start(coinbase common.Address, threads int) { self.sub = self.mux.Subscribe(core.TxPreEvent{}, core.NewBlockEvent{}, core.NewMinedBlockEvent{}) - go self.filterLoop(coinbase, threads) + //go self.filterLoop(coinbase, threads) + go self.runLoop(coinbase, threads) + +} + +func (self *Miner) runLoop(coinbase common.Address, threads int) { + for true { + if len(self.worker.txQueue) == 0 { + if self.Mining() { + glog.V(logger.Info).Infoln("Nothing to do. The miner sleeps.") + self.Stop() + } + } else { + if self.Mining() == false { + glog.V(logger.Info).Infoln("A transaction awaits! Waking up miner.") + self.Start(coinbase, threads) + } + time.Sleep(3000 * time.Millisecond) + } + } } func (self *Miner) filterLoop(coinbase common.Address, threads int) { - for event := range self.sub.Chan() { - switch event.Data.(type) { - case core.TxPreEvent: - glog.V(logger.Info).Infoln("New pending tranny yo, start mining!") - self.actuallyStart(coinbase, threads) - case core.NewBlockEvent: - glog.V(logger.Info).Infoln("New block event") - self.Stop() - self.Start(coinbase, threads) - case core.NewMinedBlockEvent: - glog.V(logger.Info).Infoln("New MINED block event") - self.Stop() - self.Start(coinbase, threads) - } - } + for event := range self.sub.Chan() { + switch event.Data.(type) { + case core.TxPreEvent: + glog.V(logger.Info).Infoln("New pending tranny yo, start mining!") + self.actuallyStart(coinbase, threads) + case core.NewBlockEvent: + glog.V(logger.Info).Infoln("New block event") + self.Stop() + self.Start(coinbase, threads) + case core.NewMinedBlockEvent: + glog.V(logger.Info).Infoln("New MINED block event") + self.Stop() + self.Start(coinbase, threads) + } + } } func (self *Miner) actuallyStart(coinbase common.Address, threads int) { - atomic.StoreInt32(&self.shouldStart, 1) - self.threads = threads - self.worker.coinbase = coinbase - self.coinbase = coinbase + atomic.StoreInt32(&self.shouldStart, 1) + self.threads = threads + self.worker.coinbase = coinbase + self.coinbase = coinbase - if atomic.LoadInt32(&self.canStart) == 0 { - glog.V(logger.Info).Infoln("Can not start mining operation due to network sync (starts when finished)") - return - } + if atomic.LoadInt32(&self.canStart) == 0 { + glog.V(logger.Info).Infoln("Can not start mining operation due to network sync (starts when finished)") + return + } - atomic.StoreInt32(&self.mining, 1) + atomic.StoreInt32(&self.mining, 1) - for i := 0; i < threads; i++ { - self.worker.register(NewCpuAgent(i, self.pow)) - } + for i := 0; i < threads; i++ { + self.worker.register(NewCpuAgent(i, self.pow)) + } - glog.V(logger.Info).Infof("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents)) + glog.V(logger.Info).Infof("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents)) - self.worker.start() + self.worker.start() - self.worker.commitNewWork() + self.worker.commitNewWork() } func (self *Miner) Stop() { - if(self.sub != nil) { - self.sub.Unsubscribe(); - } - self.worker.stop() + if self.sub != nil { + self.sub.Unsubscribe() + } + self.worker.stop() atomic.StoreInt32(&self.mining, 0) atomic.StoreInt32(&self.shouldStart, 0) } From c399152a07049c51b4dbb06211eaa84a3c79016d Mon Sep 17 00:00:00 2001 From: Luke Williams Date: Wed, 22 Jun 2016 15:06:00 +1000 Subject: [PATCH 7/9] Poll-based mining --- miner/miner.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index 9ec8e59c34..ca0ce6af5a 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -57,6 +57,7 @@ type Miner struct { func New(eth core.Backend, config *core.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner { miner := &Miner{eth: eth, mux: mux, pow: pow, worker: newWorker(config, common.Address{}, eth), canStart: 1} go miner.update() + go miner.runLoop() return miner } @@ -105,13 +106,13 @@ func (m *Miner) SetGasPrice(price *big.Int) { func (self *Miner) Start(coinbase common.Address, threads int) { self.sub = self.mux.Subscribe(core.TxPreEvent{}, core.NewBlockEvent{}, core.NewMinedBlockEvent{}) //go self.filterLoop(coinbase, threads) - go self.runLoop(coinbase, threads) + self.actuallyStart(coinbase, threads) } -func (self *Miner) runLoop(coinbase common.Address, threads int) { +func (self *Miner) runLoop() { for true { - if len(self.worker.txQueue) == 0 { + if len(self.worker.current.txs) == 0 { if self.Mining() { glog.V(logger.Info).Infoln("Nothing to do. The miner sleeps.") self.Stop() @@ -119,10 +120,10 @@ func (self *Miner) runLoop(coinbase common.Address, threads int) { } else { if self.Mining() == false { glog.V(logger.Info).Infoln("A transaction awaits! Waking up miner.") - self.Start(coinbase, threads) + self.Start(self.coinbase, self.threads) } - time.Sleep(3000 * time.Millisecond) } + time.Sleep(3000 * time.Millisecond) } } From c6782a42844c17a917884a152d99860496a055fd Mon Sep 17 00:00:00 2001 From: Luke Williams Date: Tue, 28 Jun 2016 15:22:15 +1000 Subject: [PATCH 8/9] Fix makefile, clean up miner.go --- Makefile | 2 +- miner/miner.go | 64 ++++++++++++++------------------------------------ 2 files changed, 19 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index c2fb9bb354..cf7fe918c8 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ geth-ios: xgo @ls -ld $(GOBIN)/geth-ios-* evm: - build/env.sh $(GOROOT)/bin/go install -v $(shell build/flags.sh) ./cmd/evm + build/env.sh go install -v $(shell build/flags.sh) ./cmd/evm @echo "Done building." @echo "Run \"$(GOBIN)/evm to start the evm." diff --git a/miner/miner.go b/miner/miner.go index ca0ce6af5a..58f3623e0f 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -51,7 +51,6 @@ type Miner struct { canStart int32 // can start indicates whether we can start the mining operation shouldStart int32 // should start indicates whether we should start after sync - sub event.Subscription } func New(eth core.Backend, config *core.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner { @@ -104,48 +103,6 @@ func (m *Miner) SetGasPrice(price *big.Int) { } func (self *Miner) Start(coinbase common.Address, threads int) { - self.sub = self.mux.Subscribe(core.TxPreEvent{}, core.NewBlockEvent{}, core.NewMinedBlockEvent{}) - //go self.filterLoop(coinbase, threads) - self.actuallyStart(coinbase, threads) - -} - -func (self *Miner) runLoop() { - for true { - if len(self.worker.current.txs) == 0 { - if self.Mining() { - glog.V(logger.Info).Infoln("Nothing to do. The miner sleeps.") - self.Stop() - } - } else { - if self.Mining() == false { - glog.V(logger.Info).Infoln("A transaction awaits! Waking up miner.") - self.Start(self.coinbase, self.threads) - } - } - time.Sleep(3000 * time.Millisecond) - } -} - -func (self *Miner) filterLoop(coinbase common.Address, threads int) { - for event := range self.sub.Chan() { - switch event.Data.(type) { - case core.TxPreEvent: - glog.V(logger.Info).Infoln("New pending tranny yo, start mining!") - self.actuallyStart(coinbase, threads) - case core.NewBlockEvent: - glog.V(logger.Info).Infoln("New block event") - self.Stop() - self.Start(coinbase, threads) - case core.NewMinedBlockEvent: - glog.V(logger.Info).Infoln("New MINED block event") - self.Stop() - self.Start(coinbase, threads) - } - } -} - -func (self *Miner) actuallyStart(coinbase common.Address, threads int) { atomic.StoreInt32(&self.shouldStart, 1) self.threads = threads self.worker.coinbase = coinbase @@ -167,12 +124,27 @@ func (self *Miner) actuallyStart(coinbase common.Address, threads int) { self.worker.start() self.worker.commitNewWork() + +} + +func (self *Miner) runLoop() { + for true { + if len(self.worker.current.txs) == 0 { + if self.Mining() { + glog.V(logger.Info).Infoln("Nothing to do. The miner sleeps.") + self.Stop() + } + } else { + if self.Mining() == false { + glog.V(logger.Info).Infoln("A transaction awaits! Waking up miner.") + self.Start(self.coinbase, self.threads) + } + } + time.Sleep(3000 * time.Millisecond) + } } func (self *Miner) Stop() { - if self.sub != nil { - self.sub.Unsubscribe() - } self.worker.stop() atomic.StoreInt32(&self.mining, 0) atomic.StoreInt32(&self.shouldStart, 0) From 919fd902c547ec6b25a8527f1b3d8db7d40af8df Mon Sep 17 00:00:00 2001 From: Luke Williams Date: Tue, 28 Jun 2016 15:41:22 +1000 Subject: [PATCH 9/9] Add poll interval flag --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 7 +++++++ eth/backend.go | 6 ++++++ miner/miner.go | 2 +- 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 65338be8a3..94f0b5a5f2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -234,6 +234,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.GpobaseCorrectionFactorFlag, utils.ExtraDataFlag, utils.FixedDifficultyFlag, + utils.PollIntervalFlag, utils.MinerPassphraseFlag, } app.Flags = append(app.Flags, debug.Flags...) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4b14b113ef..43e0fc5054 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -397,6 +397,11 @@ var ( Usage: "Specify a fixed difficulty.", Value: -1, } + PollIntervalFlag = cli.IntFlag{ + Name: "interval", + Usage: "Miner polling interval in milliseconds.", + Value: 200, + } MinerPassphraseFlag = cli.StringFlag{ Name: "minerpass", Usage: "Passphrase used to unlock key for signing blocks.", @@ -723,6 +728,8 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte, SolcPath: ctx.GlobalString(SolcPathFlag.Name), AutoDAG: ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name), MinerPassphrase: ctx.GlobalString(MinerPassphraseFlag.Name), + FixedDifficulty: ctx.GlobalInt(FixedDifficultyFlag.Name), + PollInterval: ctx.GlobalInt(PollIntervalFlag.Name), } // Configure the Whisper service shhEnable := ctx.GlobalBool(WhisperEnabledFlag.Name) diff --git a/eth/backend.go b/eth/backend.go index 6a8c6fd24b..c312a1cd79 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -102,6 +102,7 @@ type Config struct { TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!) FixedDifficulty int + PollInterval int MinerPassphrase string } @@ -147,6 +148,7 @@ type Ethereum struct { netRPCService *PublicNetAPI fixedDifficulty int + pollInterval int minerPassphrase string } @@ -224,6 +226,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { GpobaseStepUp: config.GpobaseStepUp, GpobaseCorrectionFactor: config.GpobaseCorrectionFactor, httpclient: httpclient.New(config.DocRoot), + fixedDifficulty: config.FixedDifficulty, + pollInterval: config.PollInterval, minerPassphrase: config.MinerPassphrase, } switch { @@ -389,6 +393,8 @@ func (s *Ethereum) StopMining() { s.miner.Stop() } func (s *Ethereum) IsMining() bool { return s.miner.Mining() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) MinerPassphrase() string { return s.minerPassphrase } +func (s *Ethereum) FixedDifficulty() int { return s.fixedDifficulty } +func (s *Ethereum) PollInterval() int { return s.pollInterval } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } diff --git a/miner/miner.go b/miner/miner.go index 58f3623e0f..de03f6f31c 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -140,7 +140,7 @@ func (self *Miner) runLoop() { self.Start(self.coinbase, self.threads) } } - time.Sleep(3000 * time.Millisecond) + time.Sleep(self.eth.PollInterval() * time.Millisecond) } }