From 821e01b0139eee9bfab9647e4ac1f2d6f1fb01bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 19 Jun 2015 18:13:49 +0300 Subject: cmd/geth, eth/fetcher: initial metrics support Conflicts: cmd/geth/admin.go --- eth/fetcher/fetcher.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'eth') diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 90a202235..a9f4227c4 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -7,6 +7,8 @@ import ( "math/rand" "time" + "github.com/rcrowley/go-metrics" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/logger" @@ -96,6 +98,11 @@ type Fetcher struct { // Testing hooks fetchingHook func([]common.Hash) // Method to call upon starting a block fetch importedHook func(*types.Block) // Method to call upon successful block import + + // Runtime metrics + announceStats metrics.Meter + broadcastStats metrics.Meter + discardStats metrics.Meter } // New creates a block fetcher to retrieve blocks based on hash announcements. @@ -118,6 +125,9 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo chainHeight: chainHeight, insertChain: insertChain, dropPeer: dropPeer, + announceStats: metrics.GetOrRegisterMeter("eth/Announced Blocks", metrics.DefaultRegistry), + broadcastStats: metrics.GetOrRegisterMeter("eth/Propagated Blocks", metrics.DefaultRegistry), + discardStats: metrics.GetOrRegisterMeter("eth/Discarded Blocks", metrics.DefaultRegistry), } } @@ -229,6 +239,8 @@ func (f *Fetcher) loop() { case notification := <-f.notify: // A block was announced, make sure the peer isn't DOSing us + f.announceStats.Mark(1) + count := f.announces[notification.origin] + 1 if count > hashLimit { glog.V(logger.Debug).Infof("Peer %s: exceeded outstanding announces (%d)", notification.origin, hashLimit) @@ -246,6 +258,7 @@ func (f *Fetcher) loop() { case op := <-f.inject: // A direct block insertion was requested, try and fill any pending gaps + f.broadcastStats.Mark(1) f.enqueue(op.origin, op.block) case hash := <-f.done: @@ -364,6 +377,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) { // Discard any past or too distant blocks if dist := int64(block.NumberU64()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x], distance %d", peer, block.NumberU64(), hash.Bytes()[:4], dist) + f.discardStats.Mark(1) return } // Schedule the block for future importing -- cgit v1.2.3 From b426301467304a6c047df9baa033a042ddf3c4bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sun, 21 Jun 2015 20:23:51 +0300 Subject: cmd/geth, eth/fetcher: polish metrics reporting, add some more --- eth/fetcher/fetcher.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'eth') diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index a9f4227c4..a8f0dddbd 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -7,12 +7,11 @@ import ( "math/rand" "time" - "github.com/rcrowley/go-metrics" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" + "github.com/rcrowley/go-metrics" "gopkg.in/karalabe/cookiejar.v2/collections/prque" ) @@ -100,9 +99,11 @@ type Fetcher struct { importedHook func(*types.Block) // Method to call upon successful block import // Runtime metrics - announceStats metrics.Meter - broadcastStats metrics.Meter - discardStats metrics.Meter + announceMeter metrics.Meter // Counter for metering the inbound announcements + announceTimer metrics.Timer // Counter and timer for metering the announce forwarding + broadcastMeter metrics.Meter // Counter for metering the inbound propagations + broadcastTimer metrics.Timer // Counter and timer for metering the block forwarding + discardMeter metrics.Meter // Counter for metering the discarded blocks } // New creates a block fetcher to retrieve blocks based on hash announcements. @@ -125,9 +126,11 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo chainHeight: chainHeight, insertChain: insertChain, dropPeer: dropPeer, - announceStats: metrics.GetOrRegisterMeter("eth/Announced Blocks", metrics.DefaultRegistry), - broadcastStats: metrics.GetOrRegisterMeter("eth/Propagated Blocks", metrics.DefaultRegistry), - discardStats: metrics.GetOrRegisterMeter("eth/Discarded Blocks", metrics.DefaultRegistry), + announceMeter: metrics.GetOrRegisterMeter("eth/RemoteAnnounces", metrics.DefaultRegistry), + announceTimer: metrics.GetOrRegisterTimer("eth/LocalAnnounces", metrics.DefaultRegistry), + broadcastMeter: metrics.GetOrRegisterMeter("eth/RemoteBroadcasts", metrics.DefaultRegistry), + broadcastTimer: metrics.GetOrRegisterTimer("eth/LocalBroadcasts", metrics.DefaultRegistry), + discardMeter: metrics.GetOrRegisterMeter("eth/DiscardedBlocks", metrics.DefaultRegistry), } } @@ -239,7 +242,7 @@ func (f *Fetcher) loop() { case notification := <-f.notify: // A block was announced, make sure the peer isn't DOSing us - f.announceStats.Mark(1) + f.announceMeter.Mark(1) count := f.announces[notification.origin] + 1 if count > hashLimit { @@ -258,7 +261,7 @@ func (f *Fetcher) loop() { case op := <-f.inject: // A direct block insertion was requested, try and fill any pending gaps - f.broadcastStats.Mark(1) + f.broadcastMeter.Mark(1) f.enqueue(op.origin, op.block) case hash := <-f.done: @@ -418,6 +421,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) { f.dropPeer(peer) return } + f.broadcastTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, true) // Run the actual import and log any issues @@ -426,6 +430,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) { return } // If import succeeded, broadcast the block + f.announceTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, false) // Invoke the testing hook if needed -- cgit v1.2.3 From 6260b86c153abfd1d4c96fa558ed20e80c6c0e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 22 Jun 2015 12:14:07 +0300 Subject: eth/fetcher: fix failed merge --- eth/fetcher/fetcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'eth') diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index a8f0dddbd..13c65121b 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -380,7 +380,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) { // Discard any past or too distant blocks if dist := int64(block.NumberU64()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x], distance %d", peer, block.NumberU64(), hash.Bytes()[:4], dist) - f.discardStats.Mark(1) + f.discardMeter.Mark(1) return } // Schedule the block for future importing -- cgit v1.2.3 From 792b0ddccdf135a8d9c33298bcb20d7bafb79a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 23 Jun 2015 13:03:33 +0300 Subject: core, eth, eth/fetcher, ethdb: polish metrics gathering a bit --- eth/backend.go | 19 +++++++++++++++++++ eth/fetcher/fetcher.go | 10 +++++----- 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 'eth') diff --git a/eth/backend.go b/eth/backend.go index 37fe66abf..5969c238c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/whisper" + "github.com/rcrowley/go-metrics" ) const ( @@ -248,14 +249,32 @@ func New(config *Config) (*Ethereum, error) { if err != nil { return nil, fmt.Errorf("blockchain db err: %v", err) } + blockDb.(*ethdb.LDBDatabase).GetMeter = metrics.GetOrRegisterMeter("eth/db/block/Gets", metrics.DefaultRegistry) + blockDb.(*ethdb.LDBDatabase).PutMeter = metrics.GetOrRegisterMeter("eth/db/block/Puts", metrics.DefaultRegistry) + blockDb.(*ethdb.LDBDatabase).DelMeter = metrics.GetOrRegisterMeter("eth/db/block/Dels", metrics.DefaultRegistry) + blockDb.(*ethdb.LDBDatabase).ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/Reads", metrics.DefaultRegistry) + blockDb.(*ethdb.LDBDatabase).WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/Writes", metrics.DefaultRegistry) + stateDb, err := newdb(filepath.Join(config.DataDir, "state")) if err != nil { return nil, fmt.Errorf("state db err: %v", err) } + stateDb.(*ethdb.LDBDatabase).GetMeter = metrics.GetOrRegisterMeter("eth/db/state/Gets", metrics.DefaultRegistry) + stateDb.(*ethdb.LDBDatabase).PutMeter = metrics.GetOrRegisterMeter("eth/db/state/Puts", metrics.DefaultRegistry) + stateDb.(*ethdb.LDBDatabase).DelMeter = metrics.GetOrRegisterMeter("eth/db/state/Dels", metrics.DefaultRegistry) + stateDb.(*ethdb.LDBDatabase).ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/Reads", metrics.DefaultRegistry) + stateDb.(*ethdb.LDBDatabase).WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/Writes", metrics.DefaultRegistry) + extraDb, err := newdb(filepath.Join(config.DataDir, "extra")) if err != nil { return nil, fmt.Errorf("extra db err: %v", err) } + extraDb.(*ethdb.LDBDatabase).GetMeter = metrics.GetOrRegisterMeter("eth/db/extra/Gets", metrics.DefaultRegistry) + extraDb.(*ethdb.LDBDatabase).PutMeter = metrics.GetOrRegisterMeter("eth/db/extra/Puts", metrics.DefaultRegistry) + extraDb.(*ethdb.LDBDatabase).DelMeter = metrics.GetOrRegisterMeter("eth/db/extra/Dels", metrics.DefaultRegistry) + extraDb.(*ethdb.LDBDatabase).ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/Reads", metrics.DefaultRegistry) + extraDb.(*ethdb.LDBDatabase).WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/Writes", metrics.DefaultRegistry) + nodeDb := filepath.Join(config.DataDir, "nodes") // Perform database sanity checks diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 13c65121b..07a32b9f1 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -126,11 +126,11 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo chainHeight: chainHeight, insertChain: insertChain, dropPeer: dropPeer, - announceMeter: metrics.GetOrRegisterMeter("eth/RemoteAnnounces", metrics.DefaultRegistry), - announceTimer: metrics.GetOrRegisterTimer("eth/LocalAnnounces", metrics.DefaultRegistry), - broadcastMeter: metrics.GetOrRegisterMeter("eth/RemoteBroadcasts", metrics.DefaultRegistry), - broadcastTimer: metrics.GetOrRegisterTimer("eth/LocalBroadcasts", metrics.DefaultRegistry), - discardMeter: metrics.GetOrRegisterMeter("eth/DiscardedBlocks", metrics.DefaultRegistry), + announceMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteAnnounces", metrics.DefaultRegistry), + announceTimer: metrics.GetOrRegisterTimer("eth/sync/LocalAnnounces", metrics.DefaultRegistry), + broadcastMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteBroadcasts", metrics.DefaultRegistry), + broadcastTimer: metrics.GetOrRegisterTimer("eth/sync/LocalBroadcasts", metrics.DefaultRegistry), + discardMeter: metrics.GetOrRegisterMeter("eth/sync/DiscardedBlocks", metrics.DefaultRegistry), } } -- cgit v1.2.3 From 0609fcf030f5e93528501e6fea98e096feccec3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 23 Jun 2015 15:54:16 +0300 Subject: eth: make sure dbs are lvldb before instrumenting --- eth/backend.go | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'eth') diff --git a/eth/backend.go b/eth/backend.go index 5969c238c..cef0fe3ab 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -249,32 +249,35 @@ func New(config *Config) (*Ethereum, error) { if err != nil { return nil, fmt.Errorf("blockchain db err: %v", err) } - blockDb.(*ethdb.LDBDatabase).GetMeter = metrics.GetOrRegisterMeter("eth/db/block/Gets", metrics.DefaultRegistry) - blockDb.(*ethdb.LDBDatabase).PutMeter = metrics.GetOrRegisterMeter("eth/db/block/Puts", metrics.DefaultRegistry) - blockDb.(*ethdb.LDBDatabase).DelMeter = metrics.GetOrRegisterMeter("eth/db/block/Dels", metrics.DefaultRegistry) - blockDb.(*ethdb.LDBDatabase).ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/Reads", metrics.DefaultRegistry) - blockDb.(*ethdb.LDBDatabase).WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/Writes", metrics.DefaultRegistry) - + if db, ok := blockDb.(*ethdb.LDBDatabase); ok { + db.GetMeter = metrics.GetOrRegisterMeter("eth/db/block/Gets", metrics.DefaultRegistry) + db.PutMeter = metrics.GetOrRegisterMeter("eth/db/block/Puts", metrics.DefaultRegistry) + db.DelMeter = metrics.GetOrRegisterMeter("eth/db/block/Dels", metrics.DefaultRegistry) + db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/Reads", metrics.DefaultRegistry) + db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/Writes", metrics.DefaultRegistry) + } stateDb, err := newdb(filepath.Join(config.DataDir, "state")) if err != nil { return nil, fmt.Errorf("state db err: %v", err) } - stateDb.(*ethdb.LDBDatabase).GetMeter = metrics.GetOrRegisterMeter("eth/db/state/Gets", metrics.DefaultRegistry) - stateDb.(*ethdb.LDBDatabase).PutMeter = metrics.GetOrRegisterMeter("eth/db/state/Puts", metrics.DefaultRegistry) - stateDb.(*ethdb.LDBDatabase).DelMeter = metrics.GetOrRegisterMeter("eth/db/state/Dels", metrics.DefaultRegistry) - stateDb.(*ethdb.LDBDatabase).ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/Reads", metrics.DefaultRegistry) - stateDb.(*ethdb.LDBDatabase).WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/Writes", metrics.DefaultRegistry) - + if db, ok := stateDb.(*ethdb.LDBDatabase); ok { + db.GetMeter = metrics.GetOrRegisterMeter("eth/db/state/Gets", metrics.DefaultRegistry) + db.PutMeter = metrics.GetOrRegisterMeter("eth/db/state/Puts", metrics.DefaultRegistry) + db.DelMeter = metrics.GetOrRegisterMeter("eth/db/state/Dels", metrics.DefaultRegistry) + db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/Reads", metrics.DefaultRegistry) + db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/Writes", metrics.DefaultRegistry) + } extraDb, err := newdb(filepath.Join(config.DataDir, "extra")) if err != nil { return nil, fmt.Errorf("extra db err: %v", err) } - extraDb.(*ethdb.LDBDatabase).GetMeter = metrics.GetOrRegisterMeter("eth/db/extra/Gets", metrics.DefaultRegistry) - extraDb.(*ethdb.LDBDatabase).PutMeter = metrics.GetOrRegisterMeter("eth/db/extra/Puts", metrics.DefaultRegistry) - extraDb.(*ethdb.LDBDatabase).DelMeter = metrics.GetOrRegisterMeter("eth/db/extra/Dels", metrics.DefaultRegistry) - extraDb.(*ethdb.LDBDatabase).ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/Reads", metrics.DefaultRegistry) - extraDb.(*ethdb.LDBDatabase).WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/Writes", metrics.DefaultRegistry) - + if db, ok := extraDb.(*ethdb.LDBDatabase); ok { + db.GetMeter = metrics.GetOrRegisterMeter("eth/db/extra/Gets", metrics.DefaultRegistry) + db.PutMeter = metrics.GetOrRegisterMeter("eth/db/extra/Puts", metrics.DefaultRegistry) + db.DelMeter = metrics.GetOrRegisterMeter("eth/db/extra/Dels", metrics.DefaultRegistry) + db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/Reads", metrics.DefaultRegistry) + db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/Writes", metrics.DefaultRegistry) + } nodeDb := filepath.Join(config.DataDir, "nodes") // Perform database sanity checks -- cgit v1.2.3 From 803b3c4a825ed0ac5d22c93fc3159651b8c590b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 23 Jun 2015 18:36:08 +0300 Subject: eth, ethdb: measure database operation latencies too --- eth/backend.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'eth') diff --git a/eth/backend.go b/eth/backend.go index cef0fe3ab..0da6f128c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -250,9 +250,9 @@ func New(config *Config) (*Ethereum, error) { return nil, fmt.Errorf("blockchain db err: %v", err) } if db, ok := blockDb.(*ethdb.LDBDatabase); ok { - db.GetMeter = metrics.GetOrRegisterMeter("eth/db/block/Gets", metrics.DefaultRegistry) - db.PutMeter = metrics.GetOrRegisterMeter("eth/db/block/Puts", metrics.DefaultRegistry) - db.DelMeter = metrics.GetOrRegisterMeter("eth/db/block/Dels", metrics.DefaultRegistry) + db.GetTimer = metrics.GetOrRegisterTimer("eth/db/block/Gets", metrics.DefaultRegistry) + db.PutTimer = metrics.GetOrRegisterTimer("eth/db/block/Puts", metrics.DefaultRegistry) + db.MissMeter = metrics.GetOrRegisterMeter("eth/db/block/Misses", metrics.DefaultRegistry) db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/Reads", metrics.DefaultRegistry) db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/Writes", metrics.DefaultRegistry) } @@ -261,9 +261,9 @@ func New(config *Config) (*Ethereum, error) { return nil, fmt.Errorf("state db err: %v", err) } if db, ok := stateDb.(*ethdb.LDBDatabase); ok { - db.GetMeter = metrics.GetOrRegisterMeter("eth/db/state/Gets", metrics.DefaultRegistry) - db.PutMeter = metrics.GetOrRegisterMeter("eth/db/state/Puts", metrics.DefaultRegistry) - db.DelMeter = metrics.GetOrRegisterMeter("eth/db/state/Dels", metrics.DefaultRegistry) + db.GetTimer = metrics.GetOrRegisterTimer("eth/db/state/Gets", metrics.DefaultRegistry) + db.PutTimer = metrics.GetOrRegisterTimer("eth/db/state/Puts", metrics.DefaultRegistry) + db.MissMeter = metrics.GetOrRegisterMeter("eth/db/state/Misses", metrics.DefaultRegistry) db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/Reads", metrics.DefaultRegistry) db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/Writes", metrics.DefaultRegistry) } @@ -272,9 +272,9 @@ func New(config *Config) (*Ethereum, error) { return nil, fmt.Errorf("extra db err: %v", err) } if db, ok := extraDb.(*ethdb.LDBDatabase); ok { - db.GetMeter = metrics.GetOrRegisterMeter("eth/db/extra/Gets", metrics.DefaultRegistry) - db.PutMeter = metrics.GetOrRegisterMeter("eth/db/extra/Puts", metrics.DefaultRegistry) - db.DelMeter = metrics.GetOrRegisterMeter("eth/db/extra/Dels", metrics.DefaultRegistry) + db.GetTimer = metrics.GetOrRegisterTimer("eth/db/extra/Gets", metrics.DefaultRegistry) + db.PutTimer = metrics.GetOrRegisterTimer("eth/db/extra/Puts", metrics.DefaultRegistry) + db.MissMeter = metrics.GetOrRegisterMeter("eth/db/extra/Misses", metrics.DefaultRegistry) db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/Reads", metrics.DefaultRegistry) db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/Writes", metrics.DefaultRegistry) } -- cgit v1.2.3 From 29d53b20739645eb6ecab3ef79ecf3518eae6b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 29 Jun 2015 13:49:04 +0300 Subject: eth/fetcher: don't double filter/fetch the same block --- eth/fetcher/fetcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'eth') diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 07a32b9f1..69f3cb5d1 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -323,7 +323,7 @@ func (f *Fetcher) loop() { hash := block.Hash() // Filter explicitly requested blocks from hash announcements - if _, ok := f.fetching[hash]; ok { + if f.fetching[hash] != nil && f.queued[hash] == nil { // Discard if already imported by other means if f.getBlock(hash) == nil { explicit = append(explicit, block) -- cgit v1.2.3 From a7d22658ad81064abad5a12bd38545c98a0c508c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 29 Jun 2015 14:20:13 +0300 Subject: eth/fetcher: don't drop on future blocks, just not propagate --- eth/fetcher/fetcher.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'eth') diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 69f3cb5d1..5a1509f89 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -7,6 +7,8 @@ import ( "math/rand" "time" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/logger" @@ -104,6 +106,7 @@ type Fetcher struct { broadcastMeter metrics.Meter // Counter for metering the inbound propagations broadcastTimer metrics.Timer // Counter and timer for metering the block forwarding discardMeter metrics.Meter // Counter for metering the discarded blocks + futureMeter metrics.Meter // Counter for metering future blocks } // New creates a block fetcher to retrieve blocks based on hash announcements. @@ -131,6 +134,7 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo broadcastMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteBroadcasts", metrics.DefaultRegistry), broadcastTimer: metrics.GetOrRegisterTimer("eth/sync/LocalBroadcasts", metrics.DefaultRegistry), discardMeter: metrics.GetOrRegisterMeter("eth/sync/DiscardedBlocks", metrics.DefaultRegistry), + futureMeter: metrics.GetOrRegisterMeter("eth/sync/FutureBlocks", metrics.DefaultRegistry), } } @@ -416,14 +420,22 @@ func (f *Fetcher) insert(peer string, block *types.Block) { return } // Quickly validate the header and propagate the block if it passes - if err := f.validateBlock(block, parent); err != nil { + switch err := f.validateBlock(block, parent); err { + case nil: + // All ok, quickly propagate to our peers + f.broadcastTimer.UpdateSince(block.ReceivedAt) + go f.broadcastBlock(block, true) + + case core.BlockFutureErr: + f.futureMeter.Mark(1) + // Weird future block, don't fail, but neither propagate + + default: + // Something went very wrong, drop the peer glog.V(logger.Debug).Infof("Peer %s: block #%d [%x] verification failed: %v", peer, block.NumberU64(), hash[:4], err) f.dropPeer(peer) return } - f.broadcastTimer.UpdateSince(block.ReceivedAt) - go f.broadcastBlock(block, true) - // Run the actual import and log any issues if _, err := f.insertChain(types.Blocks{block}); err != nil { glog.V(logger.Warn).Infof("Peer %s: block #%d [%x] import failed: %v", peer, block.NumberU64(), hash[:4], err) -- cgit v1.2.3 From 654564e164b3b6f7f4ba1e8bbd6fcd64776068fa Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 11 Jun 2015 14:05:32 +0200 Subject: core/types: make transactions immutable --- eth/protocol_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'eth') diff --git a/eth/protocol_test.go b/eth/protocol_test.go index 6e0eef59c..60fa35443 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -234,7 +234,7 @@ func (pool *fakeTxPool) GetTransactions() types.Transactions { func newtx(from *crypto.Key, nonce uint64, datasize int) *types.Transaction { data := make([]byte, datasize) - tx := types.NewTransactionMessage(common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), data) - tx.SetNonce(nonce) + tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), data) + tx, _ = tx.SignECDSA(from.PrivateKey) return tx } -- cgit v1.2.3 From 1d42888d3047dabfb352c94a2051e7af14d2a509 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 16 Jun 2015 12:41:50 +0200 Subject: core/types: make blocks immutable --- eth/downloader/downloader_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'eth') diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 4fc4e1434..fb8aa7e4b 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -40,7 +40,10 @@ func createHashes(amount int, root common.Hash) (hashes []common.Hash) { // createBlock assembles a new block at the given chain height. func createBlock(i int, parent, hash common.Hash) *types.Block { - header := &types.Header{Number: big.NewInt(int64(i))} + header := &types.Header{ + Hash: hash, + Number: big.NewInt(int64(i)) + } block := types.NewBlockWithHeader(header) block.HeaderHash = hash block.ParentHeaderHash = parent -- cgit v1.2.3 From e0e5f747765cec7050dd5ea4eed896e73ef0ab1f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 27 Jun 2015 02:57:53 +0200 Subject: eth/downloader, eth/fetcher: use core.GenerateChain in tests TestMadeupParentBlockChainAttack has been deleted because it was too hard to port and the attack that it checks the prevention of is being averted in a different way (through a protocol change). --- eth/downloader/downloader_test.go | 253 +++++++++++++++----------------------- eth/fetcher/fetcher_test.go | 123 +++++++----------- 2 files changed, 140 insertions(+), 236 deletions(-) (limited to 'eth') diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index fb8aa7e4b..7feca8782 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -1,7 +1,7 @@ package downloader import ( - "encoding/binary" + "crypto/rand" "errors" "fmt" "math/big" @@ -12,61 +12,47 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" ) var ( - knownHash = common.Hash{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - unknownHash = common.Hash{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2} - bannedHash = common.Hash{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3} - - genesis = createBlock(1, common.Hash{}, knownHash) + testdb, _ = ethdb.NewMemDatabase() + genesis = core.GenesisBlockForTesting(testdb, common.Address{}, big.NewInt(0)) ) -// idCounter is used by the createHashes method the generate deterministic but unique hashes -var idCounter = int64(2) // #1 is the genesis block - -// createHashes generates a batch of hashes rooted at a specific point in the chain. -func createHashes(amount int, root common.Hash) (hashes []common.Hash) { - hashes = make([]common.Hash, amount+1) - hashes[len(hashes)-1] = root - - for i := 0; i < len(hashes)-1; i++ { - binary.BigEndian.PutUint64(hashes[i][:8], uint64(idCounter)) - idCounter++ - } - return -} - -// createBlock assembles a new block at the given chain height. -func createBlock(i int, parent, hash common.Hash) *types.Block { - header := &types.Header{ - Hash: hash, - Number: big.NewInt(int64(i)) - } - block := types.NewBlockWithHeader(header) - block.HeaderHash = hash - block.ParentHeaderHash = parent - return block -} - -// copyBlock makes a deep copy of a block suitable for local modifications. -func copyBlock(block *types.Block) *types.Block { - return createBlock(int(block.Number().Int64()), block.ParentHeaderHash, block.HeaderHash) -} - -// createBlocksFromHashes assembles a collection of blocks, each having a correct -// place in the given hash chain. -func createBlocksFromHashes(hashes []common.Hash) map[common.Hash]*types.Block { - blocks := make(map[common.Hash]*types.Block) - for i := 0; i < len(hashes); i++ { - parent := knownHash - if i < len(hashes)-1 { - parent = hashes[i+1] - } - blocks[hashes[i]] = createBlock(len(hashes)-i, parent, hashes[i]) - } - return blocks +// makeChain creates a chain of n blocks starting at and including +// parent. the returned hash chain is ordered head->parent. +func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { + blocks := core.GenerateChain(parent, testdb, n, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(common.Address{seed}) + }) + hashes := make([]common.Hash, n+1) + hashes[len(hashes)-1] = parent.Hash() + blockm := make(map[common.Hash]*types.Block, n+1) + blockm[parent.Hash()] = parent + for i, b := range blocks { + hashes[len(hashes)-i-2] = b.Hash() + blockm[b.Hash()] = b + } + return hashes, blockm +} + +// makeChainFork creates two chains of length n, such that h1[:f] and +// h2[:f] are different but have a common suffix of length n-f. +func makeChainFork(n, f int, parent *types.Block) (h1, h2 []common.Hash, b1, b2 map[common.Hash]*types.Block) { + // Create the common suffix. + h, b := makeChain(n-f-1, 0, parent) + // Create the forks. + h1, b1 = makeChain(f, 1, b[h[0]]) + h1 = append(h1, h[1:]...) + h2, b2 = makeChain(f, 2, b[h[0]]) + h2 = append(h2, h[1:]...) + for hash, block := range b { + b1[hash] = block + b2[hash] = block + } + return h1, h2, b1, b2 } // downloadTester is a test simulator for mocking out local block chain. @@ -84,8 +70,8 @@ type downloadTester struct { // newTester creates a new downloader test mocker. func newTester() *downloadTester { tester := &downloadTester{ - ownHashes: []common.Hash{knownHash}, - ownBlocks: map[common.Hash]*types.Block{knownHash: genesis}, + ownHashes: []common.Hash{genesis.Hash()}, + ownBlocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, peerHashes: make(map[string][]common.Hash), peerBlocks: make(map[string]map[common.Hash]*types.Block), } @@ -139,10 +125,9 @@ func (dl *downloadTester) newSlowPeer(id string, hashes []common.Hash, blocks ma // Assign the owned hashes and blocks to the peer (deep copy) dl.peerHashes[id] = make([]common.Hash, len(hashes)) copy(dl.peerHashes[id], hashes) - dl.peerBlocks[id] = make(map[common.Hash]*types.Block) for hash, block := range blocks { - dl.peerBlocks[id][hash] = copyBlock(block) + dl.peerBlocks[id][hash] = block } } return err @@ -213,8 +198,7 @@ func (dl *downloadTester) peerGetBlocksFn(id string, delay time.Duration) func([ func TestSynchronisation(t *testing.T) { // Create a small enough block chain to download and the tester targetBlocks := blockCacheLimit - 15 - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) tester := newTester() tester.newPeer("peer", hashes, blocks) @@ -245,8 +229,7 @@ func TestInactiveDownloader(t *testing.T) { func TestCancel(t *testing.T) { // Create a small enough block chain to download and the tester targetBlocks := blockCacheLimit - 15 - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) tester := newTester() tester.newPeer("peer", hashes, blocks) @@ -273,8 +256,7 @@ func TestCancel(t *testing.T) { func TestThrottling(t *testing.T) { // Create a long block chain to download and the tester targetBlocks := 8 * blockCacheLimit - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) tester := newTester() tester.newPeer("peer", hashes, blocks) @@ -330,9 +312,7 @@ func TestMultiSynchronisation(t *testing.T) { // Create various peers with various parts of the chain targetPeers := 16 targetBlocks := targetPeers*blockCacheLimit - 15 - - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) tester := newTester() for i := 0; i < targetPeers; i++ { @@ -365,9 +345,7 @@ func TestSlowSynchronisation(t *testing.T) { targetCycles := 2 targetBlocks := targetCycles*blockCacheLimit - 15 targetIODelay := time.Second - - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) tester.newSlowPeer("fast", hashes, blocks, 0) tester.newSlowPeer("slow", hashes, blocks, targetIODelay) @@ -392,14 +370,12 @@ func TestSlowSynchronisation(t *testing.T) { func TestNonExistingParentAttack(t *testing.T) { tester := newTester() - // Forge a single-link chain with a forged header - hashes := createHashes(1, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(1, 0, genesis) tester.newPeer("valid", hashes, blocks) - hashes = createHashes(1, knownHash) - blocks = createBlocksFromHashes(hashes) - blocks[hashes[0]].ParentHeaderHash = unknownHash + wrongblock := types.NewBlock(&types.Header{}, nil, nil, nil) + wrongblock.Td = blocks[hashes[0]].Td + hashes, blocks = makeChain(1, 0, wrongblock) tester.newPeer("attack", hashes, blocks) // Try and sync with the malicious node and check that it fails @@ -424,8 +400,7 @@ func TestRepeatingHashAttack(t *testing.T) { // TODO: Is this thing valid?? tester := newTester() // Create a valid chain, but drop the last link - hashes := createHashes(blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(blockCacheLimit, 0, genesis) tester.newPeer("valid", hashes, blocks) tester.newPeer("attack", hashes[:len(hashes)-1], blocks) @@ -455,11 +430,10 @@ func TestNonExistingBlockAttack(t *testing.T) { tester := newTester() // Create a valid chain, but forge the last link - hashes := createHashes(blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(blockCacheLimit, 0, genesis) tester.newPeer("valid", hashes, blocks) - hashes[len(hashes)/2] = unknownHash + hashes[len(hashes)/2] = common.Hash{} tester.newPeer("attack", hashes, blocks) // Try and sync with the malicious node and check that it fails @@ -478,8 +452,7 @@ func TestInvalidHashOrderAttack(t *testing.T) { tester := newTester() // Create a valid long chain, but reverse some hashes within - hashes := createHashes(4*blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(4*blockCacheLimit, 0, genesis) tester.newPeer("valid", hashes, blocks) chunk1 := make([]common.Hash, blockCacheLimit) @@ -509,11 +482,15 @@ func TestMadeupHashChainAttack(t *testing.T) { crossCheckCycle = 25 * time.Millisecond // Create a long chain of hashes without backing blocks - hashes := createHashes(4*blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(4*blockCacheLimit, 0, genesis) + + randomHashes := make([]common.Hash, 1024*blockCacheLimit) + for i := range randomHashes { + rand.Read(randomHashes[i][:]) + } tester.newPeer("valid", hashes, blocks) - tester.newPeer("attack", createHashes(1024*blockCacheLimit, knownHash), nil) + tester.newPeer("attack", randomHashes, nil) // Try and sync with the malicious node and check that it fails if err := tester.sync("attack"); err != errCrossCheckFailed { @@ -531,12 +508,16 @@ func TestMadeupHashChainAttack(t *testing.T) { // one by one prevents reliable block/parent verification. func TestMadeupHashChainDrippingAttack(t *testing.T) { // Create a random chain of hashes to drip - hashes := createHashes(16*blockCacheLimit, knownHash) + randomHashes := make([]common.Hash, 16*blockCacheLimit) + for i := range randomHashes { + rand.Read(randomHashes[i][:]) + } + randomHashes[len(randomHashes)-1] = genesis.Hash() tester := newTester() // Try and sync with the attacker, one hash at a time tester.maxHashFetch = 1 - tester.newPeer("attack", hashes, nil) + tester.newPeer("attack", randomHashes, nil) if err := tester.sync("attack"); err != errStallingPeer { t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer) } @@ -552,9 +533,7 @@ func TestMadeupBlockChainAttack(t *testing.T) { crossCheckCycle = 25 * time.Millisecond // Create a long chain of blocks and simulate an invalid chain by dropping every second - hashes := createHashes(16*blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) - + hashes, blocks := makeChain(16*blockCacheLimit, 0, genesis) gapped := make([]common.Hash, len(hashes)/2) for i := 0; i < len(gapped); i++ { gapped[i] = hashes[2*i] @@ -575,65 +554,26 @@ func TestMadeupBlockChainAttack(t *testing.T) { } } -// Advanced form of the above forged blockchain attack, where not only does the -// attacker make up a valid hashes for random blocks, but also forges the block -// parents to point to existing hashes. -func TestMadeupParentBlockChainAttack(t *testing.T) { - tester := newTester() - - defaultBlockTTL := blockSoftTTL - defaultCrossCheckCycle := crossCheckCycle - - blockSoftTTL = 100 * time.Millisecond - crossCheckCycle = 25 * time.Millisecond - - // Create a long chain of blocks and simulate an invalid chain by dropping every second - hashes := createHashes(16*blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) - tester.newPeer("valid", hashes, blocks) - - for _, block := range blocks { - block.ParentHeaderHash = knownHash // Simulate pointing to already known hash - } - tester.newPeer("attack", hashes, blocks) - - // Try and sync with the malicious node and check that it fails - if err := tester.sync("attack"); err != errCrossCheckFailed { - t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errCrossCheckFailed) - } - // Ensure that a valid chain can still pass sync - blockSoftTTL = defaultBlockTTL - crossCheckCycle = defaultCrossCheckCycle - - if err := tester.sync("valid"); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) - } -} - -// Tests that if one/multiple malicious peers try to feed a banned blockchain to +// tests that if one/multiple malicious peers try to feed a banned blockchain to // the downloader, it will not keep refetching the same chain indefinitely, but -// gradually block pieces of it, until it's head is also blocked. +// gradually block pieces of it, until its head is also blocked. func TestBannedChainStarvationAttack(t *testing.T) { - // Create the tester and ban the selected hash - tester := newTester() - tester.downloader.banned.Add(bannedHash) + n := 8 * blockCacheLimit + fork := n/2 - 23 + hashes, forkHashes, blocks, forkBlocks := makeChainFork(n, fork, genesis) - // Construct a valid chain, for it and ban the fork - hashes := createHashes(8*blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) + // Create the tester and ban the selected hash. + tester := newTester() + tester.downloader.banned.Add(forkHashes[fork-1]) tester.newPeer("valid", hashes, blocks) - - fork := len(hashes)/2 - 23 - hashes = append(createHashes(4*blockCacheLimit, bannedHash), hashes[fork:]...) - blocks = createBlocksFromHashes(hashes) - tester.newPeer("attack", hashes, blocks) + tester.newPeer("attack", forkHashes, forkBlocks) // Iteratively try to sync, and verify that the banned hash list grows until // the head of the invalid chain is blocked too. for banned := tester.downloader.banned.Size(); ; { // Try to sync with the attacker, check hash chain failure if err := tester.sync("attack"); err != errInvalidChain { - if tester.downloader.banned.Has(hashes[0]) && err == errBannedHead { + if tester.downloader.banned.Has(forkHashes[0]) && err == errBannedHead { break } t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain) @@ -646,7 +586,7 @@ func TestBannedChainStarvationAttack(t *testing.T) { banned = bans } // Check that after banning an entire chain, bad peers get dropped - if err := tester.newPeer("new attacker", hashes, blocks); err != errBannedHead { + if err := tester.newPeer("new attacker", forkHashes, forkBlocks); err != errBannedHead { t.Fatalf("peer registration mismatch: have %v, want %v", err, errBannedHead) } if peer := tester.downloader.peers.Peer("new attacker"); peer != nil { @@ -662,9 +602,14 @@ func TestBannedChainStarvationAttack(t *testing.T) { // gradually banned, it will have an upper limit on the consumed memory and also // the origin bad hashes will not be evacuated. func TestBannedChainMemoryExhaustionAttack(t *testing.T) { - // Create the tester and ban the selected hash + // Construct a banned chain with more chunks than the ban limit + n := 8 * blockCacheLimit + fork := n/2 - 23 + hashes, forkHashes, blocks, forkBlocks := makeChainFork(n, fork, genesis) + + // Create the tester and ban the root hash of the fork. tester := newTester() - tester.downloader.banned.Add(bannedHash) + tester.downloader.banned.Add(forkHashes[fork-1]) // Reduce the test size a bit defaultMaxBlockFetch := MaxBlockFetch @@ -673,15 +618,8 @@ func TestBannedChainMemoryExhaustionAttack(t *testing.T) { MaxBlockFetch = 4 maxBannedHashes = 256 - // Construct a banned chain with more chunks than the ban limit - hashes := createHashes(8*blockCacheLimit, knownHash) - blocks := createBlocksFromHashes(hashes) tester.newPeer("valid", hashes, blocks) - - fork := len(hashes)/2 - 23 - hashes = append(createHashes(maxBannedHashes*MaxBlockFetch, bannedHash), hashes[fork:]...) - blocks = createBlocksFromHashes(hashes) - tester.newPeer("attack", hashes, blocks) + tester.newPeer("attack", forkHashes, forkBlocks) // Iteratively try to sync, and verify that the banned hash list grows until // the head of the invalid chain is blocked too. @@ -690,8 +628,8 @@ func TestBannedChainMemoryExhaustionAttack(t *testing.T) { if err := tester.sync("attack"); err != errInvalidChain { t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain) } - // Short circuit if the entire chain was banned - if tester.downloader.banned.Has(hashes[0]) { + // Short circuit if the entire chain was banned. + if tester.downloader.banned.Has(forkHashes[0]) { break } // Otherwise ensure we never exceed the memory allowance and the hard coded bans are untouched @@ -722,8 +660,7 @@ func TestBannedChainMemoryExhaustionAttack(t *testing.T) { func TestOverlappingDeliveryAttack(t *testing.T) { // Create an arbitrary batch of blocks ( < cache-size not to block) targetBlocks := blockCacheLimit - 23 - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) // Register an attacker that always returns non-requested blocks too tester := newTester() @@ -775,7 +712,7 @@ func TestHashAttackerDropping(t *testing.T) { for i, tt := range tests { // Register a new peer and ensure it's presence id := fmt.Sprintf("test %d", i) - if err := tester.newPeer(id, []common.Hash{knownHash}, nil); err != nil { + if err := tester.newPeer(id, []common.Hash{genesis.Hash()}, nil); err != nil { t.Fatalf("test %d: failed to register new peer: %v", i, err) } if _, ok := tester.peerHashes[id]; !ok { @@ -784,7 +721,7 @@ func TestHashAttackerDropping(t *testing.T) { // Simulate a synchronisation and check the required result tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.result } - tester.downloader.Synchronise(id, knownHash) + tester.downloader.Synchronise(id, genesis.Hash()) if _, ok := tester.peerHashes[id]; !ok != tt.drop { t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop) } @@ -797,7 +734,10 @@ func TestBlockAttackerDropping(t *testing.T) { tests := []struct { failure bool drop bool - }{{true, true}, {false, false}} + }{ + {true, true}, + {false, false}, + } // Run the tests and check disconnection status tester := newTester() @@ -811,9 +751,10 @@ func TestBlockAttackerDropping(t *testing.T) { t.Fatalf("test %d: registered peer not found", i) } // Assemble a good or bad block, depending of the test - raw := createBlock(1, knownHash, common.Hash{}) + raw := core.GenerateChain(genesis, testdb, 1, nil)[0] if tt.failure { - raw = createBlock(1, unknownHash, common.Hash{}) + parent := types.NewBlock(&types.Header{}, nil, nil, nil) + raw = core.GenerateChain(parent, testdb, 1, nil)[0] } block := &Block{OriginPeer: id, RawBlock: raw} diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 80247d9d2..2c9c9bca3 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -1,7 +1,6 @@ package fetcher import ( - "encoding/binary" "errors" "math/big" "sync" @@ -10,58 +9,32 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" ) var ( - knownHash = common.Hash{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - unknownHash = common.Hash{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2} - bannedHash = common.Hash{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3} - - genesis = createBlock(1, common.Hash{}, knownHash) + testdb, _ = ethdb.NewMemDatabase() + genesis = core.GenesisBlockForTesting(testdb, common.Address{}, big.NewInt(0)) + unknownBlock = types.NewBlock(&types.Header{}, nil, nil, nil) ) -// idCounter is used by the createHashes method the generate deterministic but unique hashes -var idCounter = int64(2) // #1 is the genesis block - -// createHashes generates a batch of hashes rooted at a specific point in the chain. -func createHashes(amount int, root common.Hash) (hashes []common.Hash) { - hashes = make([]common.Hash, amount+1) - hashes[len(hashes)-1] = root - - for i := 0; i < len(hashes)-1; i++ { - binary.BigEndian.PutUint64(hashes[i][:8], uint64(idCounter)) - idCounter++ - } - return -} - -// createBlock assembles a new block at the given chain height. -func createBlock(i int, parent, hash common.Hash) *types.Block { - header := &types.Header{Number: big.NewInt(int64(i))} - block := types.NewBlockWithHeader(header) - block.HeaderHash = hash - block.ParentHeaderHash = parent - return block -} - -// copyBlock makes a deep copy of a block suitable for local modifications. -func copyBlock(block *types.Block) *types.Block { - return createBlock(int(block.Number().Int64()), block.ParentHeaderHash, block.HeaderHash) -} - -// createBlocksFromHashes assembles a collection of blocks, each having a correct -// place in the given hash chain. -func createBlocksFromHashes(hashes []common.Hash) map[common.Hash]*types.Block { - blocks := make(map[common.Hash]*types.Block) - for i := 0; i < len(hashes); i++ { - parent := knownHash - if i < len(hashes)-1 { - parent = hashes[i+1] - } - blocks[hashes[i]] = createBlock(len(hashes)-i, parent, hashes[i]) - } - return blocks +// makeChain creates a chain of n blocks starting at and including parent. +// the returned hash chain is ordered head->parent. +func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { + blocks := core.GenerateChain(parent, testdb, n, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(common.Address{seed}) + }) + hashes := make([]common.Hash, n+1) + hashes[len(hashes)-1] = parent.Hash() + blockm := make(map[common.Hash]*types.Block, n+1) + blockm[parent.Hash()] = parent + for i, b := range blocks { + hashes[len(hashes)-i-2] = b.Hash() + blockm[b.Hash()] = b + } + return hashes, blockm } // fetcherTester is a test simulator for mocking out local block chain. @@ -77,8 +50,8 @@ type fetcherTester struct { // newTester creates a new fetcher test mocker. func newTester() *fetcherTester { tester := &fetcherTester{ - hashes: []common.Hash{knownHash}, - blocks: map[common.Hash]*types.Block{knownHash: genesis}, + hashes: []common.Hash{genesis.Hash()}, + blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, } tester.fetcher = New(tester.getBlock, tester.verifyBlock, tester.broadcastBlock, tester.chainHeight, tester.insertChain, tester.dropPeer) tester.fetcher.Start() @@ -138,10 +111,9 @@ func (f *fetcherTester) dropPeer(peer string) { // peerFetcher retrieves a fetcher associated with a simulated peer. func (f *fetcherTester) makeFetcher(blocks map[common.Hash]*types.Block) blockRequesterFn { - // Copy all the blocks to ensure they are not tampered with closure := make(map[common.Hash]*types.Block) for hash, block := range blocks { - closure[hash] = copyBlock(block) + closure[hash] = block } // Create a function that returns blocks from the closure return func(hashes []common.Hash) error { @@ -195,8 +167,7 @@ func verifyImportDone(t *testing.T, imported chan *types.Block) { func TestSequentialAnnouncements(t *testing.T) { // Create a chain of blocks to import targetBlocks := 4 * hashLimit - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) tester := newTester() fetcher := tester.makeFetcher(blocks) @@ -217,8 +188,7 @@ func TestSequentialAnnouncements(t *testing.T) { func TestConcurrentAnnouncements(t *testing.T) { // Create a chain of blocks to import targetBlocks := 4 * hashLimit - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) // Assemble a tester with a built in counter for the requests tester := newTester() @@ -253,8 +223,7 @@ func TestConcurrentAnnouncements(t *testing.T) { func TestOverlappingAnnouncements(t *testing.T) { // Create a chain of blocks to import targetBlocks := 4 * hashLimit - hashes := createHashes(targetBlocks, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(targetBlocks, 0, genesis) tester := newTester() fetcher := tester.makeFetcher(blocks) @@ -280,8 +249,7 @@ func TestOverlappingAnnouncements(t *testing.T) { // Tests that announces already being retrieved will not be duplicated. func TestPendingDeduplication(t *testing.T) { // Create a hash and corresponding block - hashes := createHashes(1, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(1, 0, genesis) // Assemble a tester with a built in counter and delayed fetcher tester := newTester() @@ -319,9 +287,9 @@ func TestPendingDeduplication(t *testing.T) { // imported when all the gaps are filled in. func TestRandomArrivalImport(t *testing.T) { // Create a chain of blocks to import, and choose one to delay - hashes := createHashes(maxQueueDist, knownHash) - blocks := createBlocksFromHashes(hashes) - skip := maxQueueDist / 2 + targetBlocks := maxQueueDist + hashes, blocks := makeChain(targetBlocks, 0, genesis) + skip := targetBlocks / 2 tester := newTester() fetcher := tester.makeFetcher(blocks) @@ -345,9 +313,9 @@ func TestRandomArrivalImport(t *testing.T) { // are correctly schedule, filling and import queue gaps. func TestQueueGapFill(t *testing.T) { // Create a chain of blocks to import, and choose one to not announce at all - hashes := createHashes(maxQueueDist, knownHash) - blocks := createBlocksFromHashes(hashes) - skip := maxQueueDist / 2 + targetBlocks := maxQueueDist + hashes, blocks := makeChain(targetBlocks, 0, genesis) + skip := targetBlocks / 2 tester := newTester() fetcher := tester.makeFetcher(blocks) @@ -371,8 +339,7 @@ func TestQueueGapFill(t *testing.T) { // announces, etc) do not get scheduled for import multiple times. func TestImportDeduplication(t *testing.T) { // Create two blocks to import (one for duplication, the other for stalling) - hashes := createHashes(2, knownHash) - blocks := createBlocksFromHashes(hashes) + hashes, blocks := makeChain(2, 0, genesis) // Create the tester and wrap the importer with a counter tester := newTester() @@ -410,9 +377,7 @@ func TestImportDeduplication(t *testing.T) { // discarded no prevent wasting resources on useless blocks from faulty peers. func TestDistantDiscarding(t *testing.T) { // Create a long chain to import - hashes := createHashes(3*maxQueueDist, knownHash) - blocks := createBlocksFromHashes(hashes) - + hashes, blocks := makeChain(3*maxQueueDist, 0, genesis) head := hashes[len(hashes)/2] // Create a tester and simulate a head block being the middle of the above chain @@ -445,11 +410,11 @@ func TestHashMemoryExhaustionAttack(t *testing.T) { tester.fetcher.importedHook = func(block *types.Block) { imported <- block } // Create a valid chain and an infinite junk chain - hashes := createHashes(hashLimit+2*maxQueueDist, knownHash) - blocks := createBlocksFromHashes(hashes) + targetBlocks := hashLimit + 2*maxQueueDist + hashes, blocks := makeChain(targetBlocks, 0, genesis) valid := tester.makeFetcher(blocks) - attack := createHashes(hashLimit+2*maxQueueDist, unknownHash) + attack, _ := makeChain(targetBlocks, 0, unknownBlock) attacker := tester.makeFetcher(nil) // Feed the tester a huge hashset from the attacker, and a limited from the valid peer @@ -484,13 +449,11 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) { tester.fetcher.importedHook = func(block *types.Block) { imported <- block } // Create a valid chain and a batch of dangling (but in range) blocks - hashes := createHashes(blockLimit+2*maxQueueDist, knownHash) - blocks := createBlocksFromHashes(hashes) - + targetBlocks := hashLimit + 2*maxQueueDist + hashes, blocks := makeChain(targetBlocks, 0, genesis) attack := make(map[common.Hash]*types.Block) - for len(attack) < blockLimit+2*maxQueueDist { - hashes := createHashes(maxQueueDist-1, unknownHash) - blocks := createBlocksFromHashes(hashes) + for i := byte(0); len(attack) < blockLimit+2*maxQueueDist; i++ { + hashes, blocks := makeChain(maxQueueDist-1, i, unknownBlock) for _, hash := range hashes[:maxQueueDist-2] { attack[hash] = blocks[hash] } @@ -499,7 +462,7 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) { for _, block := range attack { tester.fetcher.Enqueue("attacker", block) } - time.Sleep(100 * time.Millisecond) + time.Sleep(200 * time.Millisecond) if queued := tester.fetcher.queue.Size(); queued != blockLimit { t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit) } -- cgit v1.2.3 From 76821d167acd7da15e13b23beeceb6779138ffe5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 27 Jun 2015 03:08:50 +0200 Subject: core, eth, rpc: avoid unnecessary block header copying --- eth/gasprice.go | 12 ++++++------ eth/handler.go | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'eth') diff --git a/eth/gasprice.go b/eth/gasprice.go index cd5293691..44202d709 100644 --- a/eth/gasprice.go +++ b/eth/gasprice.go @@ -133,20 +133,20 @@ func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int { gasUsed = recepits[len(recepits)-1].CumulativeGasUsed } - if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.Header().GasLimit, + if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.GasLimit(), big.NewInt(int64(self.eth.GpoFullBlockRatio)))) < 0 { // block is not full, could have posted a tx with MinGasPrice return self.eth.GpoMinGasPrice } - if len(block.Transactions()) < 1 { + txs := block.Transactions() + if len(txs) == 0 { return self.eth.GpoMinGasPrice } - // block is full, find smallest gasPrice - minPrice := block.Transactions()[0].GasPrice() - for i := 1; i < len(block.Transactions()); i++ { - price := block.Transactions()[i].GasPrice() + minPrice := txs[0].GasPrice() + for i := 1; i < len(txs); i++ { + price := txs[i].GasPrice() if price.Cmp(minPrice) < 0 { minPrice = price } diff --git a/eth/handler.go b/eth/handler.go index ad88e9c59..278a2bec2 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -93,7 +93,7 @@ func NewProtocolManager(protocolVersion, networkId int, mux *event.TypeMux, txpo manager.downloader = downloader.New(manager.eventMux, manager.chainman.HasBlock, manager.chainman.GetBlock, manager.chainman.InsertChain, manager.removePeer) validator := func(block *types.Block, parent *types.Block) error { - return core.ValidateHeader(pow, block.Header(), parent.Header(), true) + return core.ValidateHeader(pow, block.Header(), parent, true) } heighter := func() uint64 { return manager.chainman.CurrentBlock().NumberU64() -- cgit v1.2.3 From 5d9df7348d80fbd5de9a92d7f6abe6c02646c24d Mon Sep 17 00:00:00 2001 From: zsfelfoldi Date: Mon, 29 Jun 2015 13:48:10 +0200 Subject: gpo non-existent block checks --- eth/gasprice.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'eth') diff --git a/eth/gasprice.go b/eth/gasprice.go index 44202d709..ddf1c8c09 100644 --- a/eth/gasprice.go +++ b/eth/gasprice.go @@ -47,14 +47,21 @@ func NewGasPriceOracle(eth *Ethereum) (self *GasPriceOracle) { } func (self *GasPriceOracle) processPastBlocks() { - last := self.chain.CurrentBlock().NumberU64() - first := uint64(0) + last := int64(-1) + cblock := self.chain.CurrentBlock() + if cblock != nil { + last = int64(cblock.NumberU64()) + } + first := int64(0) if last > gpoProcessPastBlocks { first = last - gpoProcessPastBlocks } - self.firstProcessed = first + self.firstProcessed = uint64(first) for i := first; i <= last; i++ { - self.processBlock(self.chain.GetBlockByNumber(i)) + block := self.chain.GetBlockByNumber(uint64(i)) + if block != nil { + self.processBlock(block) + } } } -- cgit v1.2.3 From ccbb56b4f2cdba352eaa859ce3e34f999287f5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sat, 27 Jun 2015 20:03:31 +0300 Subject: cmd/geth, eth, ethdb: monitor database compactions --- eth/backend.go | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'eth') diff --git a/eth/backend.go b/eth/backend.go index 0da6f128c..21ec71b10 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -250,33 +250,42 @@ func New(config *Config) (*Ethereum, error) { return nil, fmt.Errorf("blockchain db err: %v", err) } if db, ok := blockDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/block/Gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/block/Puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/block/Misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/Reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/Writes", metrics.DefaultRegistry) + db.GetTimer = metrics.GetOrRegisterTimer("eth/db/block/user/gets", metrics.DefaultRegistry) + db.PutTimer = metrics.GetOrRegisterTimer("eth/db/block/user/puts", metrics.DefaultRegistry) + db.MissMeter = metrics.GetOrRegisterMeter("eth/db/block/user/misses", metrics.DefaultRegistry) + db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/user/reads", metrics.DefaultRegistry) + db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/user/writes", metrics.DefaultRegistry) + db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/time", metrics.DefaultRegistry) + db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/input", metrics.DefaultRegistry) + db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/output", metrics.DefaultRegistry) } stateDb, err := newdb(filepath.Join(config.DataDir, "state")) if err != nil { return nil, fmt.Errorf("state db err: %v", err) } if db, ok := stateDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/state/Gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/state/Puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/state/Misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/Reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/Writes", metrics.DefaultRegistry) + db.GetTimer = metrics.GetOrRegisterTimer("eth/db/state/user/gets", metrics.DefaultRegistry) + db.PutTimer = metrics.GetOrRegisterTimer("eth/db/state/user/puts", metrics.DefaultRegistry) + db.MissMeter = metrics.GetOrRegisterMeter("eth/db/state/user/misses", metrics.DefaultRegistry) + db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/user/reads", metrics.DefaultRegistry) + db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/user/writes", metrics.DefaultRegistry) + db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/time", metrics.DefaultRegistry) + db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/input", metrics.DefaultRegistry) + db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/output", metrics.DefaultRegistry) } extraDb, err := newdb(filepath.Join(config.DataDir, "extra")) if err != nil { return nil, fmt.Errorf("extra db err: %v", err) } if db, ok := extraDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/extra/Gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/extra/Puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/extra/Misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/Reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/Writes", metrics.DefaultRegistry) + db.GetTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/gets", metrics.DefaultRegistry) + db.PutTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/puts", metrics.DefaultRegistry) + db.MissMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/misses", metrics.DefaultRegistry) + db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/reads", metrics.DefaultRegistry) + db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/writes", metrics.DefaultRegistry) + db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/time", metrics.DefaultRegistry) + db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/input", metrics.DefaultRegistry) + db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/output", metrics.DefaultRegistry) } nodeDb := filepath.Join(config.DataDir, "nodes") -- cgit v1.2.3 From 01fe97211354d13ecaba8a52c82b808b7a7e8393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 29 Jun 2015 16:11:01 +0300 Subject: cmd, core, eth, metrics, p2p: require enabling metrics --- eth/backend.go | 51 +++++++++++++++++++++++++------------------------- eth/fetcher/fetcher.go | 30 +++++++---------------------- eth/fetcher/metrics.go | 16 ++++++++++++++++ 3 files changed, 49 insertions(+), 48 deletions(-) create mode 100644 eth/fetcher/metrics.go (limited to 'eth') diff --git a/eth/backend.go b/eth/backend.go index 21ec71b10..4644b8a93 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -11,6 +11,8 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -29,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/whisper" - "github.com/rcrowley/go-metrics" ) const ( @@ -250,42 +251,42 @@ func New(config *Config) (*Ethereum, error) { return nil, fmt.Errorf("blockchain db err: %v", err) } if db, ok := blockDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/block/user/gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/block/user/puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/block/user/misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/user/reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/user/writes", metrics.DefaultRegistry) - db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/time", metrics.DefaultRegistry) - db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/input", metrics.DefaultRegistry) - db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/output", metrics.DefaultRegistry) + db.GetTimer = metrics.NewTimer("eth/db/block/user/gets") + db.PutTimer = metrics.NewTimer("eth/db/block/user/puts") + db.MissMeter = metrics.NewMeter("eth/db/block/user/misses") + db.ReadMeter = metrics.NewMeter("eth/db/block/user/reads") + db.WriteMeter = metrics.NewMeter("eth/db/block/user/writes") + db.CompTimeMeter = metrics.NewMeter("eth/db/block/compact/time") + db.CompReadMeter = metrics.NewMeter("eth/db/block/compact/input") + db.CompWriteMeter = metrics.NewMeter("eth/db/block/compact/output") } stateDb, err := newdb(filepath.Join(config.DataDir, "state")) if err != nil { return nil, fmt.Errorf("state db err: %v", err) } if db, ok := stateDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/state/user/gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/state/user/puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/state/user/misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/user/reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/user/writes", metrics.DefaultRegistry) - db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/time", metrics.DefaultRegistry) - db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/input", metrics.DefaultRegistry) - db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/output", metrics.DefaultRegistry) + db.GetTimer = metrics.NewTimer("eth/db/state/user/gets") + db.PutTimer = metrics.NewTimer("eth/db/state/user/puts") + db.MissMeter = metrics.NewMeter("eth/db/state/user/misses") + db.ReadMeter = metrics.NewMeter("eth/db/state/user/reads") + db.WriteMeter = metrics.NewMeter("eth/db/state/user/writes") + db.CompTimeMeter = metrics.NewMeter("eth/db/state/compact/time") + db.CompReadMeter = metrics.NewMeter("eth/db/state/compact/input") + db.CompWriteMeter = metrics.NewMeter("eth/db/state/compact/output") } extraDb, err := newdb(filepath.Join(config.DataDir, "extra")) if err != nil { return nil, fmt.Errorf("extra db err: %v", err) } if db, ok := extraDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/writes", metrics.DefaultRegistry) - db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/time", metrics.DefaultRegistry) - db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/input", metrics.DefaultRegistry) - db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/output", metrics.DefaultRegistry) + db.GetTimer = metrics.NewTimer("eth/db/extra/user/gets") + db.PutTimer = metrics.NewTimer("eth/db/extra/user/puts") + db.MissMeter = metrics.NewMeter("eth/db/extra/user/misses") + db.ReadMeter = metrics.NewMeter("eth/db/extra/user/reads") + db.WriteMeter = metrics.NewMeter("eth/db/extra/user/writes") + db.CompTimeMeter = metrics.NewMeter("eth/db/extra/compact/time") + db.CompReadMeter = metrics.NewMeter("eth/db/extra/compact/input") + db.CompWriteMeter = metrics.NewMeter("eth/db/extra/compact/output") } nodeDb := filepath.Join(config.DataDir, "nodes") diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 5a1509f89..256b452e1 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -7,13 +7,11 @@ import ( "math/rand" "time" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" - "github.com/rcrowley/go-metrics" "gopkg.in/karalabe/cookiejar.v2/collections/prque" ) @@ -99,14 +97,6 @@ type Fetcher struct { // Testing hooks fetchingHook func([]common.Hash) // Method to call upon starting a block fetch importedHook func(*types.Block) // Method to call upon successful block import - - // Runtime metrics - announceMeter metrics.Meter // Counter for metering the inbound announcements - announceTimer metrics.Timer // Counter and timer for metering the announce forwarding - broadcastMeter metrics.Meter // Counter for metering the inbound propagations - broadcastTimer metrics.Timer // Counter and timer for metering the block forwarding - discardMeter metrics.Meter // Counter for metering the discarded blocks - futureMeter metrics.Meter // Counter for metering future blocks } // New creates a block fetcher to retrieve blocks based on hash announcements. @@ -129,12 +119,6 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo chainHeight: chainHeight, insertChain: insertChain, dropPeer: dropPeer, - announceMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteAnnounces", metrics.DefaultRegistry), - announceTimer: metrics.GetOrRegisterTimer("eth/sync/LocalAnnounces", metrics.DefaultRegistry), - broadcastMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteBroadcasts", metrics.DefaultRegistry), - broadcastTimer: metrics.GetOrRegisterTimer("eth/sync/LocalBroadcasts", metrics.DefaultRegistry), - discardMeter: metrics.GetOrRegisterMeter("eth/sync/DiscardedBlocks", metrics.DefaultRegistry), - futureMeter: metrics.GetOrRegisterMeter("eth/sync/FutureBlocks", metrics.DefaultRegistry), } } @@ -246,7 +230,7 @@ func (f *Fetcher) loop() { case notification := <-f.notify: // A block was announced, make sure the peer isn't DOSing us - f.announceMeter.Mark(1) + announceMeter.Mark(1) count := f.announces[notification.origin] + 1 if count > hashLimit { @@ -265,7 +249,7 @@ func (f *Fetcher) loop() { case op := <-f.inject: // A direct block insertion was requested, try and fill any pending gaps - f.broadcastMeter.Mark(1) + broadcastMeter.Mark(1) f.enqueue(op.origin, op.block) case hash := <-f.done: @@ -384,7 +368,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) { // Discard any past or too distant blocks if dist := int64(block.NumberU64()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x], distance %d", peer, block.NumberU64(), hash.Bytes()[:4], dist) - f.discardMeter.Mark(1) + discardMeter.Mark(1) return } // Schedule the block for future importing @@ -423,11 +407,11 @@ func (f *Fetcher) insert(peer string, block *types.Block) { switch err := f.validateBlock(block, parent); err { case nil: // All ok, quickly propagate to our peers - f.broadcastTimer.UpdateSince(block.ReceivedAt) + broadcastTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, true) case core.BlockFutureErr: - f.futureMeter.Mark(1) + futureMeter.Mark(1) // Weird future block, don't fail, but neither propagate default: @@ -442,7 +426,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) { return } // If import succeeded, broadcast the block - f.announceTimer.UpdateSince(block.ReceivedAt) + announceTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, false) // Invoke the testing hook if needed diff --git a/eth/fetcher/metrics.go b/eth/fetcher/metrics.go new file mode 100644 index 000000000..e46e3c0fb --- /dev/null +++ b/eth/fetcher/metrics.go @@ -0,0 +1,16 @@ +// Contains the metrics collected by the fetcher. + +package fetcher + +import ( + "github.com/ethereum/go-ethereum/metrics" +) + +var ( + announceMeter = metrics.NewMeter("eth/sync/RemoteAnnounces") + announceTimer = metrics.NewTimer("eth/sync/LocalAnnounces") + broadcastMeter = metrics.NewMeter("eth/sync/RemoteBroadcasts") + broadcastTimer = metrics.NewTimer("eth/sync/LocalBroadcasts") + discardMeter = metrics.NewMeter("eth/sync/DiscardedBlocks") + futureMeter = metrics.NewMeter("eth/sync/FutureBlocks") +) -- cgit v1.2.3