diff options
Diffstat (limited to 'eth')
-rw-r--r-- | eth/api.go | 31 | ||||
-rw-r--r-- | eth/backend.go | 28 | ||||
-rw-r--r-- | eth/handler.go | 8 | ||||
-rw-r--r-- | eth/protocol_test.go | 2 | ||||
-rw-r--r-- | eth/sync.go | 12 |
5 files changed, 60 insertions, 21 deletions
diff --git a/eth/api.go b/eth/api.go index 041ccd397..0decd57ca 100644 --- a/eth/api.go +++ b/eth/api.go @@ -103,7 +103,7 @@ func (api *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest c // result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty func (api *PublicMinerAPI) GetWork() ([3]string, error) { if !api.e.IsMining() { - if err := api.e.StartMining(); err != nil { + if err := api.e.StartMining(false); err != nil { return [3]string{}, err } } @@ -139,26 +139,33 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { // threads allowed to use. func (api *PrivateMinerAPI) Start(threads *int) error { // Set the number of threads if the seal engine supports it - if threads != nil { - type threaded interface { - SetThreads(threads int) - } - if th, ok := api.e.engine.(threaded); ok { - log.Info("Updated mining threads", "threads", *threads) - th.SetThreads(*threads) - } else { - log.Warn("Current seal engine isn't threaded") - } + if threads == nil { + threads = new(int) + } else if *threads == 0 { + *threads = -1 // Disable the miner from within + } + type threaded interface { + SetThreads(threads int) + } + if th, ok := api.e.engine.(threaded); ok { + log.Info("Updated mining threads", "threads", *threads) + th.SetThreads(*threads) } // Start the miner and return if !api.e.IsMining() { - return api.e.StartMining() + return api.e.StartMining(true) } return nil } // Stop the miner func (api *PrivateMinerAPI) Stop() bool { + type threaded interface { + SetThreads(threads int) + } + if th, ok := api.e.engine.(threaded); ok { + th.SetThreads(-1) + } api.e.StopMining() return true } diff --git a/eth/backend.go b/eth/backend.go index f241d5f34..4dffa2990 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -22,10 +22,12 @@ import ( "math/big" "regexp" "sync" + "sync/atomic" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -229,6 +231,11 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig *params.ChainConfig, db ethdb.Database) consensus.Engine { + // If proof-of-authority is requested, set it up + if chainConfig.Clique != nil { + return clique.New(chainConfig.Clique, db) + } + // Otherwise assume proof-of-work switch { case config.PowFake: log.Warn("Ethash used in fake mode") @@ -240,8 +247,10 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig log.Warn("Ethash used in shared mode") return ethash.NewShared() default: - return ethash.New(ctx.ResolvePath(config.EthashCacheDir), config.EthashCachesInMem, config.EthashCachesOnDisk, + engine := ethash.New(ctx.ResolvePath(config.EthashCacheDir), config.EthashCachesInMem, config.EthashCachesOnDisk, config.EthashDatasetDir, config.EthashDatasetsInMem, config.EthashDatasetsOnDisk) + engine.SetThreads(-1) // Disable CPU mining + return engine } } @@ -324,12 +333,27 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) { self.miner.SetEtherbase(etherbase) } -func (s *Ethereum) StartMining() error { +func (s *Ethereum) StartMining(local bool) error { eb, err := s.Etherbase() if err != nil { log.Error("Cannot start mining without etherbase", "err", err) return fmt.Errorf("etherbase missing: %v", err) } + if clique, ok := s.engine.(*clique.Clique); ok { + wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", err) + return fmt.Errorf("singer missing: %v", err) + } + clique.Authorize(eb, wallet.SignHash) + } + if local { + // If local (CPU) mining is started, we can disable the transaction rejection + // mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous + // so noone will ever hit this path, whereas marking sync done on CPU mining + // will ensure that private networks work in single miner mode too. + atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) + } go s.miner.Start(eb) return nil } diff --git a/eth/handler.go b/eth/handler.go index ef62a3d65..99c2c4b32 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -62,8 +62,8 @@ func errResp(code errCode, format string, v ...interface{}) error { type ProtocolManager struct { networkId int - fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks) - synced uint32 // Flag whether we're considered synchronised (enables transaction processing) + fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks) + acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing) txpool txPool blockchain *core.BlockChain @@ -171,7 +171,7 @@ func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int return blockchain.CurrentBlock().NumberU64() } inserter := func(blocks types.Blocks) (int, error) { - atomic.StoreUint32(&manager.synced, 1) // Mark initial sync done on any fetcher import + atomic.StoreUint32(&manager.acceptTxs, 1) // Mark initial sync done on any fetcher import return manager.blockchain.InsertChain(blocks) } manager.fetcher = fetcher.New(blockchain.GetBlockByHash, validator, manager.BroadcastBlock, heighter, inserter, manager.removePeer) @@ -643,7 +643,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { case msg.Code == TxMsg: // Transactions arrived, make sure we have a valid and fresh chain to handle them - if atomic.LoadUint32(&pm.synced) == 0 { + if atomic.LoadUint32(&pm.acceptTxs) == 0 { break } // Transactions can be processed, parse all of them and deliver to the pool diff --git a/eth/protocol_test.go b/eth/protocol_test.go index 253dcd8a7..3c9a734df 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -94,7 +94,7 @@ func TestRecvTransactions63(t *testing.T) { testRecvTransactions(t, 63) } func testRecvTransactions(t *testing.T, protocol int) { txAdded := make(chan []*types.Transaction) pm := newTestProtocolManagerMust(t, false, 0, nil, txAdded) - pm.synced = 1 // mark synced to accept transactions + pm.acceptTxs = 1 // mark synced to accept transactions p, _ := newTestPeer("peer", protocol, pm, true) defer pm.Stop() defer p.close() diff --git a/eth/sync.go b/eth/sync.go index f2cae6c19..b0653acf9 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -188,8 +188,16 @@ func (pm *ProtocolManager) synchronise(peer *peer) { if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil { return } - atomic.StoreUint32(&pm.synced, 1) // Mark initial sync done - + atomic.StoreUint32(&pm.acceptTxs, 1) // Mark initial sync done + if head := pm.blockchain.CurrentBlock(); head.NumberU64() > 0 { + // We've completed a sync cycle, notify all peers of new state. This path is + // essential in star-topology networks where a gateway node needs to notify + // all its out-of-date peers of the availability of a new block. This failure + // scenario will most often crop up in private and hackathon networks with + // degenerate connectivity, but it should be healthy for the mainnet too to + // more reliably update peers or the local TD state. + go pm.BroadcastBlock(head, false) + } // If fast sync was enabled, and we synced up, disable it if atomic.LoadUint32(&pm.fastSync) == 1 { // Disable fast sync if we indeed have something in our chain |