def __init__(self, dataDir, isTestNet): QtCore.QObject.__init__(self) self.lock = threading.Lock() self._patching_BaseTxDb() self.wallet_path = os.path.join(dataDir, 'wallet.sqlite') self._pwallet = PersistentWallet(self.wallet_path, isTestNet) self._set_wallet_settings(dataDir, isTestNet) self._pwallet.init_model() self._wallet = self._pwallet.get_model() self._controller = WalletController(self._wallet) self._utxo_fetcher = AsyncUTXOFetcher( self._wallet, self._pwallet.wallet_config.get('utxo_fetcher', {})) self._utxo_fetcher_timer = QtCore.QTimer() self._utxo_fetcher_timer.timeout.connect(self._utxo_fetcher.update) self._utxo_fetcher_timer.setInterval(1000) asset = self.get_asset_definition('bitcoin') if len(self._controller.get_all_addresses(asset)) == 0: self._controller.get_new_address(asset) self._create_club_asset()
def __getattribute__(self, name): if name in ['controller', 'model']: if not self.model_is_initialized: self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.model) slef.model_is_initialized = True return object.__getattribute__(self, name)
def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model())
def __init__(self, wallet=None, testnet=False): # sanitize inputs testnet = sanitize.flag(testnet) if not wallet: wallet = "%s.wallet" % ("testnet" if testnet else "mainnet") self.wallet = PersistentWallet(wallet, testnet) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.model)
def setUp(self): self.path = ":memory:" self.config = { 'dw_master_key': 'test', 'testnet': True, 'ccc': { 'colordb_path': self.path }, 'bip0032': False } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, ['']) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = '00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c' self.txhash = '4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7' script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD('test') def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = 'test' self.wc.issue_coins(self.moniker, 'obc', 10000, 1) self.asset = self.model.get_asset_definition_manager( ).get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager( ).get_asset_by_moniker('bitcoin') self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash)
def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parser.add_argument("--testnet", action='store_true') parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path'), parsed_args.get('testnet')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model()) self.async_utxo_fetcher = AsyncUTXOFetcher( self.model, self.wallet.wallet_config.get('utxo_fetcher', {}))
def test_get_history(self): self.config['asset_definitions'] = [ {"color_set": [""], "monikers": ["bitcoin"], "unit": 100000000}, {"color_set": ["obc:03524a4d6492e8d43cb6f3906a99be5a1bcd93916241f759812828b301f25a6c:0:153267"], "monikers": ['test'], "unit": 1},] self.config['hdwam'] = { "genesis_color_sets": [ ["obc:03524a4d6492e8d43cb6f3906a99be5a1bcd93916241f759812828b301f25a6c:0:153267"], ], "color_set_states": [ {"color_set": [""], "max_index": 1}, {"color_set": ["obc:03524a4d6492e8d43cb6f3906a99be5a1bcd93916241f759812828b301f25a6c:0:153267"], "max_index": 7}, ] } self.config['bip0032'] = True self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() # modify model colored coin context, so test runs faster ccc = self.model.ccc cdbuilder = ColorDataBuilderManager( ccc.colormap, ccc.blockchain_state, ccc.cdstore, ccc.metastore, AidedColorDataBuilder) ccc.colordata = ThinColorData( cdbuilder, ccc.blockchain_state, ccc.cdstore, ccc.colormap) wc = WalletController(self.model) adm = self.model.get_asset_definition_manager() asset = adm.get_asset_by_moniker('test') self.model.utxo_man.update_all() cq = self.model.make_coin_query({"asset": asset}) utxo_list = cq.get_result() # send to the second address so the mempool has something addrs = wc.get_all_addresses(asset) wc.send_coins(asset, [addrs[1].get_color_address()], [1000]) history = self.model.get_history_for_asset(asset) self.assertTrue(len(history) > 30)
def __getattribute__(self, name): if name in ['controller', 'model', 'wallet']: if name in self.data: return self.data[name] if name == 'wallet': wallet = PersistentWallet(self.args.get('wallet_path'), self.args.get('testnet')) self.data['wallet'] = wallet return wallet else: self.wallet.init_model() self.data['model'] = self.data['wallet'].get_model() self.data['controller'] = WalletController(self.data['model']) return self.data[name] return object.__getattribute__(self, name)
def setUp(self): self.path = ":memory:" self.config = {'dw_master_key': 'test', 'testnet': True, 'ccc': { 'colordb_path' : self.path }, 'bip0032': False } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, ['']) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = '00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c' self.txhash = '4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7' script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD('test') def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = 'test' self.wc.issue_coins(self.moniker, 'obc', 10000, 1) self.asset = self.model.get_asset_definition_manager( ).get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager( ).get_asset_by_moniker('bitcoin') self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash)
def setUp(self): self.pwallet = PersistentWallet(None, True) self.pwallet.init_model() self.model = self.pwallet.get_model() adm = self.model.get_asset_definition_manager() # make sure you have the asset 'testobc' in your testnet.wallet !! self.asset = adm.get_asset_by_moniker('testobc') self.color_spec = self.asset.get_color_set().get_data()[0] self.wc = WalletController(self.model) self.ewc = EWalletController(self.model, self.wc) def null(a): pass self.wc.publish_tx = null
def setUp(self): self.path = ":memory:" self.config = { 'hdw_master_key': '91813223e97697c42f05e54b3a85bae601f04526c5c053ff0811747db77cfdf5f1accb50b3765377c379379cd5aa512c38bf24a57e4173ef592305d16314a0f4', 'testnet': True, 'ccc': { 'colordb_path': self.path }, } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.ewc = EWalletController(self.model, self.wc) self.bcolorset = self.ewc.resolve_color_spec('') self.cspec = "obc:03524a4d6492e8d43cb6f3906a99be5a1bcd93916241f759812828b301f25a6c:0:153267"
def __getattribute__(self, name): if name in ['controller', 'model', 'wallet']: try: data = self.data except AttributeError: self.data = data = {} pw = PersistentWallet(self.args.get('wallet_path')) pw.init_model() wallet_model = pw.get_model() data.update({ 'controller': WalletController(wallet_model) if wallet_model else None, 'wallet': pw, 'model': wallet_model if pw else None, }) return data[name] return object.__getattribute__(self, name)
def setUp(self): self.path = ":memory:" self.config = { 'hdw_master_key': '91813223e97697c42f05e54b3a85bae601f04526c5c053ff0811747db77cfdf5f1accb50b3765377c379379cd5aa512c38bf24a57e4173ef592305d16314a0f4', 'testnet': True, 'ccc': { 'colordb_path': self.path }, } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.ewc = EWalletController(self.model, self.wc) self.econfig = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} self.comm0 = MockComm() self.comm1 = MockComm() self.comm0.add_peer(self.comm1) self.comm1.add_peer(self.comm0) self.agent0 = EAgent(self.ewc, self.econfig, self.comm0) self.agent1 = EAgent(self.ewc, self.econfig, self.comm1) self.cspec = "obc:03524a4d6492e8d43cb6f3906a99be5a1bcd93916241f759812828b301f25a6c:0:153267"
def setUp(self): self.pwallet = PersistentWallet(None, True) self.pwallet.init_model() self.model = self.pwallet.get_model() adm = self.model.get_asset_definition_manager() # make sure you have the asset 'testobc' in your testnet.wallet !! self.asset = adm.get_asset_by_moniker('testobc') self.color_spec = self.asset.get_color_set().get_data()[0] self.comm0 = MockComm() self.comm1 = MockComm() self.comm0.add_peer(self.comm1) self.comm1.add_peer(self.comm0) self.wc = WalletController(self.model) self.ewc = EWalletController(self.model, self.wc) self.econfig = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} self.agent0 = EAgent(self.ewc, self.econfig, self.comm0) self.agent1 = EAgent(self.ewc, self.econfig, self.comm1) self.cv0 = {'color_spec': "", 'value': 100} self.cv1 = {'color_spec': self.color_spec, 'value': 200} self.offer0 = MyEOffer(None, self.cv0, self.cv1) self.offer1 = MyEOffer(None, self.cv1, self.cv0)
class Wallet(QtCore.QObject): balanceUpdated = QtCore.pyqtSignal(name='balanceUpdated') def __init__(self, dataDir, isTestNet): QtCore.QObject.__init__(self) self.lock = threading.Lock() self._patching_BaseTxDb() self.wallet_path = os.path.join(dataDir, 'wallet.sqlite') self._pwallet = PersistentWallet(self.wallet_path, isTestNet) self._set_wallet_settings(dataDir, isTestNet) self._pwallet.init_model() self._wallet = self._pwallet.get_model() self._controller = WalletController(self._wallet) self._utxo_fetcher = AsyncUTXOFetcher( self._wallet, self._pwallet.wallet_config.get('utxo_fetcher', {})) self._utxo_fetcher_timer = QtCore.QTimer() self._utxo_fetcher_timer.timeout.connect(self._utxo_fetcher.update) self._utxo_fetcher_timer.setInterval(1000) asset = self.get_asset_definition('bitcoin') if len(self._controller.get_all_addresses(asset)) == 0: self._controller.get_new_address(asset) self._create_club_asset() def _patching_BaseTxDb(self): original_add_tx = BaseTxDb.add_tx def new_add_tx(baseTxDb, txhash, txdata, raw_tx, *args, **kwargs): retval = original_add_tx(baseTxDb, txhash, txdata, raw_tx, *args, **kwargs) if retval: ctxs = raw_tx.composed_tx_spec coinStore = self._wallet.get_coin_manager().store all_addresses = [a.get_address() for a in self._wallet.get_address_manager().get_all_addresses()] lookup_moniker_by_address = {} for asset in self._controller.get_all_assets(): monikers = asset.get_monikers() for address in self._controller.get_all_addresses(asset): lookup_moniker_by_address[address.get_address()] = monikers # txin for txin in ctxs.txins: prev_txhash, prev_outindex = txin.get_outpoint() coin_id = coinStore.find_coin(prev_txhash, prev_outindex) if coin_id: address = coinStore.get_coin(coin_id)['address'] self.balanceUpdated.emit() # txout for txout in ctxs.txouts: target_addr = txout.target_addr if target_addr in all_addresses: self.balanceUpdated.emit() return retval BaseTxDb.add_tx = new_add_tx def _set_wallet_settings(self, dataDir, isTestNet): self._pwallet.wallet_config['testnet'] = isTestNet ccc = self._pwallet.wallet_config.get('ccc', {}) ccc['colordb_path'] = os.path.join(dataDir, 'color_db.sqlite') self._pwallet.wallet_config['ccc'] = ccc def _create_club_asset(self): for asset in self._wallet.get_asset_definition_manager().get_all_assets(): for color in asset.get_color_set().get_data(): if color in clubAsset['color_set']: return self._wallet.get_asset_definition_manager().add_asset_definition(clubAsset) asset = self.get_asset_definition(clubAsset['monikers'][0]) if len(self._controller.get_all_addresses(asset)) == 0: self._controller.get_new_address(asset).get_color_address() def sync_start(self): self._utxo_fetcher.start_thread() self._utxo_fetcher_timer.start() def sync_stop(self): self._utxo_fetcher.stop() self._utxo_fetcher_timer.stop() def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self._wallet.get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if not asset: raise Exception("asset not found") return asset def get_address(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_all_addresses(asset)[0].get_color_address() def get_bitcoin_address(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_all_addresses(asset)[0].get_address() def get_total_balance(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_total_balance(asset) def get_available_balance(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_available_balance(asset) def get_unconfirmed_balance(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_unconfirmed_balance(asset) def send_coins(self, moniker, address): asset = self.get_asset_definition(moniker) total = self.get_total_balance(asset) self._controller.send_coins(asset, [address], [total]) def get_auth_data(self, moniker): with self.lock: coin = self._wallet.make_coin_query({ 'asset': self.get_asset_definition(moniker), 'spent': False, }).get_result()[0] pubKey = public_pair_to_sec(coin.address_rec.publicPoint.pair(), compressed=False) return { 'color_set': clubAsset['color_set'][0], 'txhash': coin.txhash, 'outindex': coin.outindex, 'pubkey': pubKey.encode('hex'), 'privkey': coin.address_rec.rawPrivKey, 'address_rec': coin.address_rec, } def sign_data(self, data, privKey): with self.lock: symbols_set = string.ascii_letters + string.digits salt = ''.join([random.choice(symbols_set) for _ in xrange(20)]) data = int((hash160(str(data) + salt)).encode('hex'), 16) return { 'salt': salt, 'sign': ecdsa.sign(ecdsa.generator_secp256k1, privKey, data), } def validate_bitcoin_address(self, address): bcbytes = a2b_base58(str(address)) return bcbytes[-4:] == sha256(sha256(bcbytes[:-4]).digest()).digest()[:4]
class Wallet(object): thread_comm = None def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model()) def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self.wallet.get_model().get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if asset: return asset else: raise Exception("asset not found") def get_asset_definition_by_color_set(self, color_set): adm = self.wallet.get_model().get_asset_definition_manager() for asset in adm.get_all_assets(): if color_set in asset.get_color_set().get_data(): return asset raise Exception("asset not found") def add_asset(self, params): self.controller.add_asset_definition({ "monikers": [params['moniker']], "color_set": [params['color_desc']], "unit": params['unit'] }) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_asset(self): return self.wallet.wallet_config['asset_definitions'] def issue(self, params): self.controller.issue_coins( params['moniker'], params['coloring_scheme'], params['units'], params['atoms']) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_monikers(self): monikers = [asset.get_monikers()[0] for asset in self.model.get_asset_definition_manager().get_all_assets()] monikers.remove('bitcoin') monikers = ['bitcoin'] + monikers return monikers def get_balance(self, color): return self.controller.get_balance(self.get_asset_definition(color)) def get_all_addresses(self, color): return [addr.get_color_address() for addr in self.controller.get_all_addresses(self.get_asset_definition(color))] def get_address_balance(self, color): asset = self.get_asset_definition(color) return self.controller.get_address_balance(asset) def get_some_address(self, color): wam = self.model.get_address_manager() cs = self.get_asset_definition(color).get_color_set() ar = wam.get_some_address(cs) return ar.get_color_address() def get_new_address(self, color): return self.controller. \ get_new_address(self.get_asset_definition(color)).get_color_address() def scan(self): self.controller.scan_utxos() def send_coins(self, items): if isinstance(items, dict): items = [items] for item in items: self.controller.send_coins( item['asset'] if 'asset' in item \ else self.get_asset_definition(item['moniker']), [item['address']], [item['value']]) def p2ptrade_init(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm( config, 'http://p2ptrade.btx.udoidio.info/messages') self.thread_comm = ThreadedComm(comm) self.p2p_agent = EAgent(ewctrl, config, self.thread_comm) self.thread_comm.start() def p2ptrade_stop(self): if self.thread_comm is not None: self.thread_comm.stop() def p2ptrade_make_offer(self, we_sell, params): asset = self.get_asset_definition(params['moniker']) value = asset.parse_value(params['value']) bitcoin = self.get_asset_definition('bitcoin') price = bitcoin.parse_value(params['price']) total = int(float(value)/float(asset.unit)*float(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} if we_sell: return MyEOffer(None, sell_side, buy_side) else: return MyEOffer(None, buy_side, sell_side) def p2ptrade_make_mirror_offer(self, offer): data = offer.get_data() return MyEOffer(None, data['B'], data['A'], False)
class Ngccc(apigen.Definition): """Next-Generation Colored Coin Client interface.""" def __init__(self, wallet=None, testnet=False): # sanitize inputs testnet = sanitize.flag(testnet) if not wallet: wallet = "%s.wallet" % ("testnet" if testnet else "mainnet") self.wallet = PersistentWallet(wallet, testnet) self.model_is_initialized = False def __getattribute__(self, name): if name in ['controller', 'model']: if not self.model_is_initialized: self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.model) slef.model_is_initialized = True return object.__getattribute__(self, name) @apigen.command() def setconfigval(self, key, value): # FIXME behaviour ok? """Sets a value in the configuration. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) value = sanitize.cfgvalue(value) kpath = key.split('.') value = json.loads(value) # traverse the path until we get to the value we need to set if len(kpath) > 1: branch = self.wallet.wallet_config[kpath[0]] cdict = branch for k in kpath[1:-1]: cdict = cdict[k] cdict[kpath[-1]] = value value = branch if kpath[0] in self.wallet.wallet_config: self.wallet.wallet_config[kpath[0]] = value else: raise KeyNotFound(key) @apigen.command() def getconfigval(self, key): """Returns the value for a given key in the config. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) if not key: raise KeyNotFound(key) keys = key.split('.') config = self.wallet.wallet_config # traverse the path until we get the value for key in keys: config = config[key] return _print(config) @apigen.command() def dumpconfig(self): """Returns a dump of the current configuration.""" dict_config = dict(self.wallet.wallet_config.iteritems()) return _print(dict_config) @apigen.command() def importconfig(self, path): # FIXME what about subkeys and removed keys? """Import JSON config.""" with open(path, 'r') as fp: config = json.loads(fp.read()) wallet_config = self.wallet.wallet_config for k in config: wallet_config[k] = config[k] @apigen.command() def issueasset(self, moniker, quantity, unit="100000000", scheme="epobc"): """ Issue <quantity> of asset with name <moniker> and <unit> atoms, based on <scheme (epobc|obc)>.""" # sanitize inputs moniker = sanitize.moniker(moniker) quantity = sanitize.quantity(quantity) unit = sanitize.unit(unit) scheme = sanitize.scheme(scheme) self.controller.issue_coins(moniker, scheme, quantity, unit) return self.getasset(moniker) @apigen.command() def addassetjson(self, data): """Add a json asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs data = sanitize.jsonasset(data) self.controller.add_asset_definition(data) return self.getasset(data['monikers'][0]) @apigen.command() def addasset(self, moniker, color_description, unit=100000000): """Add a asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs moniker = sanitize.moniker(moniker) color_description = sanitize.colordesc(color_description) unit = sanitize.unit(unit) self.controller.add_asset_definition({ "monikers": [moniker], "color_set": [color_description], "unit" : unit }) return self.getasset(moniker) @apigen.command() def getasset(self, moniker): """Get the asset associated with the moniker.""" return _print(sanitize.asset(self.model, moniker).get_data()) @apigen.command() def listassets(self): """Lists all assets/colors registered.""" assets = self.controller.get_all_assets() return _print(map(lambda asset: asset.get_data(), assets)) def _getbalance(self, asset, unconfirmed, available): if unconfirmed: balance = self.controller.get_unconfirmed_balance(asset) elif available: balance = self.controller.get_available_balance(asset) else: balance = self.controller.get_total_balance(asset) return (asset.get_monikers()[0], asset.format_value(balance)) @apigen.command() def getbalance(self, moniker, unconfirmed=False, available=False): """Returns the balance for a particular asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) balance = dict([self._getbalance(asset, unconfirmed, available)]) return _print(balance) @apigen.command() def getbalances(self, unconfirmed=False, available=False): """Returns the balances for all assets/colors.""" # sanitize inputs unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) assets = self.controller.get_all_assets() func = lambda asset: self._getbalance(asset, unconfirmed, available) balances = dict(map(func, assets)) return _print(balances) @apigen.command() def newaddress(self, moniker): """Creates a new coloraddress for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecord = self.controller.get_new_address(asset) coloraddress = addressrecord.get_color_address() return _print(coloraddress) @apigen.command() def listaddresses(self, moniker): """Lists all addresses for a given asset""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print([ao.get_color_address() for ao in addressrecords]) @apigen.command() def send(self, moniker, coloraddress, amount): """Send <coloraddress> given <amount> of an asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) amount = sanitize.assetamount(asset, amount) txid = self.controller.send_coins(asset, [coloraddress], [amount]) return _print(txid) @apigen.command() def sendmanyjson(self, data): """Send amounts given in json fromatted data. Format [{'moniker':"val",'amount':"val",'coloraddress':"val"}] All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanyjson(self.model, data) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def sendmanycsv(self, path): """Send amounts in csv file with format 'moniker,coloraddress,amount'. All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanycsv(self.model, path) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def scan(self): """Update the database of transactions.""" sleep(5) self.controller.scan_utxos() @apigen.command() def fullrescan(self): """Rebuild database of wallet transactions.""" self.controller.full_rescan() @apigen.command() def history(self, moniker): """Show the history of transactions for given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) return _print(self.controller.get_history(asset)) @apigen.command() def received(self, moniker): """Returns total received amount for each coloraddress of a given asset. """ # sanitize inputs asset = sanitize.asset(self.model, moniker) received = {} def reformat(data): coloraddress = data['color_address'] colorvalue = data['value'].get_value() return (coloraddress, asset.format_value(colorvalue)) data = self.controller.get_received_by_address(asset) return _print(dict(map(reformat, data))) @apigen.command() def coinlog(self): """Returns the coin transaction log for this wallet.""" log = defaultdict(list) for coin in self.controller.get_coinlog(): moniker = coin.asset.get_monikers()[0] moniker = 'bitcoin' if moniker == '' else moniker log[moniker].append({ 'address' : coin.get_address(), 'txid' : coin.txhash, 'out' : coin.outindex, 'colorvalue' : coin.colorvalues[0].get_value(), 'value' : coin.value, 'confirmed' : coin.is_confirmed(), 'spendingtxs' : coin.get_spending_txs(), }) return _print(log) @apigen.command() def dumpprivkey(self, moniker, coloraddress): """Private key for a given coloraddress.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) wam = self.model.get_address_manager() for addressrecord in wam.get_all_addresses(): if coloraddress == addressrecord.get_color_address(): return _print(addressrecord.get_private_key()) raise AddressNotFound(coloraddress) @apigen.command() def dumpprivkeys(self, moniker): """Lists all private keys for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print(map(lambda ar: ar.get_private_key(), addressrecords)) def _init_p2ptrade(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm(config, 'http://p2ptrade.btx.udoidio.info/messages') return EAgent(ewctrl, config, comm) def _p2ptrade_make_offer(self, we_sell, moniker, value, price, wait): # sanitize inputs asset = sanitize.asset(self.model, moniker) bitcoin = sanitize.asset(self.model, 'bitcoin') value = sanitize.assetamount(asset, value) price = sanitize.assetamount(bitcoin, price) wait = sanitize.integer(wait) total = int(Decimal(value)/Decimal(asset.unit)*Decimal(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} agent = self._init_p2ptrade() if we_sell: agent.register_my_offer(MyEOffer(None, sell_side, buy_side)) else: agent.register_my_offer(MyEOffer(None, buy_side, sell_side)) self._p2ptrade_wait(agent, wait) def _p2ptrade_wait(self, agent, wait): if wait and wait > 0: for _ in xrange(wait): agent.update() sleep(1) else: for _ in xrange(4*6): agent.update() sleep(0.25) @apigen.command() def p2porders(self, moniker="", sellonly=False, buyonly=False): """Show peer to peer trade orders""" # sanitize inputs sellonly = sanitize.flag(sellonly) buyonly = sanitize.flag(buyonly) asset = None if moniker and moniker != 'bitcoin': asset = sanitize.asset(self.model, moniker) # get offers agent = self._init_p2ptrade() agent.update() offers = agent.their_offers.values() offers = map(lambda offer: offer.get_data(), offers) # filter asset if given if asset: descs = asset.get_color_set().color_desc_list def func(offer): return (offer["A"]["color_spec"] in descs or offer["B"]["color_spec"] in descs) offers = filter(func, offers) # filter sellonly if given if sellonly: offers = filter(lambda o: o["A"]["color_spec"] != "", offers) # filter buyonly if given if buyonly: offers = filter(lambda o: o["A"]["color_spec"] == "", offers) return _print(offers) @apigen.command() def p2psell(self, moniker, assetamount, btcprice, wait=30): """Sell <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(True, moniker, assetamount, btcprice, wait) @apigen.command() def p2pbuy(self, moniker, assetamount, btcprice, wait=30): """Buy <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(False, moniker, assetamount, btcprice, wait)
class Wallet(object): thread_comm = None def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parser.add_argument("--testnet", action='store_true') parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path'), parsed_args.get('testnet')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model()) self.async_utxo_fetcher = AsyncUTXOFetcher( self.model, self.wallet.wallet_config.get('utxo_fetcher', {})) self.update_connected_thread = TimedAsyncTask(self.update_connected, 2.5) self.update_connected_thread.start() self.update_connected() def connected(self): return self.is_connected def update_connected(self): try: for moniker in self.get_all_monikers(): asset = self.get_asset_definition(moniker) address = self.get_some_address(asset) total_balance = self.get_total_balance(asset) self.is_connected = self.async_utxo_fetcher.interface.connected() except: raise self.is_connected = False def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self.wallet.get_model().get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if asset: return asset else: raise Exception("Asset '%s' not found!" % moniker) def get_asset_definition_by_color_set(self, color_set): adm = self.wallet.get_model().get_asset_definition_manager() for asset in adm.get_all_assets(): if color_set in asset.get_color_set().get_data(): return asset raise Exception("Asset not found!") def add_asset(self, params): self.controller.add_asset_definition({ "monikers": [params['moniker']], "color_set": [params['color_desc']], "unit": params['unit'] }) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_asset(self): return self.wallet.wallet_config['asset_definitions'] def issue(self, params): self.controller.issue_coins( params['moniker'], params['coloring_scheme'], params['units'], params['atoms']) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_monikers(self): monikers = [asset.get_monikers()[0] for asset in self.model.get_asset_definition_manager().get_all_assets()] monikers.remove('bitcoin') monikers = ['bitcoin'] + monikers return monikers def get_available_balance(self, color): return self.controller.get_available_balance( self.get_asset_definition(color)) def get_total_balance(self, color): return self.controller.get_total_balance( self.get_asset_definition(color)) def get_unconfirmed_balance(self, color): return self.controller.get_unconfirmed_balance( self.get_asset_definition(color)) def get_all_addresses(self, color): return [addr.get_color_address() for addr in self.controller.get_all_addresses(self.get_asset_definition(color))] def get_received_by_address(self, color): asset = self.get_asset_definition(color) return self.controller.get_received_by_address(asset) def get_some_address(self, color): wam = self.model.get_address_manager() cs = self.get_asset_definition(color).get_color_set() ar = wam.get_some_address(cs) return ar.get_color_address() def get_new_address(self, color): return self.controller. \ get_new_address(self.get_asset_definition(color)).get_color_address() def scan(self): self.controller.scan_utxos() def send_coins(self, items): if isinstance(items, dict): items = [items] for item in items: self.controller.send_coins( item['asset'] if 'asset' in item \ else self.get_asset_definition(item['moniker']), [item['address']], [item['value']]) def p2ptrade_init(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} self.thread_comm = ThreadedComm( config, 'http://p2ptrade.btx.udoidio.info/messages' ) self.p2p_agent = EAgent(ewctrl, config, self.thread_comm) self.thread_comm.start() def p2ptrade_stop(self): if self.thread_comm is not None: self.thread_comm.stop() def p2ptrade_make_offer(self, we_sell, params): asset = self.get_asset_definition(params['moniker']) value = asset.parse_value(params['value']) bitcoin = self.get_asset_definition('bitcoin') price = bitcoin.parse_value(params['price']) total = int(Decimal(value)/Decimal(asset.unit)*Decimal(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} if we_sell: return MyEOffer(None, sell_side, buy_side) else: return MyEOffer(None, buy_side, sell_side) def p2ptrade_make_mirror_offer(self, offer): data = offer.get_data() return MyEOffer(None, data['B'], data['A']) def stop_all(self): self.update_connected_thread.stop() self.update_connected_thread.join() self.async_utxo_fetcher.stop() self.p2ptrade_stop() if hasattr(self.model.txdb, 'vbs'): self.model.txdb.vbs.stop()
class Wallet(object): thread_comm = None def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--wallet", dest="wallet_path") parser.add_argument("--testnet", action='store_true') parsed_args = vars(parser.parse_args()) self.wallet = PersistentWallet(parsed_args.get('wallet_path'), parsed_args.get('testnet')) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.wallet.get_model()) self.async_utxo_fetcher = AsyncUTXOFetcher( self.model, self.wallet.wallet_config.get('utxo_fetcher', {})) def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self.wallet.get_model().get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if asset: return asset else: raise Exception("asset not found") def get_asset_definition_by_color_set(self, color_set): adm = self.wallet.get_model().get_asset_definition_manager() for asset in adm.get_all_assets(): if color_set in asset.get_color_set().get_data(): return asset raise Exception("asset not found") def add_asset(self, params): self.controller.add_asset_definition({ "monikers": [params['moniker']], "color_set": [params['color_desc']], "unit": params['unit'] }) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_asset(self): return self.wallet.wallet_config['asset_definitions'] def issue(self, params): self.controller.issue_coins( params['moniker'], params['coloring_scheme'], params['units'], params['atoms']) if len(self.get_all_addresses(params['moniker'])) == 0: self.get_new_address(params['moniker']) def get_all_monikers(self): monikers = [asset.get_monikers()[0] for asset in self.model.get_asset_definition_manager().get_all_assets()] monikers.remove('bitcoin') monikers = ['bitcoin'] + monikers return monikers def get_available_balance(self, color): return self.controller.get_available_balance( self.get_asset_definition(color)) def get_total_balance(self, color): return self.controller.get_total_balance( self.get_asset_definition(color)) def get_unconfirmed_balance(self, color): return self.controller.get_unconfirmed_balance( self.get_asset_definition(color)) def get_all_addresses(self, color): return [addr.get_color_address() for addr in self.controller.get_all_addresses(self.get_asset_definition(color))] def get_received_by_address(self, color): asset = self.get_asset_definition(color) return self.controller.get_received_by_address(asset) def get_some_address(self, color): wam = self.model.get_address_manager() cs = self.get_asset_definition(color).get_color_set() ar = wam.get_some_address(cs) return ar.get_color_address() def get_new_address(self, color): return self.controller. \ get_new_address(self.get_asset_definition(color)).get_color_address() def scan(self): self.controller.scan_utxos() def send_coins(self, items): if isinstance(items, dict): items = [items] for item in items: self.controller.send_coins( item['asset'] if 'asset' in item \ else self.get_asset_definition(item['moniker']), [item['address']], [item['value']]) def p2ptrade_init(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm( config, 'http://p2ptrade.btx.udoidio.info/messages') self.thread_comm = ThreadedComm(comm) self.p2p_agent = EAgent(ewctrl, config, self.thread_comm) self.thread_comm.start() def p2ptrade_stop(self): if self.thread_comm is not None: self.thread_comm.stop() def p2ptrade_make_offer(self, we_sell, params): asset = self.get_asset_definition(params['moniker']) value = asset.parse_value(params['value']) bitcoin = self.get_asset_definition('bitcoin') price = bitcoin.parse_value(params['price']) total = int(float(value)/float(asset.unit)*float(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} if we_sell: return MyEOffer(None, sell_side, buy_side) else: return MyEOffer(None, buy_side, sell_side) def p2ptrade_make_mirror_offer(self, offer): data = offer.get_data() return MyEOffer(None, data['B'], data['A'], False) def stop_all(self): self.async_utxo_fetcher.stop() self.p2ptrade_stop() if hasattr(self.model.txdb, 'vbs'): self.model.txdb.vbs.stop()
def setUp(self): from ngcccbase.pwallet import PersistentWallet from ngcccbase.wallet_controller import WalletController self.pwallet = PersistentWallet(":memory:", True) self.pwallet.init_model() self.wctrl = WalletController(self.pwallet.wallet_model)
class Wallet(QtCore.QObject): balanceUpdated = QtCore.pyqtSignal(name='balanceUpdated') def __init__(self, dataDir, isTestNet): QtCore.QObject.__init__(self) self.lock = threading.Lock() self._patching_BaseTxDb() self.wallet_path = os.path.join(dataDir, 'wallet.sqlite') self._pwallet = PersistentWallet(self.wallet_path, isTestNet) self._set_wallet_settings(dataDir, isTestNet) self._pwallet.init_model() self._wallet = self._pwallet.get_model() self._controller = WalletController(self._wallet) self._utxo_fetcher = AsyncUTXOFetcher( self._wallet, self._pwallet.wallet_config.get('utxo_fetcher', {})) self._utxo_fetcher_timer = QtCore.QTimer() self._utxo_fetcher_timer.timeout.connect(self._utxo_fetcher.update) self._utxo_fetcher_timer.setInterval(1000) asset = self.get_asset_definition('bitcoin') if len(self._controller.get_all_addresses(asset)) == 0: self._controller.get_new_address(asset) self._create_club_asset() def _patching_BaseTxDb(self): original_add_tx = BaseTxDb.add_tx def new_add_tx(baseTxDb, txhash, txdata, raw_tx, *args, **kwargs): retval = original_add_tx(baseTxDb, txhash, txdata, raw_tx, *args, **kwargs) if retval: ctxs = raw_tx.composed_tx_spec coinStore = self._wallet.get_coin_manager().store all_addresses = [ a.get_address() for a in self._wallet.get_address_manager().get_all_addresses() ] lookup_moniker_by_address = {} for asset in self._controller.get_all_assets(): monikers = asset.get_monikers() for address in self._controller.get_all_addresses(asset): lookup_moniker_by_address[ address.get_address()] = monikers # txin for txin in ctxs.txins: prev_txhash, prev_outindex = txin.get_outpoint() coin_id = coinStore.find_coin(prev_txhash, prev_outindex) if coin_id: address = coinStore.get_coin(coin_id)['address'] self.balanceUpdated.emit() # txout for txout in ctxs.txouts: target_addr = txout.target_addr if target_addr in all_addresses: self.balanceUpdated.emit() return retval BaseTxDb.add_tx = new_add_tx def _set_wallet_settings(self, dataDir, isTestNet): self._pwallet.wallet_config['testnet'] = isTestNet ccc = self._pwallet.wallet_config.get('ccc', {}) ccc['colordb_path'] = os.path.join(dataDir, 'color_db.sqlite') self._pwallet.wallet_config['ccc'] = ccc def _create_club_asset(self): for asset in self._wallet.get_asset_definition_manager( ).get_all_assets(): for color in asset.get_color_set().get_data(): if color in clubAsset['color_set']: return self._wallet.get_asset_definition_manager().add_asset_definition( clubAsset) asset = self.get_asset_definition(clubAsset['monikers'][0]) if len(self._controller.get_all_addresses(asset)) == 0: self._controller.get_new_address(asset).get_color_address() def sync_start(self): self._utxo_fetcher.start_thread() self._utxo_fetcher_timer.start() def sync_stop(self): self._utxo_fetcher.stop() self._utxo_fetcher_timer.stop() def get_asset_definition(self, moniker): if isinstance(moniker, AssetDefinition): return moniker adm = self._wallet.get_asset_definition_manager() asset = adm.get_asset_by_moniker(moniker) if not asset: raise Exception("asset not found") return asset def get_address(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_all_addresses(asset)[0].get_color_address() def get_bitcoin_address(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_all_addresses(asset)[0].get_address() def get_total_balance(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_total_balance(asset) def get_available_balance(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_available_balance(asset) def get_unconfirmed_balance(self, moniker): asset = self.get_asset_definition(moniker) return self._controller.get_unconfirmed_balance(asset) def send_coins(self, moniker, address): asset = self.get_asset_definition(moniker) total = self.get_total_balance(asset) self._controller.send_coins(asset, [address], [total]) def get_auth_data(self, moniker): with self.lock: coin = self._wallet.make_coin_query({ 'asset': self.get_asset_definition(moniker), 'spent': False, }).get_result()[0] pubKey = public_pair_to_sec(coin.address_rec.publicPoint.pair(), compressed=False) return { 'color_set': clubAsset['color_set'][0], 'txhash': coin.txhash, 'outindex': coin.outindex, 'pubkey': pubKey.encode('hex'), 'privkey': coin.address_rec.rawPrivKey, 'address_rec': coin.address_rec, } def sign_data(self, data, privKey): with self.lock: symbols_set = string.ascii_letters + string.digits salt = ''.join([random.choice(symbols_set) for _ in xrange(20)]) data = int((hash160(str(data) + salt)).encode('hex'), 16) return { 'salt': salt, 'sign': ecdsa.sign(ecdsa.generator_secp256k1, privKey, data), } def validate_bitcoin_address(self, address): bcbytes = a2b_base58(str(address)) return bcbytes[-4:] == sha256(sha256( bcbytes[:-4]).digest()).digest()[:4]
class TestWalletController(unittest.TestCase): def setUp(self): self.path = ":memory:" self.config = { 'dw_master_key': 'test', 'testnet': True, 'ccc': { 'colordb_path': self.path }, 'bip0032': False } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, ['']) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = '00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c' self.txhash = '4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7' script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD('test') def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = 'test' self.wc.issue_coins(self.moniker, 'obc', 10000, 1) self.asset = self.model.get_asset_definition_manager( ).get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager( ).get_asset_by_moniker('bitcoin') self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash) def test_issue(self): self.assertRaises(InvalidColorDefinitionError, self.wc.issue_coins, self.moniker, 'nonexistent', 10000, 1) item = self.wc.get_history(self.asset)[0] self.assertEqual(item['action'], 'issued') self.assertEqual(item['value'], 10000) self.wc.scan_utxos() item = self.wc.get_history(self.asset)[0] self.assertEqual(item['action'], 'issued') self.assertEqual(item['value'], 10000) def test_new_address(self): addr = self.wc.get_new_address(self.asset) addrs = self.wc.get_all_addresses(self.asset) self.assertEqual(len(addr.get_address()), 34) self.assertTrue(addr in addrs) for d in self.wc.get_received_by_address(self.asset): if d['address'] == addr.get_address(): self.assertEqual(d['value'], 0) def test_get_all_assets(self): self.assertTrue(self.asset in self.wc.get_all_assets()) def test_get_balance(self): self.assertEqual(self.wc.get_total_balance(self.asset), 10000) def test_add_asset(self): moniker = 'addtest' params = { "monikers": [moniker], "color_set": ['obc:aaaaaaaaaaaaaaaaa:0:0'], "unit": 1 } self.wc.add_asset_definition(params) asset = self.model.get_asset_definition_manager().get_asset_by_moniker( moniker) self.assertEqual(self.wc.get_total_balance(asset), 0) self.assertEqual(self.wc.get_history(asset), []) def test_send(self): addr1 = self.wc.get_new_address(self.asset) addr2 = self.wc.get_new_address(self.asset) color_addrs = [addr1.get_color_address(), addr2.get_color_address()] self.wc.send_coins(self.asset, color_addrs, [1000, 2000]) self.assertRaises(AssetMismatchError, self.wc.send_coins, self.basset, color_addrs, [1000, 2000])
class TestWalletController(unittest.TestCase): def setUp(self): self.path = ":memory:" self.config = {"dw_master_key": "test", "testnet": True, "ccc": {"colordb_path": self.path}, "bip0032": False} self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, [""]) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = "00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c" self.txhash = "4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7" script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format(self.baddress.rawPubkey().encode("hex")) ).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format(self.baddress.rawPubkey().encode("hex")) ).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD("test") def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = "test" self.wc.issue_coins(self.moniker, "obc", 10000, 1) self.asset = self.model.get_asset_definition_manager().get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager().get_asset_by_moniker("bitcoin") self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash) def test_issue(self): self.assertRaises(InvalidColorDefinitionError, self.wc.issue_coins, self.moniker, "nonexistent", 10000, 1) item = self.wc.get_history(self.asset)[0] self.assertEqual(item["action"], "issued") self.assertEqual(item["value"], 10000) self.wc.scan_utxos() item = self.wc.get_history(self.asset)[0] self.assertEqual(item["action"], "issued") self.assertEqual(item["value"], 10000) def test_new_address(self): addr = self.wc.get_new_address(self.asset) addrs = self.wc.get_all_addresses(self.asset) self.assertEqual(len(addr.get_address()), 34) self.assertTrue(addr in addrs) for d in self.wc.get_address_balance(self.asset): if d["address"] == addr.get_address(): self.assertEqual(d["value"], 0) def test_get_all_assets(self): self.assertTrue(self.asset in self.wc.get_all_assets()) def test_get_balance(self): self.assertEqual(self.wc.get_total_balance(self.asset), 10000) def test_add_asset(self): moniker = "addtest" params = {"monikers": [moniker], "color_set": ["obc:aaaaaaaaaaaaaaaaa:0:0"], "unit": 1} self.wc.add_asset_definition(params) asset = self.model.get_asset_definition_manager().get_asset_by_moniker(moniker) self.assertEqual(self.wc.get_total_balance(asset), 0) self.assertEqual(self.wc.get_history(asset), []) def test_send(self): addr1 = self.wc.get_new_address(self.asset) addr2 = self.wc.get_new_address(self.asset) color_addrs = [addr1.get_color_address(), addr2.get_color_address()] self.wc.send_coins(self.asset, color_addrs, [1000, 2000]) self.assertRaises(AssetMismatchError, self.wc.send_coins, self.basset, color_addrs, [1000, 2000])
class Ngccc(apigen.Definition): """Next-Generation Colored Coin Client interface.""" def __init__(self, wallet=None, testnet=False): # sanitize inputs testnet = sanitize.flag(testnet) if not wallet: wallet = "%s.wallet" % ("testnet" if testnet else "mainnet") self.wallet = PersistentWallet(wallet, testnet) self.wallet.init_model() self.model = self.wallet.get_model() self.controller = WalletController(self.model) @apigen.command() def setconfigval(self, key, value): # FIXME behaviour ok? """Sets a value in the configuration. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) value = sanitize.cfgvalue(value) kpath = key.split('.') value = json.loads(value) # traverse the path until we get to the value we need to set if len(kpath) > 1: branch = self.wallet.wallet_config[kpath[0]] cdict = branch for k in kpath[1:-1]: cdict = cdict[k] cdict[kpath[-1]] = value value = branch if kpath[0] in self.wallet.wallet_config: self.wallet.wallet_config[kpath[0]] = value else: raise KeyNotFound(key) @apigen.command() def getconfigval(self, key): """Returns the value for a given key in the config. Key is expressed as: key.subkey.subsubkey """ # sanitize inputs key = sanitize.cfgkey(key) if not key: raise KeyNotFound(key) keys = key.split('.') config = self.wallet.wallet_config # traverse the path until we get the value for key in keys: config = config[key] return _print(config) @apigen.command() def dumpconfig(self): """Returns a dump of the current configuration.""" dict_config = dict(self.wallet.wallet_config.iteritems()) return _print(dict_config) @apigen.command() def importconfig(self, path): # FIXME what about subkeys and removed keys? """Import JSON config.""" with open(path, 'r') as fp: config = json.loads(fp.read()) wallet_config = self.wallet.wallet_config for k in config: wallet_config[k] = config[k] @apigen.command() def issueasset(self, moniker, quantity, unit="100000000", scheme="epobc"): """ Issue <quantity> of asset with name <moniker> and <unit> atoms, based on <scheme (epobc|obc)>.""" # sanitize inputs moniker = sanitize.moniker(moniker) quantity = sanitize.quantity(quantity) unit = sanitize.unit(unit) scheme = sanitize.scheme(scheme) self.controller.issue_coins(moniker, scheme, quantity, unit) return self.getasset(moniker) @apigen.command() def addassetjson(self, data): """Add a json asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs data = sanitize.jsonasset(data) self.controller.add_asset_definition(data) return self.getasset(data['monikers'][0]) @apigen.command() def addasset(self, moniker, color_description, unit=100000000): """Add a asset definition. Enables the use of colors/assets issued by others. """ # sanitize inputs moniker = sanitize.moniker(moniker) color_description = sanitize.colordesc(color_description) unit = sanitize.unit(unit) self.controller.add_asset_definition({ "monikers": [moniker], "color_set": [color_description], "unit": unit }) return self.getasset(moniker) @apigen.command() def getasset(self, moniker): """Get the asset associated with the moniker.""" return _print(sanitize.asset(self.model, moniker).get_data()) @apigen.command() def listassets(self): """Lists all assets/colors registered.""" assets = self.controller.get_all_assets() return _print(map(lambda asset: asset.get_data(), assets)) def _getbalance(self, asset, unconfirmed, available): if unconfirmed: balance = self.controller.get_unconfirmed_balance(asset) elif available: balance = self.controller.get_available_balance(asset) else: balance = self.controller.get_total_balance(asset) return (asset.get_monikers()[0], asset.format_value(balance)) @apigen.command() def getbalance(self, moniker, unconfirmed=False, available=False): """Returns the balance for a particular asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) balance = dict([self._getbalance(asset, unconfirmed, available)]) return _print(balance) @apigen.command() def getbalances(self, unconfirmed=False, available=False): """Returns the balances for all assets/colors.""" # sanitize inputs unconfirmed = sanitize.flag(unconfirmed) available = sanitize.flag(available) assets = self.controller.get_all_assets() func = lambda asset: self._getbalance(asset, unconfirmed, available) balances = dict(map(func, assets)) return _print(balances) @apigen.command() def newaddress(self, moniker): """Creates a new coloraddress for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecord = self.controller.get_new_address(asset) coloraddress = addressrecord.get_color_address() return _print(coloraddress) @apigen.command() def listaddresses(self, moniker): """Lists all addresses for a given asset""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print([ao.get_color_address() for ao in addressrecords]) @apigen.command() def send(self, moniker, coloraddress, amount): """Send <coloraddress> given <amount> of an asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) amount = sanitize.assetamount(asset, amount) txid = self.controller.send_coins(asset, [coloraddress], [amount]) return _print(txid) @apigen.command() def sendmanyjson(self, data): """Send amounts given in json fromatted data. Format [{'moniker':"val",'amount':"val",'coloraddress':"val"}] All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanyjson(self.model, data) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def sendmanycsv(self, path): """Send amounts in csv file with format 'moniker,coloraddress,amount'. All entries must use the same color scheme. """ # sanitize inputs sendmany_entries = sanitize.sendmanycsv(self.model, path) return _print(self.controller.sendmany_coins(sendmany_entries)) @apigen.command() def scan(self): """Update the database of transactions.""" sleep(5) self.controller.scan_utxos() @apigen.command() def fullrescan(self): """Rebuild database of wallet transactions.""" self.controller.full_rescan() @apigen.command() def history(self, moniker): """Show the history of transactions for given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) return _print(self.controller.get_history(asset)) @apigen.command() def received(self, moniker): """Returns total received amount for each coloraddress of a given asset. """ # sanitize inputs asset = sanitize.asset(self.model, moniker) received = {} def reformat(data): coloraddress = data['color_address'] colorvalue = data['value'].get_value() return (coloraddress, asset.format_value(colorvalue)) data = self.controller.get_received_by_address(asset) return _print(dict(map(reformat, data))) @apigen.command() def coinlog(self): """Returns the coin transaction log for this wallet.""" log = defaultdict(list) for coin in self.controller.get_coinlog(): moniker = coin.asset.get_monikers()[0] moniker = 'bitcoin' if moniker == '' else moniker log[moniker].append({ 'address': coin.get_address(), 'txid': coin.txhash, 'out': coin.outindex, 'colorvalue': coin.colorvalues[0].get_value(), 'value': coin.value, 'confirmed': coin.is_confirmed(), 'spendingtxs': coin.get_spending_txs(), }) return _print(log) @apigen.command() def dumpprivkey(self, moniker, coloraddress): """Private key for a given coloraddress.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) coloraddress = sanitize.coloraddress(self.model, asset, coloraddress) wam = self.model.get_address_manager() for addressrecord in wam.get_all_addresses(): if coloraddress == addressrecord.get_color_address(): return _print(addressrecord.get_private_key()) raise AddressNotFound(coloraddress) @apigen.command() def dumpprivkeys(self, moniker): """Lists all private keys for a given asset.""" # sanitize inputs asset = sanitize.asset(self.model, moniker) addressrecords = self.controller.get_all_addresses(asset) return _print(map(lambda ar: ar.get_private_key(), addressrecords)) def _init_p2ptrade(self): ewctrl = EWalletController(self.model, self.controller) config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30} comm = HTTPComm(config, 'http://p2ptrade.btx.udoidio.info/messages') return EAgent(ewctrl, config, comm) def _p2ptrade_make_offer(self, we_sell, moniker, value, price, wait): # sanitize inputs asset = sanitize.asset(self.model, moniker) bitcoin = sanitize.asset(self.model, 'bitcoin') value = sanitize.assetamount(asset, value) price = sanitize.assetamount(bitcoin, price) wait = sanitize.integer(wait) total = int(Decimal(value) / Decimal(asset.unit) * Decimal(price)) color_desc = asset.get_color_set().color_desc_list[0] sell_side = {"color_spec": color_desc, "value": value} buy_side = {"color_spec": "", "value": total} agent = self._init_p2ptrade() if we_sell: agent.register_my_offer(MyEOffer(None, sell_side, buy_side)) else: agent.register_my_offer(MyEOffer(None, buy_side, sell_side)) self._p2ptrade_wait(agent, wait) def _p2ptrade_wait(self, agent, wait): if wait and wait > 0: for _ in xrange(wait): agent.update() sleep(1) else: for _ in xrange(4 * 6): agent.update() sleep(0.25) @apigen.command() def p2porders(self, moniker="", sellonly=False, buyonly=False): """Show peer to peer trade orders""" # sanitize inputs sellonly = sanitize.flag(sellonly) buyonly = sanitize.flag(buyonly) asset = None if moniker and moniker != 'bitcoin': asset = sanitize.asset(self.model, moniker) # get offers agent = self._init_p2ptrade() agent.update() offers = agent.their_offers.values() offers = map(lambda offer: offer.get_data(), offers) # filter asset if given if asset: descs = asset.get_color_set().color_desc_list def func(offer): return (offer["A"]["color_spec"] in descs or offer["B"]["color_spec"] in descs) offers = filter(func, offers) # filter sellonly if given if sellonly: offers = filter(lambda o: o["A"]["color_spec"] != "", offers) # filter buyonly if given if buyonly: offers = filter(lambda o: o["A"]["color_spec"] == "", offers) return _print(offers) @apigen.command() def p2psell(self, moniker, assetamount, btcprice, wait=30): """Sell <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(True, moniker, assetamount, btcprice, wait) @apigen.command() def p2pbuy(self, moniker, assetamount, btcprice, wait=30): """Buy <assetamount> for <btcprice> via peer to peer trade.""" self._p2ptrade_make_offer(False, moniker, assetamount, btcprice, wait)