aboutsummaryrefslogtreecommitdiffstats
path: root/eth
diff options
context:
space:
mode:
Diffstat (limited to 'eth')
-rw-r--r--eth/api.go109
-rw-r--r--eth/backend.go4
-rw-r--r--eth/downloader/api.go7
-rw-r--r--eth/downloader/downloader.go15
-rw-r--r--eth/downloader/downloader_test.go32
-rw-r--r--eth/downloader/queue.go5
6 files changed, 119 insertions, 53 deletions
diff --git a/eth/api.go b/eth/api.go
index 526590589..37b033dc6 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -47,10 +47,7 @@ import (
"gopkg.in/fatih/set.v0"
)
-const (
- defaultGasPrice = uint64(10000000000000)
- defaultGas = uint64(90000)
-)
+const defaultGas = uint64(90000)
// blockByNumber is a commonly used helper function which retrieves and returns
// the block for the given block number, capable of handling two special blocks:
@@ -152,21 +149,79 @@ func (s *PublicEthereumAPI) Hashrate() *rpc.HexNumber {
}
// Syncing returns false in case the node is currently not synching with the network. It can be up to date or has not
-// yet received the latest block headers from its pears. In case it is synchronizing an object with 3 properties is
-// returned:
+// yet received the latest block headers from its pears. In case it is synchronizing:
// - startingBlock: block number this node started to synchronise from
-// - currentBlock: block number this node is currently importing
-// - highestBlock: block number of the highest block header this node has received from peers
+// - currentBlock: block number this node is currently importing
+// - highestBlock: block number of the highest block header this node has received from peers
+// - pulledStates: number of state entries processed until now
+// - knownStates: number of known state entries that still need to be pulled
func (s *PublicEthereumAPI) Syncing() (interface{}, error) {
- origin, current, height := s.e.Downloader().Progress()
- if current < height {
- return map[string]interface{}{
- "startingBlock": rpc.NewHexNumber(origin),
- "currentBlock": rpc.NewHexNumber(current),
- "highestBlock": rpc.NewHexNumber(height),
- }, nil
+ origin, current, height, pulled, known := s.e.Downloader().Progress()
+
+ // Return not syncing if the synchronisation already completed
+ if current >= height {
+ return false, nil
+ }
+ // Otherwise gather the block sync stats
+ return map[string]interface{}{
+ "startingBlock": rpc.NewHexNumber(origin),
+ "currentBlock": rpc.NewHexNumber(current),
+ "highestBlock": rpc.NewHexNumber(height),
+ "pulledStates": rpc.NewHexNumber(pulled),
+ "knownStates": rpc.NewHexNumber(known),
+ }, nil
+}
+
+// PublicMinerAPI provides an API to control the miner.
+// It offers only methods that operate on data that pose no security risk when it is publicly accessible.
+type PublicMinerAPI struct {
+ e *Ethereum
+ agent *miner.RemoteAgent
+}
+
+// NewPublicMinerAPI create a new PublicMinerAPI instance.
+func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI {
+ agent := miner.NewRemoteAgent()
+ e.Miner().Register(agent)
+
+ return &PublicMinerAPI{e, agent}
+}
+
+// Mining returns an indication if this node is currently mining.
+func (s *PublicMinerAPI) Mining() bool {
+ return s.e.IsMining()
+}
+
+// SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was
+// accepted. Note, this is not an indication if the provided work was valid!
+func (s *PublicMinerAPI) SubmitWork(nonce rpc.HexNumber, solution, digest common.Hash) bool {
+ return s.agent.SubmitWork(nonce.Uint64(), digest, solution)
+}
+
+// GetWork returns a work package for external miner. The work package consists of 3 strings
+// result[0], 32 bytes hex encoded current block header pow-hash
+// result[1], 32 bytes hex encoded seed hash used for DAG
+// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
+func (s *PublicMinerAPI) GetWork() ([]string, error) {
+ if !s.e.IsMining() {
+ if err := s.e.StartMining(0, ""); err != nil {
+ return nil, err
+ }
}
- return false, nil
+ if work, err := s.agent.GetWork(); err == nil {
+ return work[:], nil
+ } else {
+ glog.Infof("%v\n", err)
+ }
+ return nil, fmt.Errorf("mining not ready")
+}
+
+// SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined
+// hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which
+// must be unique between nodes.
+func (s *PublicMinerAPI) SubmitHashrate(hashrate rpc.HexNumber, id common.Hash) bool {
+ s.agent.SubmitHashrate(id, hashrate.Uint64())
+ return true
}
// PrivateMinerAPI provides private RPC methods to control the miner.
@@ -762,6 +817,7 @@ func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, err
type PublicTransactionPoolAPI struct {
eventMux *event.TypeMux
chainDb ethdb.Database
+ gpo *GasPriceOracle
bc *core.BlockChain
miner *miner.Miner
am *accounts.Manager
@@ -770,14 +826,15 @@ type PublicTransactionPoolAPI struct {
}
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
-func NewPublicTransactionPoolAPI(txPool *core.TxPool, m *miner.Miner, chainDb ethdb.Database, eventMux *event.TypeMux, bc *core.BlockChain, am *accounts.Manager) *PublicTransactionPoolAPI {
+func NewPublicTransactionPoolAPI(e *Ethereum) *PublicTransactionPoolAPI {
return &PublicTransactionPoolAPI{
- eventMux: eventMux,
- chainDb: chainDb,
- bc: bc,
- am: am,
- txPool: txPool,
- miner: m,
+ eventMux: e.EventMux(),
+ gpo: NewGasPriceOracle(e),
+ chainDb: e.ChainDb(),
+ bc: e.BlockChain(),
+ am: e.AccountManager(),
+ txPool: e.TxPool(),
+ miner: e.Miner(),
}
}
@@ -970,7 +1027,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(args SendTxArgs) (common.Hash
args.Gas = rpc.NewHexNumber(defaultGas)
}
if args.GasPrice == nil {
- args.GasPrice = rpc.NewHexNumber(defaultGasPrice)
+ args.GasPrice = rpc.NewHexNumber(s.gpo.SuggestPrice())
}
if args.Value == nil {
args.Value = rpc.NewHexNumber(0)
@@ -1111,7 +1168,7 @@ func (tx *Tx) UnmarshalJSON(b []byte) (err error) {
tx.GasLimit = rpc.NewHexNumber(0)
}
if tx.GasPrice == nil {
- tx.GasPrice = rpc.NewHexNumber(defaultGasPrice)
+ tx.GasPrice = rpc.NewHexNumber(int64(50000000000))
}
if contractCreation {
@@ -1154,7 +1211,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(args *SignTransactionArgs) (*
args.Gas = rpc.NewHexNumber(defaultGas)
}
if args.GasPrice == nil {
- args.GasPrice = rpc.NewHexNumber(defaultGasPrice)
+ args.GasPrice = rpc.NewHexNumber(s.gpo.SuggestPrice())
}
if args.Value == nil {
args.Value = rpc.NewHexNumber(0)
diff --git a/eth/backend.go b/eth/backend.go
index 352522f61..2f0bc3ee5 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -269,12 +269,12 @@ func (s *Ethereum) APIs() []rpc.API {
}, {
Namespace: "eth",
Version: "1.0",
- Service: NewPublicTransactionPoolAPI(s.TxPool(), s.Miner(), s.ChainDb(), s.EventMux(), s.BlockChain(), s.AccountManager()),
+ Service: NewPublicTransactionPoolAPI(s),
Public: true,
}, {
Namespace: "eth",
Version: "1.0",
- Service: miner.NewPublicMinerAPI(s.Miner()),
+ Service: NewPublicMinerAPI(s),
Public: true,
}, {
Namespace: "eth",
diff --git a/eth/downloader/api.go b/eth/downloader/api.go
index cc79e669f..6df911fee 100644
--- a/eth/downloader/api.go
+++ b/eth/downloader/api.go
@@ -36,6 +36,8 @@ type Progress struct {
Origin uint64 `json:"startingBlock"`
Current uint64 `json:"currentBlock"`
Height uint64 `json:"highestBlock"`
+ Pulled uint64 `json:"pulledStates"`
+ Known uint64 `json:"knownStates"`
}
// SyncingResult provides information about the current synchronisation status for this node.
@@ -44,7 +46,7 @@ type SyncingResult struct {
Status Progress `json:"status"`
}
-// Syncing provides information when this nodes starts synchronising with the Ethereumn network and when it's finished.
+// Syncing provides information when this nodes starts synchronising with the Ethereum network and when it's finished.
func (s *PublicDownloaderAPI) Syncing() (rpc.Subscription, error) {
sub := s.d.mux.Subscribe(StartEvent{}, DoneEvent{}, FailedEvent{})
@@ -52,13 +54,12 @@ func (s *PublicDownloaderAPI) Syncing() (rpc.Subscription, error) {
switch event.(type) {
case StartEvent:
result := &SyncingResult{Syncing: true}
- result.Status.Origin, result.Status.Current, result.Status.Height = s.d.Progress()
+ result.Status.Origin, result.Status.Current, result.Status.Height, result.Status.Pulled, result.Status.Known = s.d.Progress()
return result
case DoneEvent, FailedEvent:
return false
}
return nil
}
-
return rpc.NewSubscriptionWithOutputFormat(sub, output), nil
}
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index 163994730..6dad6a2cd 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -59,7 +59,6 @@ var (
maxQueuedHashes = 256 * 1024 // [eth/61] Maximum number of hashes to queue for import (DOS protection)
maxQueuedHeaders = 256 * 1024 // [eth/62] Maximum number of headers to queue for import (DOS protection)
- maxQueuedStates = 256 * 1024 // [eth/63] Maximum number of state requests to queue (DOS protection)
maxResultsProcess = 256 // Number of download results to import at once into the chain
fsHeaderCheckFrequency = 100 // Verification frequency of the downloaded headers during fast sync
@@ -197,7 +196,15 @@ func New(stateDb ethdb.Database, mux *event.TypeMux, hasHeader headerCheckFn, ha
// Progress retrieves the synchronisation boundaries, specifically the origin
// block where synchronisation started at (may have failed/suspended); the block
// or header sync is currently at; and the latest known block which the sync targets.
-func (d *Downloader) Progress() (uint64, uint64, uint64) {
+//
+// In addition, during the state download phase of fast synchonisation the number
+// of processed and the total number of known states are also returned. Otherwise
+// these are zero.
+func (d *Downloader) Progress() (uint64, uint64, uint64, uint64, uint64) {
+ // Fetch the pending state count outside of the lock to prevent unforeseen deadlocks
+ pendingStates := uint64(d.queue.PendingNodeData())
+
+ // Lock the current stats and return the progress
d.syncStatsLock.RLock()
defer d.syncStatsLock.RUnlock()
@@ -210,7 +217,7 @@ func (d *Downloader) Progress() (uint64, uint64, uint64) {
case LightSync:
current = d.headHeader().Number.Uint64()
}
- return d.syncStatsChainOrigin, current, d.syncStatsChainHeight
+ return d.syncStatsChainOrigin, current, d.syncStatsChainHeight, d.syncStatsStateDone, d.syncStatsStateDone + pendingStates
}
// Synchronising returns whether the downloader is currently retrieving blocks.
@@ -297,7 +304,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode
default:
}
}
- // Reset and ephemeral sync statistics
+ // Reset any ephemeral sync statistics
d.syncStatsLock.Lock()
d.syncStatsStateTotal = 0
d.syncStatsStateDone = 0
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index 418243b20..993190c38 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -1301,7 +1301,7 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) {
<-progress
}
// Retrieve the sync progress and ensure they are zero (pristine sync)
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0)
}
// Synchronise half the blocks and check initial progress
@@ -1316,7 +1316,7 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks/2+1) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks/2+1) {
t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, targetBlocks/2+1)
}
progress <- struct{}{}
@@ -1333,14 +1333,14 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks/2+1) || latest != uint64(targetBlocks) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks/2+1) || latest != uint64(targetBlocks) {
t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, targetBlocks/2+1, targetBlocks/2+1, targetBlocks)
}
progress <- struct{}{}
pending.Wait()
// Check final progress after successful sync
- if origin, current, latest := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) {
t.Fatalf("Final progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, targetBlocks/2+1, targetBlocks, targetBlocks)
}
}
@@ -1373,7 +1373,7 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
<-progress
}
// Retrieve the sync progress and ensure they are zero (pristine sync)
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0)
}
// Synchronise with one of the forks and check progress
@@ -1388,7 +1388,7 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(len(hashesA)-1) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(len(hashesA)-1) {
t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, len(hashesA)-1)
}
progress <- struct{}{}
@@ -1408,14 +1408,14 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesA)-1) || latest != uint64(len(hashesB)-1) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesA)-1) || latest != uint64(len(hashesB)-1) {
t.Fatalf("Forking progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, common, len(hashesA)-1, len(hashesB)-1)
}
progress <- struct{}{}
pending.Wait()
// Check final progress after successful sync
- if origin, current, latest := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesB)-1) || latest != uint64(len(hashesB)-1) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesB)-1) || latest != uint64(len(hashesB)-1) {
t.Fatalf("Final progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, common, len(hashesB)-1, len(hashesB)-1)
}
}
@@ -1448,7 +1448,7 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
<-progress
}
// Retrieve the sync progress and ensure they are zero (pristine sync)
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0)
}
// Attempt a full sync with a faulty peer
@@ -1468,7 +1468,7 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks) {
t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, targetBlocks)
}
progress <- struct{}{}
@@ -1485,14 +1485,14 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks/2) || latest != uint64(targetBlocks) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks/2) || latest != uint64(targetBlocks) {
t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/0-%v/%v", origin, current, latest, 0, targetBlocks/2, targetBlocks)
}
progress <- struct{}{}
pending.Wait()
// Check final progress after successful sync
- if origin, current, latest := tester.downloader.Progress(); origin > uint64(targetBlocks/2) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin > uint64(targetBlocks/2) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) {
t.Fatalf("Final progress mismatch: have %v/%v/%v, want 0-%v/%v/%v", origin, current, latest, targetBlocks/2, targetBlocks, targetBlocks)
}
}
@@ -1524,7 +1524,7 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
<-progress
}
// Retrieve the sync progress and ensure they are zero (pristine sync)
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 {
t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0)
}
// Create and sync with an attacker that promises a higher chain than available
@@ -1545,7 +1545,7 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks+3) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks+3) {
t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, targetBlocks+3)
}
progress <- struct{}{}
@@ -1562,14 +1562,14 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
}
}()
<-starting
- if origin, current, latest := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks) || latest != uint64(targetBlocks) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks) || latest != uint64(targetBlocks) {
t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/0-%v/%v", origin, current, latest, 0, targetBlocks, targetBlocks)
}
progress <- struct{}{}
pending.Wait()
// Check final progress after successful sync
- if origin, current, latest := tester.downloader.Progress(); origin > uint64(targetBlocks) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) {
+ if origin, current, latest, _, _ := tester.downloader.Progress(); origin > uint64(targetBlocks) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) {
t.Fatalf("Final progress mismatch: have %v/%v/%v, want 0-%v/%v/%v", origin, current, latest, targetBlocks, targetBlocks, targetBlocks)
}
}
diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go
index 1e55560db..9d0f2914d 100644
--- a/eth/downloader/queue.go
+++ b/eth/downloader/queue.go
@@ -39,7 +39,8 @@ import (
)
var (
- blockCacheLimit = 1024 // Maximum number of blocks to cache before throttling the download
+ blockCacheLimit = 1024 // Maximum number of blocks to cache before throttling the download
+ maxInFlightStates = 4096 // Maximum number of state downloads to allow concurrently
)
var (
@@ -464,7 +465,7 @@ func (q *queue) ReserveNodeData(p *peer, count int) *fetchRequest {
q.lock.Lock()
defer q.lock.Unlock()
- return q.reserveHashes(p, count, q.stateTaskQueue, generator, q.statePendPool, count)
+ return q.reserveHashes(p, count, q.stateTaskQueue, generator, q.statePendPool, maxInFlightStates)
}
// reserveHashes reserves a set of hashes for the given peer, skipping previously