From bc9539a1b60dc80946bc867681eb32ecae4f0d66 Mon Sep 17 00:00:00 2001 From: Determinant Date: Mon, 12 Aug 2019 18:10:03 -0400 Subject: make the basic demo work --- consensus/dummy/consensus.go | 234 +++++++++++++++++++++++++++++++++++++++++ coreth.go | 245 +------------------------------------------ eth/backend.go | 50 +-------- examples/payments/main.go | 35 +++++-- miner/miner.go | 51 +++++++-- 5 files changed, 312 insertions(+), 303 deletions(-) create mode 100644 consensus/dummy/consensus.go diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go new file mode 100644 index 0000000..a496262 --- /dev/null +++ b/consensus/dummy/consensus.go @@ -0,0 +1,234 @@ +package dummy + +import ( + "fmt" + "time" + "errors" + "runtime" + "math/big" + "golang.org/x/crypto/sha3" + + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" +) + +type DummyEngine struct { +} + +var ( + allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks +) + +var ( + errZeroBlockTime = errors.New("timestamp equals parent's") +) + +// modified from consensus.go +func (self *DummyEngine) verifyHeader(chain consensus.ChainReader, header, parent *types.Header, uncle bool, seal bool) error { + // Ensure that the header's extra-data section is of a reasonable size + if uint64(len(header.Extra)) > params.MaximumExtraDataSize { + return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize) + } + // Verify the header's timestamp + if !uncle { + if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) { + return consensus.ErrFutureBlock + } + } + if header.Time <= parent.Time { + return errZeroBlockTime + } + // Verify that the gas limit is <= 2^63-1 + cap := uint64(0x7fffffffffffffff) + if header.GasLimit > cap { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) + } + // Verify that the gasUsed is <= gasLimit + if header.GasUsed > header.GasLimit { + return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) + } + + // Verify that the gas limit remains within allowed bounds + diff := int64(parent.GasLimit) - int64(header.GasLimit) + if diff < 0 { + diff *= -1 + } + limit := parent.GasLimit / params.GasLimitBoundDivisor + + if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { + return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) + } + // Verify that the block number is parent's +1 + if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { + return consensus.ErrInvalidNumber + } + // Verify the engine specific seal securing the block + if seal { + if err := self.VerifySeal(chain, header); err != nil { + return err + } + } + return nil +} + +func (self *DummyEngine) verifyHeaderWorker(chain consensus.ChainReader, headers []*types.Header, seals []bool, index int) error { + var parent *types.Header + if index == 0 { + parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) + } else if headers[index-1].Hash() == headers[index].ParentHash { + parent = headers[index-1] + } + if parent == nil { + return consensus.ErrUnknownAncestor + } + if chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()) != nil { + return nil // known block + } + return self.verifyHeader(chain, headers[index], parent, false, seals[index]) +} + +func (self *DummyEngine) Author(header *types.Header) (common.Address, error) { + addr := common.Address{} + return addr, nil +} + +func (self *DummyEngine) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { + // Short circuit if the header is known, or it's parent not + number := header.Number.Uint64() + if chain.GetHeader(header.Hash(), number) != nil { + return nil + } + parent := chain.GetHeader(header.ParentHash, number-1) + if parent == nil { + return consensus.ErrUnknownAncestor + } + // Sanity checks passed, do a proper verification + return self.verifyHeader(chain, header, parent, false, seal) +} + +func (self *DummyEngine) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { + // Spawn as many workers as allowed threads + workers := runtime.GOMAXPROCS(0) + if len(headers) < workers { + workers = len(headers) + } + + // Create a task channel and spawn the verifiers + var ( + inputs = make(chan int) + done = make(chan int, workers) + errors = make([]error, len(headers)) + abort = make(chan struct{}) + ) + for i := 0; i < workers; i++ { + go func() { + for index := range inputs { + errors[index] = self.verifyHeaderWorker(chain, headers, seals, index) + done <- index + } + }() + } + + errorsOut := make(chan error, len(headers)) + go func() { + defer close(inputs) + var ( + in, out = 0, 0 + checked = make([]bool, len(headers)) + inputs = inputs + ) + for { + select { + case inputs <- in: + if in++; in == len(headers) { + // Reached end of headers. Stop sending to workers. + inputs = nil + } + case index := <-done: + for checked[index] = true; checked[out]; out++ { + errorsOut <- errors[out] + if out == len(headers)-1 { + return + } + } + case <-abort: + return + } + } + }() + return abort, errorsOut +} + +func (self *DummyEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { + return nil +} + +func (self *DummyEngine) VerifySeal(chain consensus.ChainReader, header *types.Header) error { + return nil +} + +func (self *DummyEngine) Prepare(chain consensus.ChainReader, header *types.Header) error { + header.Difficulty = big.NewInt(0) + return nil +} + +func (self *DummyEngine) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, +uncles []*types.Header) { + // commit the final state root + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) +} + +func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, +uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { + // commit the final state root + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + + // Header seems complete, assemble into a block and return + return types.NewBlock(header, txs, uncles, receipts), nil +} + +func (self *DummyEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { + time.Sleep(1000 * time.Millisecond) + fmt.Printf("sealed %s\n", block.ParentHash().String()) + results <- block + return nil +} + +func (self *DummyEngine) SealHash(header *types.Header) (hash common.Hash) { + hasher := sha3.NewLegacyKeccak256() + + rlp.Encode(hasher, []interface{}{ + header.ParentHash, + header.UncleHash, + header.Coinbase, + header.Root, + header.TxHash, + header.ReceiptHash, + header.Bloom, + header.Difficulty, + header.Number, + header.GasLimit, + header.GasUsed, + header.Time, + header.Extra, + }) + hasher.Sum(hash[:0]) + return hash +} + +func (self *DummyEngine) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { + return big.NewInt(0) +} + +func (self *DummyEngine) APIs(chain consensus.ChainReader) []rpc.API { + return nil +} + +func (self *DummyEngine) Close() error { + return nil +} diff --git a/coreth.go b/coreth.go index ec60ce6..74aabcb 100644 --- a/coreth.go +++ b/coreth.go @@ -1,26 +1,14 @@ package coreth import ( - "math/big" - "fmt" - "time" - "errors" - "runtime" "io" "crypto/ecdsa" - "golang.org/x/crypto/sha3" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" //"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core/state" - "github.com/Determinant/coreth/miner" "github.com/Determinant/coreth/eth" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" "github.com/Determinant/coreth/node" "github.com/ethereum/go-ethereum/crypto" ) @@ -30,262 +18,39 @@ type Block = types.Block type Hash = common.Hash type ETHChain struct { - mux *event.TypeMux backend *eth.Ethereum - worker *miner.Worker } -type DummyEngine struct { -} - -var ( - allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks -) - -var ( - errZeroBlockTime = errors.New("timestamp equals parent's") -) - -// modified from consensus.go -func (self *DummyEngine) verifyHeader(chain consensus.ChainReader, header, parent *types.Header, uncle bool, seal bool) error { - // Ensure that the header's extra-data section is of a reasonable size - if uint64(len(header.Extra)) > params.MaximumExtraDataSize { - return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize) - } - // Verify the header's timestamp - if !uncle { - if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) { - return consensus.ErrFutureBlock - } - } - if header.Time <= parent.Time { - return errZeroBlockTime - } - // Verify that the gas limit is <= 2^63-1 - cap := uint64(0x7fffffffffffffff) - if header.GasLimit > cap { - return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) - } - // Verify that the gasUsed is <= gasLimit - if header.GasUsed > header.GasLimit { - return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) - } - // Verify that the gas limit remains within allowed bounds - diff := int64(parent.GasLimit) - int64(header.GasLimit) - if diff < 0 { - diff *= -1 - } - limit := parent.GasLimit / params.GasLimitBoundDivisor - - if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { - return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) - } - // Verify that the block number is parent's +1 - if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { - return consensus.ErrInvalidNumber - } - // Verify the engine specific seal securing the block - if seal { - if err := self.VerifySeal(chain, header); err != nil { - return err - } - } - return nil -} - -func (self *DummyEngine) verifyHeaderWorker(chain consensus.ChainReader, headers []*types.Header, seals []bool, index int) error { - var parent *types.Header - if index == 0 { - parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) - } else if headers[index-1].Hash() == headers[index].ParentHash { - parent = headers[index-1] - } - if parent == nil { - return consensus.ErrUnknownAncestor - } - if chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()) != nil { - return nil // known block - } - return self.verifyHeader(chain, headers[index], parent, false, seals[index]) -} - -func (self *DummyEngine) Author(header *types.Header) (common.Address, error) { - addr := common.Address{} - return addr, nil -} - -func (self *DummyEngine) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { - // Short circuit if the header is known, or it's parent not - number := header.Number.Uint64() - if chain.GetHeader(header.Hash(), number) != nil { - return nil - } - parent := chain.GetHeader(header.ParentHash, number-1) - if parent == nil { - return consensus.ErrUnknownAncestor - } - // Sanity checks passed, do a proper verification - return self.verifyHeader(chain, header, parent, false, seal) -} - -func (self *DummyEngine) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { - // Spawn as many workers as allowed threads - workers := runtime.GOMAXPROCS(0) - if len(headers) < workers { - workers = len(headers) - } - - // Create a task channel and spawn the verifiers - var ( - inputs = make(chan int) - done = make(chan int, workers) - errors = make([]error, len(headers)) - abort = make(chan struct{}) - ) - for i := 0; i < workers; i++ { - go func() { - for index := range inputs { - errors[index] = self.verifyHeaderWorker(chain, headers, seals, index) - done <- index - } - }() - } - - errorsOut := make(chan error, len(headers)) - go func() { - defer close(inputs) - var ( - in, out = 0, 0 - checked = make([]bool, len(headers)) - inputs = inputs - ) - for { - select { - case inputs <- in: - if in++; in == len(headers) { - // Reached end of headers. Stop sending to workers. - inputs = nil - } - case index := <-done: - for checked[index] = true; checked[out]; out++ { - errorsOut <- errors[out] - if out == len(headers)-1 { - return - } - } - case <-abort: - return - } - } - }() - return abort, errorsOut -} - -func (self *DummyEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { - return nil -} - -func (self *DummyEngine) VerifySeal(chain consensus.ChainReader, header *types.Header) error { - return nil -} - -func (self *DummyEngine) Prepare(chain consensus.ChainReader, header *types.Header) error { - header.Difficulty = big.NewInt(0) - return nil -} - -func (self *DummyEngine) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, -uncles []*types.Header) { - // commit the final state root - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) -} - -func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, -uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { - // commit the final state root - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - - // Header seems complete, assemble into a block and return - return types.NewBlock(header, txs, uncles, receipts), nil -} - -func (self *DummyEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { - time.Sleep(1000 * time.Millisecond) - fmt.Printf("sealed %s\n", block.ParentHash().String()) - results <- block - return nil -} - -func (self *DummyEngine) SealHash(header *types.Header) (hash common.Hash) { - hasher := sha3.NewLegacyKeccak256() - - rlp.Encode(hasher, []interface{}{ - header.ParentHash, - header.UncleHash, - header.Coinbase, - header.Root, - header.TxHash, - header.ReceiptHash, - header.Bloom, - header.Difficulty, - header.Number, - header.GasLimit, - header.GasUsed, - header.Time, - header.Extra, - }) - hasher.Sum(hash[:0]) - return hash -} - -func (self *DummyEngine) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { - return big.NewInt(0) -} - -func (self *DummyEngine) APIs(chain consensus.ChainReader) []rpc.API { - return nil -} - -func (self *DummyEngine) Close() error { - return nil -} func isLocalBlock(block *types.Block) bool { return false } -func NewETHChain(config *eth.Config, chainConfig *params.ChainConfig, etherBase *common.Address) *ETHChain { +func NewETHChain(config *eth.Config, etherBase *common.Address) *ETHChain { if config == nil { config = ð.DefaultConfig } - if chainConfig == nil { - chainConfig = params.MainnetChainConfig - } mux := new(event.TypeMux) ctx := node.NewServiceContext(mux) backend, _ := eth.New(&ctx, config) - chain := ÐChain { - mux: mux, - backend: backend, - worker: miner.NewWorker(&config.Miner, chainConfig, &DummyEngine{}, backend, mux, isLocalBlock), - } + chain := ÐChain { backend: backend } if etherBase == nil { etherBase = &common.Address{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } } - chain.worker.SetEtherbase(*etherBase) + backend.SetEtherbase(*etherBase) return chain } func (self *ETHChain) Start() { - self.worker.Start() + self.backend.StartMining(0) } func (self *ETHChain) Stop() { - self.worker.Stop() + self.backend.Stop() } func (self *ETHChain) AddRemoteTxs(txs []*types.Transaction) []error { diff --git a/eth/backend.go b/eth/backend.go index 048074d..dd91405 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" mycore "github.com/Determinant/coreth/core" + "github.com/Determinant/coreth/consensus/dummy" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -45,7 +46,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/Determinant/coreth/internal/ethapi" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" + "github.com/Determinant/coreth/miner" "github.com/Determinant/coreth/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enr" @@ -245,33 +246,7 @@ func makeExtraData(extra []byte) []byte { // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, 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 config.PowMode { - case ethash.ModeFake: - log.Warn("Ethash used in fake mode") - return ethash.NewFaker() - case ethash.ModeTest: - log.Warn("Ethash used in test mode") - return ethash.NewTester(nil, noverify) - case ethash.ModeShared: - log.Warn("Ethash used in shared mode") - return ethash.NewShared() - default: - engine := ethash.New(ethash.Config{ - CacheDir: ctx.ResolvePath(config.CacheDir), - CachesInMem: config.CachesInMem, - CachesOnDisk: config.CachesOnDisk, - DatasetDir: config.DatasetDir, - DatasetsInMem: config.DatasetsInMem, - DatasetsOnDisk: config.DatasetsOnDisk, - }, notify, noverify) - engine.SetThreads(-1) // Disable CPU mining - return engine - } + return new(dummy.DummyEngine) } // APIs return the collection of RPC services the ethereum package offers. @@ -434,17 +409,6 @@ func (s *Ethereum) SetEtherbase(etherbase common.Address) { // is already running, this method adjust the number of threads allowed to use // and updates the minimum price required by the transaction pool. func (s *Ethereum) StartMining(threads int) error { - // Update the thread count within the consensus engine - type threaded interface { - SetThreads(threads int) - } - if th, ok := s.engine.(threaded); ok { - log.Info("Updated mining threads", "threads", threads) - if threads == 0 { - threads = -1 // Disable the miner from within - } - th.SetThreads(threads) - } // If the miner was not running, initialize it if !s.IsMining() { // Propagate the initial price point to the transaction pool @@ -459,14 +423,6 @@ func (s *Ethereum) StartMining(threads int) error { 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("signer missing: %v", err) - } - clique.Authorize(eb, wallet.SignData) - } // If mining is started, we can disable the transaction rejection mechanism // introduced to speed sync times. atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) diff --git a/examples/payments/main.go b/examples/payments/main.go index d5d10b4..76306b0 100644 --- a/examples/payments/main.go +++ b/examples/payments/main.go @@ -1,7 +1,7 @@ package main import ( - //"time" + "time" "os" "os/signal" "syscall" @@ -16,6 +16,7 @@ import ( "github.com/Determinant/coreth" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/common" ) func checkError(err error) { @@ -25,14 +26,29 @@ func checkError(err error) { func main() { log.Root().SetHandler(log.StderrHandler) config := eth.DefaultConfig - chainConfig := params.MainnetChainConfig + chainConfig := ¶ms.ChainConfig { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: nil, + Ethash: nil, + } genBalance := big.NewInt(1000000000000000000) genKey, _ := coreth.NewKey(rand.Reader) config.Genesis = &core.Genesis{ - Config: params.MainnetChainConfig, + Config: chainConfig, Nonce: 0, + Number: 0, ExtraData: hexutil.MustDecode("0x00"), GasLimit: 100000000, Difficulty: big.NewInt(0), @@ -45,12 +61,17 @@ func main() { gasLimit := 21000 gasPrice := big.NewInt(1000) bob, err := coreth.NewKey(rand.Reader); checkError(err) - tx := types.NewTransaction(nonce, bob.Address, value, uint64(gasLimit), gasPrice, nil) - signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey); checkError(err) - chain := coreth.NewETHChain(&config, chainConfig, nil) + chain := coreth.NewETHChain(&config, nil) chain.Start() - chain.AddLocalTxs([]*types.Transaction{signedTx}) + + for i := 0; i < 10; i++ { + tx := types.NewTransaction(nonce, bob.Address, value, uint64(gasLimit), gasPrice, nil) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey); checkError(err) + chain.AddLocalTxs([]*types.Transaction{signedTx}) + time.Sleep(5000 * time.Millisecond) + nonce++ + } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) diff --git a/miner/miner.go b/miner/miner.go index b55d4fc..56440cd 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -18,6 +18,8 @@ package miner import ( + "fmt" + "time" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -25,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" eminer "github.com/ethereum/go-ethereum/miner" ) @@ -37,20 +40,50 @@ type Backend interface { // Config is the configuration parameters of mining. type Config = eminer.Config -type Worker = worker +type Miner struct { + w *worker +} + +func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(block *types.Block) bool) *Miner { + return &Miner { + w: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock), + } +} + +func (self *Miner) SetEtherbase(addr common.Address) { + self.w.setEtherbase(addr) +} + +func (self *Miner) Start(coinbase common.Address) { + self.w.start() +} + +func (self *Miner) Stop() { + self.w.stop() +} -func NewWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(*types.Block) bool) *Worker { - return newWorker(config, chainConfig, engine, eth, mux, isLocalBlock) +func (self *Miner) SetExtra(extra []byte) error { + if uint64(len(extra)) > params.MaximumExtraDataSize { + return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize) + } + self.w.setExtra(extra) + return nil } -func (self *Worker) SetEtherbase(addr common.Address) { - self.setEtherbase(addr) +func (self *Miner) Mining() bool { + return false } -func (self *Worker) Start() { - self.start() +func (self *Miner) HashRate() uint64 { + return 0 +} + +func (self *Miner) SetRecommitInterval(interval time.Duration) {} + +func (self *Miner) PendingBlock() *types.Block { + return self.w.pendingBlock() } -func (self *Worker) Stop() { - self.stop() +func (self *Miner) Pending() (*types.Block, *state.StateDB) { + return self.w.pending() } -- cgit v1.2.3