コード例 #1
0
ファイル: blockchain.py プロジェクト: yoandresaav/tinydecred
    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()
コード例 #2
0
 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()
コード例 #3
0
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
コード例 #4
0
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)
コード例 #5
0
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()
コード例 #6
0
 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
コード例 #7
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"
コード例 #8
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()
コード例 #9
0
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)]
コード例 #10
0
    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()
コード例 #11
0
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()