def __init__(self, netParams, dbPath, url, user, pw, certPath=None): """ Args: netParams (module): The network parameters. dbPath (str or Path): A path to a database file for use by the LocalNode. url (str): The URL for the local node, with protocol. user (str): The user name for authenticating the connection. pw (str): The password for authenticating the connection. certPath (str or Path): A filepath to the dcrd TLS certificate. """ self.netParams = netParams self.db = database.KeyValueDatabase(dbPath) self.mainchainDB = self.db.child( "mainchain", datatypes=("INTEGER", "BLOB"), blobber=ByteArray ) self.headerDB = self.db.child( "headers", blobber=BlockHeader, keyBlobber=ByteArray ) self.socketURL = helpers.makeWebsocketURL(url, "ws") self.rpc = None def connect(): self.close() self.rpc = rpc.WebsocketClient(self.socketURL, user, pw, cert=certPath) self.connect = connect connect()
def __init__(self, db, netParams, datapath, skipConnect=False): """ Args: db (database.Bucket | database.KeyValueDatabase | filepath): the database or a filepath. If a filepath, a new database will be created. netParams module: the network parameters. datapath str: a URL for a dcrdata server. skipConnect bool: skip initial connection to dcrdata. """ # Allow string arguments for database. self.ownsDB = False if not isinstance(db, (database.Bucket, database.KeyValueDatabase)): self.ownsDB = True db = database.KeyValueDatabase(db) self.db = db self.netParams = netParams self.datapath = datapath self.dcrdata = None self.txDB = db.child("tx", blobber=msgtx.MsgTx) self.heightMap = db.child("height", datatypes=("INTEGER", "BLOB")) self.headerDB = db.child("header", blobber=msgblock.BlockHeader) self.txBlockMap = db.child("blocklink") self.tipHeight = -1 self.subsidyCache = txscript.SubsidyCache(netParams) self.addrSubscribers = {} self.blockSubscribers = [] if not skipConnect: self.connect()
def test_discover(prepareLogger): cryptoKey = rando.newKey() db = database.KeyValueDatabase(":memory:").child("tmp") acctMgr = accounts.createNewAccountManager(tRoot, cryptoKey, "dcr", nets.mainnet, db) txs = {} class Blockchain: params = nets.mainnet addrsHaveTxs = lambda addrs: any(a in txs for a in addrs) ogChain = chains.chain("dcr") chains.registerChain("dcr", Blockchain) ogLimit = accounts.ACCOUNT_GAP_LIMIT accounts.ACCOUNT_GAP_LIMIT = 2 acctMgr.discover(cryptoKey) assert len(acctMgr.accounts) == 1 coinExtKey = acctMgr.coinKey(cryptoKey) acct2ExtKey = coinExtKey.deriveAccountKey(2).neuter().child(0) acct2Addr5 = addrlib.deriveChildAddress(acct2ExtKey, 5, nets.mainnet) txs[acct2Addr5] = ["tx"] acctMgr.discover(cryptoKey) assert len(acctMgr.accounts) == 3 chains.registerChain("dcr", ogChain) accounts.ACCOUNT_GAP_LIMIT = ogLimit
def test_discover(monkeypatch, prepareLogger): cryptoKey = rando.newKey() db = database.KeyValueDatabase(":memory:").child("tmp") acctMgr = accounts.createNewAccountManager(tRoot, cryptoKey, "dcr", nets.mainnet, db) txs = {} class Blockchain: params = nets.mainnet addrsHaveTxs = lambda addrs: any(a in txs for a in addrs) # Set up globals for test. origChain = chains.chain("dcr") chains.registerChain("dcr", Blockchain) # Set up globals for test. monkeypatch.setattr(accounts, "ACCOUNT_GAP_LIMIT", 2) monkeypatch.setattr(account, "DefaultGapLimit", 4) acctMgr.discover(cryptoKey) assert len(acctMgr.accounts) == 1 coinExtKey = acctMgr.coinKey(cryptoKey) acct2ExtKey = coinExtKey.deriveAccountKey(2).neuter().child(0) acct2Addr3 = addrlib.deriveChildAddress(acct2ExtKey, 3, nets.mainnet) txs[acct2Addr3] = ["tx"] acctMgr.discover(cryptoKey) assert len(acctMgr.accounts) == 3 # Restore globals. chains.registerChain("dcr", origChain)
def test_change_addresses(prepareLogger): """ Test internal branch address derivation. """ cryptoKey = rando.newKey() db = database.KeyValueDatabase(":memory:").child("tmp") # ticker for coin type is ok. Case insensitive. acctMgr = accounts.createNewAccountManager(tRoot, cryptoKey, "DcR", nets.mainnet, db) acct = acctMgr.openAccount(0, cryptoKey) for i in range(10): acct.nextInternalAddress()
def __init__(self, path): """ Args: path (str): The path to the wallet database. """ 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) self.keyParams = None self.selectedAccount = None self.openAccount = None self.mgrCache = {} # The best block. self.users = 0
def test_account_manager(monkeypatch, prepareLogger): # Set up globals for test. monkeypatch.setattr(account, "DefaultGapLimit", 2) cryptoKey = rando.newKey() db = database.KeyValueDatabase(":memory:").child("tmp") # 42 = Decred acctMgr = accounts.createNewAccountManager(tRoot, cryptoKey, 42, nets.mainnet, db) acct = acctMgr.openAccount(0, cryptoKey) tempAcct = acctMgr.addAccount(cryptoKey, "temp") assert acctMgr.account(1) == tempAcct assert acctMgr.listAccounts() == [acct, tempAcct] acctMgr.setNode("node") assert acctMgr.node == "node" assert tempAcct.node == "node" acctMgr.accounts[3] = tempAcct del acctMgr.accounts[1] with pytest.raises(DecredError): acctMgr.listAccounts() del acctMgr.accounts[3] with pytest.raises(DecredError): accounts.AccountManager.unblob(encode.BuildyBytes(0)) zeroth = acct.currentAddress() b = acctMgr.serialize() reAM = accounts.AccountManager.unblob(b.b) assert acctMgr.coinType == reAM.coinType assert acctMgr.netName == reAM.netName assert acctMgr.netName == reAM.netName reAM.load(db, None) reAcct = reAM.openAccount(0, cryptoKey) reZeroth = reAcct.currentAddress() assert zeroth == reZeroth acctMgr.saveAccount(0) db = acctMgr.dbForAcctIdx(0) assert db.name == "tmp$accts$0"
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 setup_db(tmpdir): # Open a key value db in the temp directory. db = database.KeyValueDatabase(tmpdir.join("bm.sqlite")).child("testdb") # Generate some data. return db, [(str(i).encode(), str(i).encode()) for i in range(10)]
def __init__(self, qApp): """ Args: qApp (QApplication): An initialized QApplication. """ super().__init__() self.qApp = qApp self.cfg = config.load() self.log = self.initLogging() self.wallet = None # trackedCssItems are CSS-styled elements to be updated if dark mode is # enabled/disabled. self.trackedCssItems = [] st = self.sysTray = QtWidgets.QSystemTrayIcon(QtGui.QIcon(DCR.FAVICON)) self.contextMenu = ctxMenu = QtWidgets.QMenu() ctxMenu.addAction("minimize").triggered.connect(self.minimizeApp) ctxMenu.addAction("quit").triggered.connect(self.shutdown) st.setContextMenu(ctxMenu) st.activated.connect(self.sysTrayActivated) # The signalRegistry maps a signal to any number of receivers. Signals # are routed through a Qt Signal. self.signalRegistry = {} self.qRawSignal.connect(self.signal_) self.blockchainSignals = TinySignals( balance=self.balanceSync, working=lambda: self.emitSignal(ui.WORKING_SIGNAL), done=lambda: self.emitSignal(ui.DONE_SIGNAL), spentTickets=lambda: self.emitSignal(ui.SPENT_TICKETS_SIGNAL), ) self.netDirectory = os.path.join(config.DATA_DIR, self.cfg.netParams.Name) helpers.mkdir(self.netDirectory) self.appDB = database.KeyValueDatabase( os.path.join(self.netDirectory, "app.db") ) self.settings = self.appDB.child("settings") self.loadSettings() dcrdataDB = database.KeyValueDatabase(self.assetDirectory("dcr") / "dcrdata.db") # The initialized DcrdataBlockchain will not be connected, as that is a # blocking operation. It will be called when the wallet is open. self.dcrdata = DcrdataBlockchain( dcrdataDB, self.cfg.netParams, self.settings[DB.dcrdata].decode(), skipConnect=True, ) chains.registerChain("dcr", self.dcrdata) # appWindow is the main application window. The TinyDialog class has # methods for organizing a stack of Screen widgets. self.appWindow = screens.TinyDialog(self) self.homeSig.connect(self.home_) def gohome(screen=None): self.homeSig.emit(screen) self.home = gohome self.homeScreen = None self.pwDialog = screens.PasswordDialog() self.waitingScreen = screens.WaitingScreen() # Set waiting screen as initial home screen. self.appWindow.stack(self.waitingScreen) self.confirmScreen = screens.ConfirmScreen() self.walletSig.connect(self.setWallet_) def setwallet(wallet): self.walletSig.emit(wallet) self.setWallet = setwallet self.sysTray.show() self.appWindow.show() self.initialize()
def test_database(prepareLogger, randBytes): # Open a key value db in the temp directory. master = database.KeyValueDatabase(":memory:") # '$' in bucket name is illegal. with pytest.raises(DecredError): master.child("a$b") try: db = master.child("test") # Again, '$' in bucket name is illegal. with pytest.raises(DecredError): db.child("c$d") # Create some test data. random.seed(0) testPairs = [(randBytes(low=1), randBytes()) for _ in range(20)] runPairs(db, testPairs) # check integer keys and child naming scheme intdb = db.child("inttest", datatypes=("INTEGER", "BLOB")) assert intdb.name == "test$inttest" intdb[5] = b"asdf" assert intdb[5] == b"asdf" intdb[6] = b"jkl;" assert intdb.first() == (5, b"asdf") assert intdb.last() == (6, b"jkl;") # check uniqueness of keys: k = testPairs[0][0] db[k] = b"some new bytes" assert len([key for key in db if key == k]) == 1 # test a serializable object randBlobber = lambda: TBlobber(ByteArray(randBytes())) objDB = master.child("blobber", blobber=TBlobber, unique=False) testPairs = [(randBytes(low=1), randBlobber()) for _ in range(20)] runPairs(objDB, testPairs) # non-uniqueness of keys k = testPairs[0][0] objDB[k] = randBlobber() assert len([key for key in objDB if key == k]) == 2 # test a second-level child kidDB = db.child("kid") testPairs = [(randBytes(low=1), randBytes()) for _ in range(20)] runPairs(kidDB, testPairs) # uniqueness of table keys k = testPairs[0][0] kidDB[k] = b"some new bytes" assert len([key for key in kidDB if key == k]) == 1 # slice notation sliceDB = db.child("slice", datatypes=("INTEGER", "TEXT")) n = 5 for i in range(n): sliceDB[i] = str(i) nums = sliceDB[:n] assert len(nums) == 5 assert all(i == int(s) for i, s in nums) assert sliceDB.last()[0] == 4 finally: master.close()