Skip to content

Commit

Permalink
add staking (#7)
Browse files Browse the repository at this point in the history
Adds support for all script types other that alt-sig types.

Adds new tinyhttp module in util, used in both dcrdata and stakepool.

Add VSP client and update interface to support ticket purchases. 
No solo voting and still needs revocation support.

Wallets directory for wallet-related modules

Improved wallet loading sequence.
  • Loading branch information
buck54321 authored Nov 26, 2019
1 parent dfadbd8 commit a7d871c
Show file tree
Hide file tree
Showing 30 changed files with 6,823 additions and 1,538 deletions.
74 changes: 29 additions & 45 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import sys
from PyQt5 import QtGui, QtCore, QtWidgets
from tinydecred import config
from tinydecred.wallet.wallet import Wallet
from tinydecred.util import helpers
from tinydecred.pydecred import constants as DCR
from tinydecred.pydecred.dcrdata import DcrdataBlockchain
from tinydecred.wallet import Wallet
from tinydecred.ui import screens, ui, qutilities as Q

# the directory of the tinydecred package
Expand Down Expand Up @@ -108,9 +108,11 @@ def __init__(self, qApp):
self.loadSettings()

# The initialized DcrdataBlockchain will not be connected, as that is a
# blocking operation. Connect will be called in a QThread in `initDCR`.
# blocking operation. It will be called when the wallet is open.
self.dcrdata = DcrdataBlockchain(os.path.join(self.netDirectory(), "dcr.db"), cfg.net, self.getNetSetting("dcrdata"), skipConnect=True)

self.registerSignal(ui.WALLET_CONNECTED, self.syncWallet)

# appWindow is the main application window. The TinyDialog class has
# methods for organizing a stack of Screen widgets.
self.appWindow = screens.TinyDialog(self)
Expand All @@ -127,35 +129,26 @@ def __init__(self, qApp):

self.sendScreen = screens.SendScreen(self)

self.confirmScreen = screens.ConfirmScreen(self)

self.sysTray.show()
self.appWindow.show()

# If there is a wallet file, prompt for a password to open the wallet.
# Otherwise, show the initialization screen.
if os.path.isfile(self.walletFilename()):
def openw(path, pw):
try:
w = Wallet.openFile(path, pw)
w.open(0, pw, self.dcrdata, self.blockchainSignals)
self.appWindow.pop(self.pwDialog)
return w
except Exception as e:
log.warning("exception encountered while attempting to open wallet: %s" % formatTraceback(e))
self.appWindow.showError("incorrect password")
def login(pw):
if pw is None or pw == "":
self.appWindow.showError("you must enter a password to continue")
else:
path = self.walletFilename()
self.waitThread(openw, self.finishOpen, path, pw)
self.waitThread(self.openWallet, None, path, pw)
self.getPassword(login)
else:
initScreen = screens.InitializationScreen(self)
initScreen.setFadeIn(True)
self.appWindow.stack(initScreen)

# Connect to dcrdata in a QThread.
self.makeThread(self.initDCR, self._setDCR)
def waiting(self):
"""
Stack the waiting screen.
Expand All @@ -178,18 +171,25 @@ def unwaiting(*cba, **cbk):
self.appWindow.pop(self.waitingScreen)
cb(*cba, **cbk)
self.makeThread(tryExecute, unwaiting, f, *a, **k)
def finishOpen(self, wallet):
def openWallet(self, path, pw):
"""
Callback for the initial wallet load. If the load failed, probably
because of a bad password, the provided wallet will be None.
Args:
wallet (Wallet): The newly opened Wallet instance.
"""
if wallet == None:
return
self.setWallet(wallet)
self.home()
try:
self.dcrdata.connect()
self.emitSignal(ui.BLOCKCHAIN_CONNECTED)
w = Wallet.openFile(path, pw)
w.open(0, pw, self.dcrdata, self.blockchainSignals)
self.appWindow.pop(self.pwDialog)
self.setWallet(w)
self.home()
except Exception as e:
log.warning("exception encountered while attempting to open wallet: %s" % formatTraceback(e))
self.appWindow.showError("incorrect password")
def getPassword(self, f, *args, **kwargs):
"""
Calls the provided function with a user-provided password string as its
Expand All @@ -209,7 +209,7 @@ def walletFilename(self):
return self.getNetSetting(currentWallet)
def sysTrayActivated(self, trigger):
"""
Qt Slot called when the user interacts with the system tray icon. Shows
Qt Slot called when the user interacts with the system tray icon. Shows
the window, creating an icon in the user's application panel that
persists until the appWindow is minimized.
"""
Expand Down Expand Up @@ -329,7 +329,7 @@ def signal_(self, s):
A Qt Slot used for routing signalRegistry signals.
Args:
s (tuple): A tuple of (func, signal args, user args, signal kwargs,
s (tuple): A tuple of (func, signal args, user args, signal kwargs,
user kwargs).
"""
cb, sigA, a, sigK, k = s
Expand All @@ -343,7 +343,7 @@ def setWallet(self, wallet):
"""
self.wallet = wallet
self.emitSignal(ui.BALANCE_SIGNAL, wallet.balance())
self.tryInitSync()
self.emitSignal(ui.WALLET_CONNECTED)
def withUnlockedWallet(self, f, cb, *a, **k):
"""
Run the provided function with the wallet open. This is the preferred
Expand Down Expand Up @@ -381,12 +381,17 @@ def step2(pw, a, k):
self.emitSignal(ui.DONE_SIGNAL)
return False
self.getPassword(step1, cb, a, k)
def tryInitSync(self):
def confirm(self, msg, cb):
"""
Call the callback function only if the user confirms the prompt.
"""
self.appWindow.stack(self.confirmScreen.withPurpose(msg, cb))
def syncWallet(self):
"""
If conditions are right, start syncing the wallet.
"""
wallet = self.wallet
if wallet and wallet.openAccount and self.dcrdata:
if wallet and wallet.openAccount:
wallet.lock()
self.emitSignal(ui.WORKING_SIGNAL)
self.makeThread(wallet.sync, self.doneSyncing)
Expand All @@ -407,27 +412,6 @@ def balanceSync(self, balance):
balance (Balance): The balance to pass to subscribed receivers.
"""
self.emitSignal(ui.BALANCE_SIGNAL, balance)
def initDCR(self):
"""
Connect to dcrdata.
Returns:
bool: True on success. On exception, returns None.
"""
try:
self.dcrdata.connect()
return True
except Exception as e:
log.error("unable to initialize dcrdata connection at %s: %s" % (self.dcrdata.baseURI, formatTraceback(e)))
return None
def _setDCR(self, res):
"""
Callback to receive return value from initDCR.
"""
if not res:
self.appWindow.showError("No dcrdata connection available.")
return
self.tryInitSync()
def getButton(self, size, text, tracked=True):
"""
Get a button of the requested size.
Expand Down
2 changes: 1 addition & 1 deletion config.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def save(self):
"""
Save the file.
"""
tinyjson.save(CONFIG_PATH, self.file)
tinyjson.save(CONFIG_PATH, self.file, indent=4, sort_keys=True)

tinyConfig = TinyConfig()

Expand Down
24 changes: 12 additions & 12 deletions crypto/bytearray.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,23 @@ def decodeBA(b, copy=False):

class ByteArray(object):
"""
ByteArray is a bytearray manager that also implements tinyjson marshalling.
It implements a subset of bytearray's bitwise operators and provides some
convenience decodings on the fly, so operations work with various types of
input. Since bytearrays are mutable, ByteArray can also zero the internal
ByteArray is a bytearray manager that also implements tinyjson marshalling.
It implements a subset of bytearray's bitwise operators and provides some
convenience decodings on the fly, so operations work with various types of
input. Since bytearrays are mutable, ByteArray can also zero the internal
value without relying on garbage collection. An
important difference between ByteArray and bytearray is
that an integer argument to ByteArray constructor will result in the
shortest possible byte representation of the integer, where for
bytearray an int argument results in a zero-valued bytearray of said
length. To get a zero-valued or zero-padded ByteArray of length n, use the
important difference between ByteArray and bytearray is
that an integer argument to ByteArray constructor will result in the
shortest possible byte representation of the integer, where for
bytearray an int argument results in a zero-valued bytearray of said
length. To get a zero-valued or zero-padded ByteArray of length n, use the
`length` keyword argument.
"""
def __init__(self, b=b'', copy=True, length=None):
"""
Set copy to False if you want to share the memory with another bytearray/ByteArray.
Set copy to False if you want to share the memory with another bytearray/ByteArray.
If the type of b is not bytearray or ByteArray, copy has no effect.
"""
if length:
Expand Down Expand Up @@ -94,7 +94,7 @@ def __and__(self, a):
b[bLen-i-1] &= a[aLen-i-1] if i < aLen else 0
return b
def __iand__(self, a):
a, aLen, b, bLen = self.decode(a)
a, aLen, b, bLen = self.decode(a)
for i in range(bLen):
b[bLen-i-1] &= a[aLen-i-1] if i < aLen else 0
return self
Expand Down Expand Up @@ -169,7 +169,7 @@ def pop(self, n):
return b

# register the ByteArray class with the json encoder/decoder.
tinyjson.register(ByteArray)
tinyjson.register(ByteArray, "ByteArray")

class TestByteArray(unittest.TestCase):
def test_operators(self):
Expand Down
Loading

0 comments on commit a7d871c

Please sign in to comment.