From a96fc7a942fb6f0a9da5b5bf9c84a98af42a24dc Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 26 Sep 2019 16:16:56 -0400 Subject: remove 1s limit from block generation; more API --- consensus/dummy/consensus.go | 13 +++-- coreth.go | 16 +++++- eth/backend.go | 8 +-- examples/chain/main.go | 115 +++++++++++++++++++++++++------------------ miner/miner.go | 5 +- miner/worker.go | 22 +++++++-- params/protocol_params.go | 23 +++++++++ 7 files changed, 138 insertions(+), 64 deletions(-) create mode 100644 params/protocol_params.go diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go index 0fbc674..c9bbb90 100644 --- a/consensus/dummy/consensus.go +++ b/consensus/dummy/consensus.go @@ -8,6 +8,7 @@ import ( "runtime" "time" + myparams "github.com/ava-labs/coreth/params" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/consensus" "github.com/ava-labs/go-ethereum/core/state" @@ -24,6 +25,7 @@ type OnAPIsCallbackType = func(consensus.ChainReader) []rpc.API type ConsensusCallbacks struct { OnSeal func(*types.Block) error + OnSealHash func(*types.Header) OnAPIs OnAPIsCallbackType OnFinalize OnFinalizeCallbackType OnFinalizeAndAssemble OnFinalizeAndAssembleCallbackType @@ -54,8 +56,8 @@ var ( // 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) + if uint64(len(header.Extra)) > myparams.MaximumExtraDataSize { + return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), myparams.MaximumExtraDataSize) } // Verify the header's timestamp if !uncle { @@ -63,7 +65,8 @@ func (self *DummyEngine) verifyHeader(chain consensus.ChainReader, header, paren return consensus.ErrFutureBlock } } - if header.Time <= parent.Time { + //if header.Time <= parent.Time { + if header.Time < parent.Time { return errZeroBlockTime } // Verify that the gas limit is <= 2^63-1 @@ -278,6 +281,10 @@ func (self *DummyEngine) Seal(chain consensus.ChainReader, block *types.Block, r } func (self *DummyEngine) SealHash(header *types.Header) (hash common.Hash) { + if self.cb.OnSealHash != nil { + self.cb.OnSealHash(header) + } + hasher := sha3.NewLegacyKeccak256() rlp.Encode(hasher, []interface{}{ diff --git a/coreth.go b/coreth.go index f3180e6..4bb0ae8 100644 --- a/coreth.go +++ b/coreth.go @@ -96,8 +96,20 @@ func (self *ETHChain) SetOnSeal(cb func(*types.Block) error) { self.cb.OnSeal = cb } -func (self *ETHChain) SetOnSealMiner(cb func(*types.Block) error) { - self.mcb.OnSeal = cb +func (self *ETHChain) SetOnSealHash(cb func(*types.Header)) { + self.cb.OnSealHash = cb +} + +func (self *ETHChain) SetOnSealFinish(cb func(*types.Block) error) { + self.mcb.OnSealFinish = cb +} + +func (self *ETHChain) SetOnHeaderNew(cb func(*types.Header)) { + self.mcb.OnHeaderNew = cb +} + +func (self *ETHChain) SetOnSealDrop(cb func(*types.Block)) { + self.mcb.OnSealDrop = cb } func (self *ETHChain) SetOnAPIs(cb dummy.OnAPIsCallbackType) { diff --git a/eth/backend.go b/eth/backend.go index b297b9b..4281d96 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -30,6 +30,7 @@ import ( "github.com/ava-labs/coreth/internal/ethapi" "github.com/ava-labs/coreth/miner" "github.com/ava-labs/coreth/node" + myparams "github.com/ava-labs/coreth/params" "github.com/ava-labs/go-ethereum/accounts" "github.com/ava-labs/go-ethereum/accounts/abi/bind" "github.com/ava-labs/go-ethereum/common" @@ -240,8 +241,8 @@ func makeExtraData(extra []byte) []byte { runtime.GOOS, }) } - if uint64(len(extra)) > params.MaximumExtraDataSize { - log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) + if uint64(len(extra)) > myparams.MaximumExtraDataSize { + log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", myparams.MaximumExtraDataSize) extra = nil } return extra @@ -441,7 +442,8 @@ func (s *Ethereum) StartMining(threads int) error { // introduced to speed sync times. atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) - go s.miner.Start(eb) + //go s.miner.Start(eb) + s.miner.Start(eb) } return nil } diff --git a/examples/chain/main.go b/examples/chain/main.go index eddebd5..92350d3 100644 --- a/examples/chain/main.go +++ b/examples/chain/main.go @@ -13,8 +13,8 @@ import ( "github.com/ava-labs/go-ethereum/params" "github.com/ava-labs/go-ethereum/rlp" "math/big" - //mrand "math/rand" - "time" + "sync" + //"time" ) func checkError(err error) { @@ -30,6 +30,7 @@ type TestChain struct { chain *coreth.ETHChain parentBlock common.Hash outBlockCh chan<- []byte + blockWait sync.WaitGroup } func (tc *TestChain) insertBlock(block *types.Block) { @@ -50,7 +51,16 @@ func NewTestChain(name string, config *eth.Config, outBlockCh: outBlockCh, } tc.insertBlock(tc.chain.GetGenesisBlock()) - tc.chain.SetOnSealMiner(func(block *types.Block) error { + tc.chain.SetOnHeaderNew(func(header *types.Header) { + hid := make([]byte, 32) + _, err := rand.Read(hid) + if err != nil { + panic("cannot generate hid") + } + header.Extra = append(header.Extra, hid...) + //fmt.Printf("%s\n", hexutil.Encode(header.Extra)) + }) + tc.chain.SetOnSealFinish(func(block *types.Block) error { blkID := tc.blkCount tc.blkCount++ if len(block.Uncles()) != 0 { @@ -71,6 +81,7 @@ func NewTestChain(name string, config *eth.Config, <-inAckCh log.Info(fmt.Sprintf("%s: got ack", name)) } + tc.blockWait.Done() return nil }) go func() { @@ -104,72 +115,37 @@ func (tc *TestChain) GenRandomTree(n int, max int) { for i := 0; i < n; i++ { nblocks := len(tc.blocks) m := max - if m < 0 { + if m < 0 || nblocks < m { m = nblocks } pb, _ := rand.Int(rand.Reader, big.NewInt((int64)(m))) pn := pb.Int64() tc.parentBlock = tc.blocks[nblocks-1-(int)(pn)] tc.chain.SetTail(tc.parentBlock) + tc.blockWait.Add(1) tc.chain.GenBlock() - time.Sleep(time.Second) + tc.blockWait.Wait() } } -func main() { - // configure the chain - config := eth.DefaultConfig - 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, - } - - // configure the genesis block - genBalance := big.NewInt(100000000000000000) - genKey, _ := coreth.NewKey(rand.Reader) - - config.Genesis = &core.Genesis{ - Config: chainConfig, - Nonce: 0, - Number: 0, - ExtraData: hexutil.MustDecode("0x00"), - GasLimit: 100000000, - Difficulty: big.NewInt(0), - Alloc: core.GenesisAlloc{genKey.Address: {Balance: genBalance}}, - } - - // grab the control of block generation and disable auto uncle - config.Miner.ManualMining = true - config.Miner.DisableUncle = true - +func run(config *eth.Config, a1, a2, b1, b2 int) { aliceBlk := make(chan []byte) bobBlk := make(chan []byte) aliceAck := make(chan struct{}) bobAck := make(chan struct{}) - alice := NewTestChain("alice", &config, bobBlk, aliceBlk, bobAck, aliceAck) - bob := NewTestChain("bob", &config, aliceBlk, bobBlk, aliceAck, bobAck) + alice := NewTestChain("alice", config, bobBlk, aliceBlk, bobAck, aliceAck) + bob := NewTestChain("bob", config, aliceBlk, bobBlk, aliceAck, bobAck) alice.Start() bob.Start() - alice.GenRandomTree(60, -1) + alice.GenRandomTree(a1, a2) log.Info("alice finished generating the tree") - time.Sleep(2 * time.Second) + //time.Sleep(1 * time.Second) bob.outBlockCh = nil - bob.GenRandomTree(60, 2) + bob.GenRandomTree(b1, b2) //mrand.Shuffle(len(bob.blocks), // func(i, j int) { bob.blocks[i], bob.blocks[j] = bob.blocks[j], bob.blocks[i] }) log.Info("bob finished generating the tree") - time.Sleep(2 * time.Second) + //time.Sleep(1 * time.Second) log.Info("bob sends out all its blocks") for i := range bob.blocks { serialized, err := rlp.EncodeToBytes(bob.chain.GetBlockByHash(bob.blocks[i])) @@ -181,7 +157,7 @@ func main() { log.Info(fmt.Sprintf("bob: got ack")) } log.Info("bob finished generating the tree") - time.Sleep(2 * time.Second) + //time.Sleep(1 * time.Second) log.Info("comparing two trees") if len(alice.blocks) != len(bob.blocks) { panic(fmt.Sprintf("mismatching tree size %d != %d", len(alice.blocks), len(bob.blocks))) @@ -211,3 +187,44 @@ func main() { alice.Stop() bob.Stop() } + +func main() { + // configure the chain + config := eth.DefaultConfig + 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, + } + + // configure the genesis block + genBalance := big.NewInt(100000000000000000) + genKey, _ := coreth.NewKey(rand.Reader) + + config.Genesis = &core.Genesis{ + Config: chainConfig, + Nonce: 0, + Number: 0, + ExtraData: hexutil.MustDecode("0x00"), + GasLimit: 100000000, + Difficulty: big.NewInt(0), + Alloc: core.GenesisAlloc{genKey.Address: {Balance: genBalance}}, + } + + // grab the control of block generation and disable auto uncle + config.Miner.ManualMining = true + config.Miner.DisableUncle = true + + run(&config, 60, 1, 60, 1) + run(&config, 500, 10, 500, 5) +} diff --git a/miner/miner.go b/miner/miner.go index 60a5d39..583e458 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -22,6 +22,7 @@ import ( "math/big" "time" + myparams "github.com/ava-labs/coreth/params" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/common/hexutil" "github.com/ava-labs/go-ethereum/consensus" @@ -80,8 +81,8 @@ func (self *Miner) HashRate() uint64 { } 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) + if uint64(len(extra)) > myparams.MaximumExtraDataSize { + return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), myparams.MaximumExtraDataSize) } self.w.setExtra(extra) return nil diff --git a/miner/worker.go b/miner/worker.go index 8dd2aff..11f3f71 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -26,7 +26,6 @@ import ( "sync" "sync/atomic" "time" - //"fmt" "github.com/ava-labs/go-ethereum/common" "github.com/ava-labs/go-ethereum/consensus" @@ -124,7 +123,9 @@ type intervalAdjust struct { } type MinerCallbacks struct { - OnSeal func(*types.Block) error + OnSealFinish func(*types.Block) error + OnSealDrop func(*types.Block) + OnHeaderNew func(*types.Header) } // worker is the main object which takes care of submitting new work to consensus engine @@ -558,6 +559,10 @@ func (w *worker) taskLoop() { // Reject duplicate sealing work due to resubmitting. sealHash := w.engine.SealHash(task.block.Header()) if sealHash == prev { + log.Warn("Reject duplicate sealing work due to resubmitting.") + if w.minerCallbacks.OnSealDrop != nil { + w.minerCallbacks.OnSealDrop(task.block) + } continue } // Interrupt previous sealing operation @@ -565,6 +570,9 @@ func (w *worker) taskLoop() { stopCh, prev = make(chan struct{}), sealHash if w.skipSealHook != nil && w.skipSealHook(task) { + if w.minerCallbacks.OnSealDrop != nil { + w.minerCallbacks.OnSealDrop(task.block) + } continue } w.pendingMu.Lock() @@ -636,8 +644,8 @@ func (w *worker) resultLoop() { } log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) - if w.minerCallbacks.OnSeal != nil { - w.minerCallbacks.OnSeal(block) + if w.minerCallbacks.OnSealFinish != nil { + w.minerCallbacks.OnSealFinish(block) } // Broadcast the block and announce chain insertion event @@ -883,7 +891,8 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) parent := w.chain.CurrentBlock() if parent.Time() >= uint64(timestamp) { - timestamp = int64(parent.Time() + 1) + //timestamp = int64(parent.Time() + 1) + timestamp = int64(parent.Time()) } // this will ensure we're not going off too far in the future if now := time.Now().Unix(); timestamp > now+1 { @@ -925,6 +934,9 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) } } } + if w.minerCallbacks.OnHeaderNew != nil { + w.minerCallbacks.OnHeaderNew(header) + } // Could potentially happen if starting to mine in an odd state. err := w.makeCurrent(parent, header) if err != nil { diff --git a/params/protocol_params.go b/params/protocol_params.go new file mode 100644 index 0000000..c738450 --- /dev/null +++ b/params/protocol_params.go @@ -0,0 +1,23 @@ +// Copyright 2015 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 . + +package params + +//import "math/big" + +const ( + MaximumExtraDataSize uint64 = 64 // Maximum size extra data may be after Genesis. +) -- cgit v1.2.3-70-g09d2