aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Godeps/Godeps.json4
-rw-r--r--Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go22
-rw-r--r--Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c127
-rw-r--r--cmd/geth/main.go2
-rw-r--r--core/block_processor.go2
-rw-r--r--eth/downloader/downloader.go69
-rw-r--r--miner/miner.go2
-rw-r--r--miner/worker.go19
8 files changed, 95 insertions, 152 deletions
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index ce78f487c..f0d16330f 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -17,8 +17,8 @@
},
{
"ImportPath": "github.com/ethereum/ethash",
- "Comment": "v23.1-204-g0401fdf",
- "Rev": "0401fdf56a3bc8679f9560e542c3d1cf83020efe"
+ "Comment": "v23.1-206-gf0e6321",
+ "Rev": "f0e63218b721dc2f696920a92d5de1f6364e9bf7"
},
{
"ImportPath": "github.com/howeyc/fsnotify",
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
index 5b94711c4..ce450d461 100644
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
+++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
@@ -18,6 +18,7 @@ import (
"path/filepath"
"runtime"
"sync"
+ "sync/atomic"
"time"
"unsafe"
@@ -235,7 +236,7 @@ type Full struct {
test bool // if set use a smaller DAG size
turbo bool
- hashRate int64
+ hashRate int32
mu sync.Mutex // protects dag
current *dag // current full DAG
@@ -265,6 +266,7 @@ func (pow *Full) Search(block pow.Block, stop <-chan struct{}) (nonce uint64, mi
i := int64(0)
starti := i
start := time.Now().UnixNano()
+ previousHashrate := int32(0)
nonce = uint64(r.Int63())
hash := hashToH256(block.HashNoNonce())
@@ -272,14 +274,20 @@ func (pow *Full) Search(block pow.Block, stop <-chan struct{}) (nonce uint64, mi
for {
select {
case <-stop:
- pow.hashRate = 0
+ atomic.AddInt32(&pow.hashRate, -previousHashrate)
return 0, nil
default:
i++
- elapsed := time.Now().UnixNano() - start
- hashes := ((float64(1e9) / float64(elapsed)) * float64(i-starti)) / 1000
- pow.hashRate = int64(hashes)
+ // we don't have to update hash rate on every nonce, so update after
+ // first nonce check and then after 2^X nonces
+ if i == 2 || ((i % (1 << 16)) == 0) {
+ elapsed := time.Now().UnixNano() - start
+ hashes := (float64(1e9) / float64(elapsed)) * float64(i-starti)
+ hashrateDiff := int32(hashes) - previousHashrate
+ previousHashrate = int32(hashes)
+ atomic.AddInt32(&pow.hashRate, hashrateDiff)
+ }
ret := C.ethash_full_compute(dag.ptr, hash, C.uint64_t(nonce))
result := h256ToHash(ret.result).Big()
@@ -287,6 +295,7 @@ func (pow *Full) Search(block pow.Block, stop <-chan struct{}) (nonce uint64, mi
// TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining
if ret.success && result.Cmp(target) <= 0 {
mixDigest = C.GoBytes(unsafe.Pointer(&ret.mix_hash), C.int(32))
+ atomic.AddInt32(&pow.hashRate, -previousHashrate)
return nonce, mixDigest
}
nonce += 1
@@ -299,8 +308,7 @@ func (pow *Full) Search(block pow.Block, stop <-chan struct{}) (nonce uint64, mi
}
func (pow *Full) GetHashrate() int64 {
- // TODO: this needs to use an atomic operation.
- return pow.hashRate
+ return int64(atomic.LoadInt32(&pow.hashRate))
}
func (pow *Full) Turbo(on bool) {
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c
index d77b9761b..c66e03c54 100644
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c
+++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <time.h>
#include "../libethash/ethash.h"
+#include "../libethash/internal.h"
#if PY_MAJOR_VERSION >= 3
#define PY_STRING_FORMAT "y#"
@@ -16,66 +17,20 @@
#define MIX_WORDS (ETHASH_MIX_BYTES/4)
static PyObject *
-get_cache_size(PyObject *self, PyObject *args) {
- unsigned long block_number;
- if (!PyArg_ParseTuple(args, "k", &block_number))
- return 0;
- if (block_number >= ETHASH_EPOCH_LENGTH * 2048) {
- char error_message[1024];
- sprintf(error_message, "Block number must be less than %i (was %lu)", ETHASH_EPOCH_LENGTH * 2048, block_number);
-
- PyErr_SetString(PyExc_ValueError, error_message);
- return 0;
- }
-
- return Py_BuildValue("i", ethash_get_cachesize(block_number));
-}
-
-static PyObject *
-get_full_size(PyObject *self, PyObject *args) {
- unsigned long block_number;
- if (!PyArg_ParseTuple(args, "k", &block_number))
- return 0;
- if (block_number >= ETHASH_EPOCH_LENGTH * 2048) {
- char error_message[1024];
- sprintf(error_message, "Block number must be less than %i (was %lu)", ETHASH_EPOCH_LENGTH * 2048, block_number);
-
- PyErr_SetString(PyExc_ValueError, error_message);
- return 0;
- }
-
- return Py_BuildValue("i", ethash_get_datasize(block_number));
-}
-
-
-static PyObject *
mkcache_bytes(PyObject *self, PyObject *args) {
- char *seed;
+ unsigned long block_number;
unsigned long cache_size;
- int seed_len;
-
- if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT, &cache_size, &seed, &seed_len))
- return 0;
- if (seed_len != 32) {
- char error_message[1024];
- sprintf(error_message, "Seed must be 32 bytes long (was %i)", seed_len);
-
- PyErr_SetString(PyExc_ValueError, error_message);
+ if (!PyArg_ParseTuple(args, "k", &block_number))
return 0;
- }
- ethash_params params;
- params.cache_size = (size_t) cache_size;
- ethash_cache cache;
- cache.mem = malloc(cache_size);
- ethash_mkcache(&cache, &params, (ethash_h256_t *) seed);
- PyObject * val = Py_BuildValue(PY_STRING_FORMAT, cache.mem, cache_size);
- free(cache.mem);
+ ethash_light_t L = ethash_light_new(block_number);
+ PyObject * val = Py_BuildValue(PY_STRING_FORMAT, L->cache, L->cache_size);
+ free(L->cache);
return val;
}
-
+/*
static PyObject *
calc_dataset_bytes(PyObject *self, PyObject *args) {
char *cache_bytes;
@@ -109,49 +64,38 @@ calc_dataset_bytes(PyObject *self, PyObject *args) {
PyObject * val = Py_BuildValue(PY_STRING_FORMAT, (char *) mem, full_size);
free(mem);
return val;
-}
+}*/
// hashimoto_light(full_size, cache, header, nonce)
static PyObject *
hashimoto_light(PyObject *self, PyObject *args) {
char *cache_bytes;
char *header;
- unsigned long full_size;
+ unsigned long block_number;
unsigned long long nonce;
int cache_size, header_size;
- if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT PY_STRING_FORMAT "K", &full_size, &cache_bytes, &cache_size, &header, &header_size, &nonce))
- return 0;
- if (full_size % MIX_WORDS != 0) {
- char error_message[1024];
- sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %lu)", MIX_WORDS, full_size);
- PyErr_SetString(PyExc_ValueError, error_message);
- return 0;
- }
- if (cache_size % ETHASH_HASH_BYTES != 0) {
- char error_message[1024];
- sprintf(error_message, "The size of the cache must be a multiple of %i bytes (was %i)", ETHASH_HASH_BYTES, cache_size);
- PyErr_SetString(PyExc_ValueError, error_message);
+ if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT PY_STRING_FORMAT "K", &block_number, &cache_bytes, &cache_size, &header, &header_size, &nonce))
return 0;
- }
if (header_size != 32) {
char error_message[1024];
sprintf(error_message, "Seed must be 32 bytes long (was %i)", header_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
-
- ethash_return_value out;
- ethash_params params;
- params.cache_size = (size_t) cache_size;
- params.full_size = (size_t) full_size;
- ethash_cache cache;
- cache.mem = (void *) cache_bytes;
- ethash_light(&out, &cache, &params, (ethash_h256_t *) header, nonce);
+ struct ethash_light *s;
+ s = calloc(sizeof(*s), 1);
+ s->cache = cache_bytes;
+ s->cache_size = cache_size;
+ s->block_number = block_number;
+ struct ethash_h256 *h;
+ h = calloc(sizeof(*h), 1);
+ for (int i = 0; i < 32; i++) h->b[i] = header[i];
+ struct ethash_return_value out = ethash_light_compute(s, *h, nonce);
return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "," PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "}",
"mix digest", &out.mix_hash, 32,
"result", &out.result, 32);
}
-
+/*
// hashimoto_full(dataset, header, nonce)
static PyObject *
hashimoto_full(PyObject *self, PyObject *args) {
@@ -236,6 +180,7 @@ mine(PyObject *self, PyObject *args) {
"result", &out.result, 32,
"nonce", nonce);
}
+*/
//get_seedhash(block_number)
static PyObject *
@@ -256,40 +201,24 @@ get_seedhash(PyObject *self, PyObject *args) {
static PyMethodDef PyethashMethods[] =
{
- {"get_cache_size", get_cache_size, METH_VARARGS,
- "get_cache_size(block_number)\n\n"
- "Get the cache size for a given block number\n"
- "\nExample:\n"
- ">>> get_cache_size(0)\n"
- "1048384"},
- {"get_full_size", get_full_size, METH_VARARGS,
- "get_full_size(block_number)\n\n"
- "Get the full size for a given block number\n"
- "\nExample:\n"
- ">>> get_full_size(0)\n"
- "1073739904"
- },
{"get_seedhash", get_seedhash, METH_VARARGS,
"get_seedhash(block_number)\n\n"
"Gets the seedhash for a block."},
{"mkcache_bytes", mkcache_bytes, METH_VARARGS,
- "mkcache_bytes(size, header)\n\n"
- "Makes a byte array for the cache for given cache size and seed hash\n"
- "\nExample:\n"
- ">>> pyethash.mkcache_bytes( 1024, \"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\").encode('hex')"
- "\"2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b\""},
- {"calc_dataset_bytes", calc_dataset_bytes, METH_VARARGS,
+ "mkcache_bytes(block_number)\n\n"
+ "Makes a byte array for the cache for given block number\n"},
+ /*{"calc_dataset_bytes", calc_dataset_bytes, METH_VARARGS,
"calc_dataset_bytes(full_size, cache_bytes)\n\n"
- "Makes a byte array for the dataset for a given size given cache bytes"},
+ "Makes a byte array for the dataset for a given size given cache bytes"},*/
{"hashimoto_light", hashimoto_light, METH_VARARGS,
- "hashimoto_light(full_size, cache_bytes, header, nonce)\n\n"
+ "hashimoto_light(block_number, cache_bytes, header, nonce)\n\n"
"Runs the hashimoto hashing function just using cache bytes. Takes an int (full_size), byte array (cache_bytes), another byte array (header), and an int (nonce). Returns an object containing the mix digest, and hash result."},
- {"hashimoto_full", hashimoto_full, METH_VARARGS,
+ /*{"hashimoto_full", hashimoto_full, METH_VARARGS,
"hashimoto_full(dataset_bytes, header, nonce)\n\n"
"Runs the hashimoto hashing function using the dataset bytes. Useful for testing. Returns an object containing the mix digest (byte array), and hash result (another byte array)."},
{"mine", mine, METH_VARARGS,
"mine(dataset_bytes, header, difficulty_bytes)\n\n"
- "Mine for an adequate header. Returns an object containing the mix digest (byte array), hash result (another byte array) and nonce (an int)."},
+ "Mine for an adequate header. Returns an object containing the mix digest (byte array), hash result (another byte array) and nonce (an int)."},*/
{NULL, NULL, 0, NULL}
};
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index b4d7feed1..725f04efe 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -563,7 +563,7 @@ func upgradeDb(ctx *cli.Context) {
bcVersion = core.BlockChainVersion
}
- filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("2006-01-02_15:04:05"))
+ filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405"))
exportFile := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename)
err = utils.ExportChain(ethereum.ChainManager(), exportFile)
diff --git a/core/block_processor.go b/core/block_processor.go
index af47069ad..059c442cc 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -197,7 +197,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
// There can be at most two uncles
if len(block.Uncles()) > 2 {
- return nil, ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles()))
+ return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
}
receipts, err := sm.TransitionState(state, parent, block, false)
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index 55455262a..85de78ebf 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -65,12 +65,15 @@ type Downloader struct {
// Status
synchronising int32
+ notified int32
// Channels
newPeerCh chan *peer
hashCh chan hashPack
blockCh chan blockPack
- cancelCh chan struct{}
+
+ cancelCh chan struct{} // Channel to cancel mid-flight syncs
+ cancelLock sync.RWMutex // Lock to protect the cancel channel in delivers
}
func New(hasBlock hashCheckFn, getBlock getBlockFn) *Downloader {
@@ -83,7 +86,6 @@ func New(hasBlock hashCheckFn, getBlock getBlockFn) *Downloader {
hashCh: make(chan hashPack, 1),
blockCh: make(chan blockPack, 1),
}
-
return downloader
}
@@ -123,8 +125,14 @@ func (d *Downloader) Synchronise(id string, hash common.Hash) error {
}
defer atomic.StoreInt32(&d.synchronising, 0)
- // Create cancel channel for aborting midflight
+ // Post a user notification of the sync (only once per session)
+ if atomic.CompareAndSwapInt32(&d.notified, 0, 1) {
+ glog.V(logger.Info).Infoln("Block synchronisation started")
+ }
+ // Create cancel channel for aborting mid-flight
+ d.cancelLock.Lock()
d.cancelCh = make(chan struct{})
+ d.cancelLock.Unlock()
// Abort if the queue still contains some leftover data
if _, cached := d.queue.Size(); cached > 0 && d.queue.GetHeadBlock() != nil {
@@ -183,32 +191,15 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash) (err error) {
// Cancel cancels all of the operations and resets the queue. It returns true
// if the cancel operation was completed.
func (d *Downloader) Cancel() bool {
- hs, bs := d.queue.Size()
// If we're not syncing just return.
+ hs, bs := d.queue.Size()
if atomic.LoadInt32(&d.synchronising) == 0 && hs == 0 && bs == 0 {
return false
}
-
+ // Close the current cancel channel
+ d.cancelLock.RLock()
close(d.cancelCh)
-
- // clean up
-hashDone:
- for {
- select {
- case <-d.hashCh:
- default:
- break hashDone
- }
- }
-
-blockDone:
- for {
- select {
- case <-d.blockCh:
- default:
- break blockDone
- }
- }
+ d.cancelLock.RUnlock()
// reset the queue
d.queue.Reset()
@@ -421,9 +412,18 @@ func (d *Downloader) DeliverBlocks(id string, blocks []*types.Block) error {
if atomic.LoadInt32(&d.synchronising) == 0 {
return errNoSyncActive
}
- d.blockCh <- blockPack{id, blocks}
+ // Deliver or abort if the sync is canceled while queuing
+ d.cancelLock.RLock()
+ cancel := d.cancelCh
+ d.cancelLock.RUnlock()
- return nil
+ select {
+ case d.blockCh <- blockPack{id, blocks}:
+ return nil
+
+ case <-cancel:
+ return errNoSyncActive
+ }
}
// DeliverHashes injects a new batch of hashes received from a remote node into
@@ -434,11 +434,16 @@ func (d *Downloader) DeliverHashes(id string, hashes []common.Hash) error {
if atomic.LoadInt32(&d.synchronising) == 0 {
return errNoSyncActive
}
- if glog.V(logger.Debug) && len(hashes) != 0 {
- from, to := hashes[0], hashes[len(hashes)-1]
- glog.V(logger.Debug).Infof("adding %d (T=%d) hashes [ %x / %x ] from: %s\n", len(hashes), d.queue.Pending(), from[:4], to[:4], id)
- }
- d.hashCh <- hashPack{id, hashes}
+ // Deliver or abort if the sync is canceled while queuing
+ d.cancelLock.RLock()
+ cancel := d.cancelCh
+ d.cancelLock.RUnlock()
- return nil
+ select {
+ case d.hashCh <- hashPack{id, hashes}:
+ return nil
+
+ case <-cancel:
+ return errNoSyncActive
+ }
}
diff --git a/miner/miner.go b/miner/miner.go
index 09342e250..8143fcef7 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -70,7 +70,7 @@ func (self *Miner) Register(agent Agent) {
}
func (self *Miner) HashRate() int64 {
- return self.worker.HashRate()
+ return self.pow.GetHashrate()
}
func (self *Miner) SetExtra(extra []byte) {
diff --git a/miner/worker.go b/miner/worker.go
index f737be507..d5f9dd8c5 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -45,7 +45,8 @@ type environment struct {
state *state.StateDB // apply state changes here
coinbase *state.StateObject // the miner's account
block *types.Block // the new block
- family *set.Set // family set (used for checking uncles)
+ ancestors *set.Set // ancestor set (used for checking uncle parent validity)
+ family *set.Set // family set (used for checking uncle invalidity)
uncles *set.Set // uncle set
remove *set.Set // tx which will be removed
tcount int // tx count in cycle
@@ -62,6 +63,7 @@ func env(block *types.Block, eth core.Backend) *environment {
totalUsedGas: new(big.Int),
state: state,
block: block,
+ ancestors: set.New(),
family: set.New(),
uncles: set.New(),
coinbase: state.GetOrNewStateObject(block.Coinbase()),
@@ -173,7 +175,6 @@ func (self *worker) stop() {
func (self *worker) register(agent Agent) {
self.mu.Lock()
defer self.mu.Unlock()
-
self.agents = append(self.agents, agent)
agent.SetReturnCh(self.recv)
}
@@ -265,7 +266,11 @@ func (self *worker) makeCurrent() {
current := env(block, self.eth)
for _, ancestor := range self.chain.GetAncestors(block, 7) {
+ for _, uncle := range ancestor.Uncles() {
+ current.family.Add(uncle.Hash())
+ }
current.family.Add(ancestor.Hash())
+ current.ancestors.Add(ancestor.Hash())
}
accounts, _ := self.eth.AccountManager().Accounts()
// Keep track of transactions which return errors so they can be removed
@@ -363,7 +368,7 @@ func (self *worker) commitUncle(uncle *types.Header) error {
}
self.current.uncles.Add(uncle.Hash())
- if !self.current.family.Has(uncle.ParentHash) {
+ if !self.current.ancestors.Has(uncle.ParentHash) {
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
}
@@ -453,13 +458,9 @@ func (self *worker) commitTransaction(tx *types.Transaction) error {
return nil
}
+// TODO: remove or use
func (self *worker) HashRate() int64 {
- var tot int64
- for _, agent := range self.agents {
- tot += agent.GetHashRate()
- }
-
- return tot
+ return 0
}
// gasprice calculates a reduced gas price based on the pct