Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: move code from simple.py to wallet.py, add tests #142

Merged
merged 2 commits into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 0 additions & 104 deletions decred/decred/wallet/simple.py

This file was deleted.

106 changes: 101 additions & 5 deletions decred/decred/wallet/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
See LICENSE for details
"""

from pathlib import Path

from decred import DecredError
from decred.crypto import crypto, mnemonic, rando
from decred.util import chains, encode, helpers
from decred.util.database import KeyValueDatabase
from decred.dcr import nets
from decred.dcr.dcrdata import DcrdataBlockchain
from decred.util import chains, database, encode, helpers
from decred.util.helpers import mkdir

from . import accounts

Expand Down Expand Up @@ -40,7 +44,7 @@ def __init__(self, path):
Args:
path (str): The path to the wallet database.
"""
self.db = KeyValueDatabase(path)
self.db = database.KeyValueDatabase(path)
self.masterDB = self.db.child("master", blobber=encode.ByteArray)
self.coinDB = self.db.child(
"accts", datatypes=("INTEGER", "BLOB"), blobber=accounts.AccountManager
Expand Down Expand Up @@ -106,7 +110,7 @@ def createFromMnemonic(words, path, password, netParams):
Args:
words (list(str)): Mnemonic seed. Assumed to be PGP words.
path (str): Filepath to store wallet.
password (str): User password. Passed to Wallet.create.
password (str): User password. Passed to Wallet.initialize.

Returns:
Wallet: A wallet initialized from the seed parsed from `words`.
Expand All @@ -116,7 +120,7 @@ def createFromMnemonic(words, path, password, netParams):
userSeed = decoded[:-1]
cs = crypto.sha256ChecksumByte(userSeed.b)
if cs != cksum:
raise Exception("bad checksum %r != %r" % (cs, cksum))
raise DecredError("bad checksum %r != %r" % (cs, cksum))
wallet = Wallet(path)
wallet.initialize(userSeed.b, password.encode(), netParams)
userSeed.zero()
Expand Down Expand Up @@ -146,3 +150,95 @@ def accountManager(self, coinType, signals):
acctMgr.load(acctDB, signals)
self.mgrCache[coinType] = acctMgr
return acctMgr


# SimpleWallet code.


class DefaultSignals:
"""DefaultSignals prints the balance to stdout."""

@staticmethod
def balance(b):
print(repr(b))


def paths(base, network):
"""
Get the paths for the network directory, the wallet database file, and the
blockchain database file.
"""
netDir = Path(base) / network
dbPath = netDir / "wallet.db"
dcrPath = netDir / "dcr.db"
return netDir, dbPath, dcrPath


DCRDATA_PATHS = {
"mainnet": "https://explorer.dcrdata.org/",
"testnet3": "https://testnet.dcrdata.org/",
"simnet": "http://localhost:17779",
}


class SimpleWallet(Wallet):
"""
SimpleWallet is a single-account Decred wallet.
"""

def __init__(self, walletDir, pw, network, signals=None, allowCreate=False):
"""
Args:
dir (str): A directory for wallet database files.
pw (str): The user password.
network (str): The network name.
signals (Signals): A signal processor.
"""
signals = signals if signals else DefaultSignals
netParams = nets.parse(network)
netDir, dbPath, dcrPath = paths(walletDir, netParams.Name)
if not Path(netDir).exists():
mkdir(netDir)
dcrdataDB = database.KeyValueDatabase(dcrPath)
# The initialized DcrdataBlockchain will not be connected, as that is a
# blocking operation. It will be called when the wallet is open.
dcrdataURL = DCRDATA_PATHS[netParams.Name]
self.dcrdata = DcrdataBlockchain(dcrdataDB, netParams, dcrdataURL)
chains.registerChain("dcr", self.dcrdata)
walletExists = Path(dbPath).is_file()
if not walletExists and not allowCreate:
raise DecredError("Wallet does not exist at %s", dbPath)

super().__init__(dbPath)
# words is only set the first time a wallet is created.
if not walletExists:
seed = rando.newKeyRaw()
self.initialize(seed, pw.encode(), netParams)
self.words = mnemonic.encode(seed)

cryptoKey = self.cryptoKey(pw)
acctMgr = self.accountManager(chains.BipIDs.decred, signals)
self.account = acctMgr.openAccount(0, cryptoKey)
self.account.sync()

def __getattr__(self, name):
"""Delegate unknown methods to the account."""
return getattr(self.account, name)

@staticmethod
def create(walletDir, pw, network, signals=None):
"""
Create a new wallet. Will not overwrite an existing wallet file. All
arguments are the same as the SimpleWallet constructor.
"""
netParams = nets.parse(network)
_, dbPath, _ = paths(walletDir, netParams.Name)
if Path(dbPath).is_file():
raise DecredError("wallet already exists at %s" % dbPath)
wallet = SimpleWallet(walletDir, pw, network, signals, True)
words = wallet.words
wallet.words.clear()
return wallet, words

def close(self):
self.dcrdata.close()
2 changes: 1 addition & 1 deletion decred/examples/create_testnet_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from getpass import getpass

from decred.wallet.simple import SimpleWallet
from decred.wallet.wallet import SimpleWallet


def main():
Expand Down
2 changes: 1 addition & 1 deletion decred/examples/send_testnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from getpass import getpass

from decred.wallet.simple import SimpleWallet
from decred.wallet.wallet import SimpleWallet

# Testnet return address for faucet.decred.org.
TESTNET_ADDRESS = "TsfDLrRkk9ciUuwfp2b8PawwnukYD7yAjGd"
Expand Down
28 changes: 28 additions & 0 deletions decred/tests/integration/wallet/test_wallet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Copyright (c) 2020, The Decred developers
"""

from decred.dcr import nets
from decred.wallet.wallet import SimpleWallet, Wallet


PASSWORD = "test_password"
NET_NAME = "testnet"

# Testnet return address for faucet.decred.org.
TESTNET_ADDRESS = "TsfDLrRkk9ciUuwfp2b8PawwnukYD7yAjGd"


def test_SimpleWallet(tmp_path):
wallet, _ = SimpleWallet.create(tmp_path, PASSWORD, NET_NAME)
wallet.close()
wallet = SimpleWallet(tmp_path, PASSWORD, NET_NAME)
wallet.close()


def test_Wallet(tmp_path):
first_wallet_path = tmp_path / "first_wallet"
netParams = nets.parse(NET_NAME)
words, _ = Wallet.create(first_wallet_path, PASSWORD, netParams)
second_wallet_path = tmp_path / "second_wallet"
Wallet.createFromMnemonic(words, second_wallet_path, PASSWORD, netParams)
Loading