forked from phoenix2/phoenix
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit a971b36
Showing
26 changed files
with
4,830 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
*.pyc | ||
*.pyo | ||
*.py~ | ||
*.elf | ||
*.cfg | ||
*.log | ||
phoenix2/www | ||
MANIFEST | ||
build | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
recursive-include phoenix2 *.py *.cl | ||
recursive-include doc *.txt *.py | ||
include phoenix2/www/TODO | ||
include phoenix.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# THIS IS AN EXAMPLE KERNEL FOR PHOENIX 2. | ||
# THOUGH IT IS FULLY FUNCTIONAL, IT IS QUITE SLOW. IT IS INTENDED FOR | ||
# DEMONSTRATION PURPOSES ONLY. | ||
|
||
# Additionally, this doesn't demonstrate QueueReader, which is the preferred | ||
# way of making kernels that dispatch a separate thread to handle NonceRanges | ||
# (as this one does) | ||
|
||
import time | ||
from twisted.internet import reactor, defer | ||
|
||
# You should really look at the functions defined here. They are useful. | ||
from phoenix2.core.KernelInterface import KernelOption | ||
|
||
# This class needs to be defined in all Phoenix 2 kernels. The required | ||
# functions are __init__, start, and stop. Everything else is optional. | ||
class MiningKernel(object): | ||
# Here you can define options that the kernel will accept from the | ||
# configuration file. | ||
GREETING = KernelOption('greeting', str, default='', | ||
help='Defines what debug message should be ' | ||
'printed at kernel start-up time.') | ||
|
||
def __init__(self, interface): | ||
self.interface = interface | ||
self._stop = False | ||
|
||
# Here we can ask the interface for the Phoenix 2 device ID, which is a | ||
# lower-case (it is lower-cased by Phoenix even if caps are used in the | ||
# configuration file) string identifying a specific device on the | ||
# system. | ||
# We don't need this for much, given that this is a CPU miner, but | ||
# let's just show how to access it. | ||
if not self.interface.getDeviceID().startswith('cpu:'): | ||
self.interface.fatal('This kernel is only for CPUs!') | ||
return | ||
|
||
# Let's also print that configuration message that we set up before... | ||
self.interface.debug('Greeting: ' + self.GREETING) | ||
|
||
# We can also provide metadata on what the kernel is doing. | ||
self.interface.setMeta('cores', '1') | ||
|
||
@classmethod | ||
def autodetect(cls, callback): | ||
# This class method is used when Phoenix loads the kernel to autodetect | ||
# the devices that it supports. When this function runs, the kernel is | ||
# to look for all supported devices present on the system, and call | ||
# callback(devid) for each one. | ||
# It is also legal to store the callback and trigger the callback in | ||
# the event of hotplug. If this is the case, the kernel must also | ||
# define a class method called stopAutodetect() that disables hotplug | ||
# detection. | ||
# Also note that it is legal to call this function multiple times | ||
# without calling stopAutodetect in between. If this function is called | ||
# again, the kernel must redetect all devices present and send them all | ||
# through the callback again, even the ones it has already detected. | ||
|
||
# In this case, there is only one device this kernel supports: the CPU | ||
# (which we know is present) - the CPU is identified by devid cpu:0 by | ||
# default. The user can use cpu:1, etc, if he wishes to run several CPU | ||
# kernels in tandem (for some reason), but the canonical ID for | ||
# "the CPU" is always cpu:0. | ||
callback('cpu:0') | ||
|
||
@classmethod | ||
def analyzeDevice(cls, devid): | ||
# This class method is for analyzing how well a kernel will support a | ||
# specific device to help Phoenix automatically choose kernels. | ||
# It is to return a tuple: (suitability, config, ids) | ||
# Where 'suitability' is a number in the following table: | ||
# 0 - DO NOT USE THIS KERNEL | ||
# 1 - WILL WORK AS A FALLBACK | ||
# 2 - INTENDED USE FOR THIS CLASS OF HARDWARE | ||
# 3 - OPTIMIZED FOR THIS BRAND OF HARDWARE | ||
# 4 - OPTIMIZED FOR THIS SPECIFIC MODEL OF HARDWARE | ||
# 5 - OPTIMIZED FOR THIS HARDWARE'S CURRENT CONFIGURATION | ||
# (e.g. kernels that work well when clocks are low, etc) | ||
# And config is a dictionary of recommended configuration values, which | ||
# will get used unless the user explicitly disables autoconfiguration. | ||
# Finally, ids is the list of IDs that the device is known by, with the | ||
# "preferred" ID being the first one. | ||
|
||
if devid.startswith('cpu:'): | ||
return (1, {}, [devid]) | ||
else: | ||
return (0, {}, [devid]) | ||
|
||
def start(self): | ||
self._stop = False | ||
reactor.callInThread(self.mine) | ||
|
||
def stop(self): | ||
self._stop = True | ||
|
||
def _fetchRangeHelper(self, d): | ||
# This function is a workaround for Twisted's threading model. The | ||
# callFromThread function, which is necessary to invoke a function in | ||
# the main thread, does not come back with return values. So, this | ||
# function accepts a deferred, fetches some work, and fires the work | ||
# through the deferred. QueueReader deals with all of this internally. | ||
self.interface.fetchRange().chainDeferred(d) | ||
|
||
# inlineCallbacks is a Twisted thing, it means you can do "x = yield y" | ||
# where y is a Deferred, and it will pause your function until the Deferred | ||
# fires back with a value | ||
@defer.inlineCallbacks | ||
def mine(self): | ||
# This is rate-counting logic... | ||
nonceCounter = 0 | ||
nonceTime = time.time() | ||
|
||
while True: | ||
d = defer.Deferred() | ||
reactor.callFromThread(self._fetchRangeHelper, d) | ||
nr = yield d | ||
# Now we work on nr... | ||
# This is defined in WorkQueue.py | ||
for nonce in xrange(nr.base, nr.base+nr.size): | ||
# Here we simply have to test nonce. We can do this ourselves, | ||
# but the interface has a convenience function to do this for | ||
# us. (It doesn't communicate elsewhere with Phoenix and is | ||
# therefore safe to use without reactor.callFromThread) | ||
hash = self.interface.calculateHash(nr.unit, nonce) | ||
|
||
# There's also a convenience function for comparing the hash | ||
# against the target. | ||
if self.interface.checkTarget(hash, nr.unit.target): | ||
# It's good! Let's send it in... | ||
reactor.callFromThread(self.interface.foundNonce, nr.unit, | ||
nonce) | ||
|
||
# Count the nonce we just did, and report the rate, in | ||
# kilohashes, to the interface. | ||
nonceCounter += 1 | ||
if nonceCounter >= 0x100: | ||
now = time.time() | ||
dt = now - nonceTime | ||
reactor.callFromThread(self.interface.updateRate, | ||
int(nonceCounter/dt/1000)) | ||
nonceCounter = 0 | ||
nonceTime = now | ||
|
||
# Finally, this thread needs to die if the kernel has been | ||
# asked to stop... | ||
if self._stop: | ||
return |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
This is just a quick reference of all JSON-RPC calls available in the Phoenix 2 | ||
server: | ||
|
||
getstatus() # Get general status on the server: | ||
{'uptime': seconds, | ||
'connection': {'type': ('rpc'|'rpclp'|'mmp'), | ||
'connected': boolean, | ||
'url': 'url'} | ||
'results': {'accepted': 12345, | ||
'rejected': 12345} | ||
} | ||
|
||
|
||
getrawconfig() # Download the entire configuration file as a single string. | ||
setrawconfig(cfg) # Overwrite the configuration file with a string. | ||
|
||
listdevices() # Returns an array of devices in this format: | ||
{'id': minerID, | ||
'name': 'miner name', | ||
'status': ('running'|'suspended'|'disabled'), | ||
'rate': khash, | ||
'config': {'key1':'value1', 'key2':'value2'}, | ||
'meta': {'key1':'value1', 'key2':'value2'}, | ||
'uptime': seconds, | ||
'results': 24690 | ||
} | ||
|
||
getlogs(skip, limit) # Return logs, skipping 'skip' logs (if skip is negative, | ||
# it will skip all but the last abs(n) logs), | ||
# and limit result to 'limit' entries (or 0 for no limit) | ||
{'id': minerID, | ||
'timestamp': unix_time_seconds, | ||
'msg': 'Message as it appears in the console, everything but the [time] [id]', | ||
'type': ('result'|'fatal'|etc), | ||
# if type=result | ||
'details': {'accepted': boolean, | ||
'hash': 'hexadecimal_here'} | ||
# if type=fatal, error, etc | ||
'details': {'error': 'Error message as from the kernel'} | ||
... | ||
} | ||
|
||
setconfig(section, variable, value) # Alter a single configuration option. | ||
getconfig(section, variable) # Retrive a configuration value. | ||
|
||
redetect(terminate) # Re-run autodetection (useful after changing the | ||
# autodetect config variable) | ||
# 'terminate' specifies whether to also forget about | ||
# autodetected kernels that don't meet with the new | ||
# autodetect rules. | ||
# It defaults to 'false' if not provided. | ||
|
||
restart(minerID) # Restart a single miner. This also refreshes the | ||
# configuration for that miner. Will not work for disabled | ||
# kernels (you will need to use start(minerID) for this) | ||
restart() # When used with no minerID, or minerID=null, it does it for every | ||
# single running kernel. | ||
disable(minerID) # Shut down the kernel and mark it as disabled in the config. | ||
suspend(minerID) # Stop a miner temporarily. This is not saved in the config. | ||
# The miner will resume when Phoenix is restarted. | ||
suspend() # As with restart() - suspends every running kernel. | ||
start(minerID) # Resume a miner from suspend or disable. | ||
start() # Starts every suspended (but not disabled) kernel. | ||
|
||
shutdown() # Stop the running Phoenix process. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#!/usr/bin/env python | ||
|
||
from twisted.internet import reactor | ||
from phoenix2.core.PhoenixCore import PhoenixCore | ||
|
||
import sys, os | ||
|
||
def main(): | ||
if len(sys.argv) > 1: | ||
cfg = sys.argv[1] | ||
elif sys.platform == 'win32': | ||
# The Windows users get their own special treatment. The script creates | ||
# an empty configuration file for them if they don't specify one. | ||
cfg = os.path.join(os.path.dirname(sys.argv[0]), 'phoenix.cfg') | ||
if not os.path.isfile(cfg) or os.stat(cfg).st_size == 0: | ||
print('-'*79) | ||
print('It looks like this is your first time running Phoenix.') | ||
#print('Please go to http://localhost:7780 in a web browser to' | ||
# ' set it up.') | ||
print('Please edit your phoenix.cfg file') | ||
print('-'*79) | ||
open(cfg, 'a').close() | ||
else: | ||
print('Please specify a configuration file.') | ||
sys.exit() | ||
|
||
if not os.path.isfile(cfg): | ||
print('Error: %s does not exist.' % cfg) | ||
sys.exit() | ||
|
||
pc = PhoenixCore(cfg) | ||
pc.start() | ||
|
||
reactor.run() | ||
|
||
if __name__ == '__main__': | ||
main() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Copyright (C) 2011 by jedi95 <[email protected]> and | ||
# CFSworks <[email protected]> | ||
# | ||
# Permission is hereby granted, free of charge, to any person obtaining a copy | ||
# of this software and associated documentation files (the "Software"), to deal | ||
# in the Software without restriction, including without limitation the rights | ||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
# copies of the Software, and to permit persons to whom the Software is | ||
# furnished to do so, subject to the following conditions: | ||
# | ||
# The above copyright notice and this permission notice shall be included in | ||
# all copies or substantial portions of the Software. | ||
# | ||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
# THE SOFTWARE. | ||
|
||
import struct | ||
|
||
class AssignedWork(object): | ||
data = None | ||
mask = None | ||
target = None | ||
maxtime = None | ||
time = None | ||
identifier = None | ||
def setMaxTimeIncrement(self, n): | ||
self.time = n | ||
self.maxtime = struct.unpack('>I', self.data[68:72])[0] + n | ||
|
||
class ClientBase(object): | ||
callbacksActive = True | ||
|
||
def _deactivateCallbacks(self): | ||
"""Shut down the runCallback function. Typically used post-disconnect. | ||
""" | ||
self.callbacksActive = False | ||
|
||
def runCallback(self, callback, *args): | ||
"""Call the callback on the handler, if it's there, specifying args.""" | ||
|
||
if not self.callbacksActive: | ||
return | ||
|
||
func = getattr(self.handler, 'on' + callback.capitalize(), None) | ||
if callable(func): | ||
func(*args) |
Oops, something went wrong.