def __init__(self, bsddb_env, filename): self.bsddb_env = bsddb_env self.filename = filename self.varstr_serializer = VarstrSerializer() self.uint256_serializer = Uint256Serializer("") self.wallet_tx_serializer = WalletTxSerializer() self.master_key_serializer = MasterKeySerializer() self.reset_wallet() self.db = bsddb.db.DB(self.bsddb_env.dbenv) self.dbflags = bsddb.db.DB_THREAD
class AlertMessageSerializer(Serializer): ALERT = Structure([VarstrSerializer("payload"), VarstrSerializer("signature")]) PAYLOAD = AlertPayloadSerializer() def serialize(self, alert_msg): payload_data = AlertPayloadSerializer().serialize(alert_msg.payload) return (self.ALERT.serialize([payload_data, alert_msg.signature])) def deserialize(self, data, cursor=0): (payload_data, signature), cursor = self.ALERT.deserialize(data, cursor) payload, _ = AlertPayloadSerializer().deserialize(payload_data) return (AlertMessage(payload, signature), cursor)
class VarstrScriptSerializer(Serializer): def __init__(self): self.serializer = ScriptSerializer() self.strencoder = VarstrSerializer() def serialize(self, script): scriptstr = self.serializer.serialize(script) return (self.strencoder.serialize(scriptstr)) def get_size(self, script): return self.strencoder.get_size_for_len(self.serializer.get_size(script)) def deserialize(self, data, cursor=0): scriptstr, newcursor = self.strencoder.deserialize(data, cursor) return (self.serializer.deserialize(scriptstr), newcursor)
class VarstrScriptSerializer(Serializer): def __init__(self): self.serializer = ScriptSerializer() self.strencoder = VarstrSerializer() def serialize(self, script): scriptstr = self.serializer.serialize(script) return (self.strencoder.serialize(scriptstr)) def get_size(self, script): return self.strencoder.get_size_for_len( self.serializer.get_size(script)) def deserialize(self, data, cursor=0): scriptstr, newcursor = self.strencoder.deserialize(data, cursor) return (self.serializer.deserialize(scriptstr), newcursor)
class MasterKeySerializer(): MASTER_KEY = Structure([ VarstrSerializer(), VarstrSerializer(), Field("<I"), Field("<I"), VarstrSerializer() ]) def serialize(self, master_key): return (self.MASTER_KEY.serialize([ master_key.crypted_key, master_key.salt, master_key.derivation_method, master_key.derive_iterations, master_key.other_derivation_parameters ])) def deserialize(self, data, cursor): master_key_fields, cursor = self.MASTER_KEY.deserialize(data, cursor) (crypted_key, salt, derivation_method, derive_iterations, other_derivation_parameters) = master_key_fields return (MasterKey(crypted_key, salt, derivation_method, derive_iterations, other_derivation_parameters), cursor)
class AlertPayloadSerializer(Serializer): PAYLOAD = Structure([Field("<I", "version"), Field("<Q", "relay_until"), Field("<Q", "expiration"), Field("<I", "id"), Field("<I", "cancel"), VarsizelistSerializer(VarintSerializer("count"), VarintSerializer("set_cancel")), Field("<I", "min_ver"), Field("<I", "max_ver"), VarsizelistSerializer(VarintSerializer("count"), VarstrSerializer("set_sub_ver")), Field("<I", "priority"), VarstrSerializer("comment"), VarstrSerializer("statusbar"), VarstrSerializer("reserved")]) def serialize(self, alert_payload): return (self.PAYLOAD.serialize([alert_payload.version, alert_payload.relay_until, alert_payload.expiration, alert_payload.id, alert_payload.cancel, alert_payload.set_cancel, alert_payload.min_ver, alert_payload.max_ver, alert_payload.set_sub_ver, alert_payload.priority, alert_payload.comment, alert_payload.statusbar, alert_payload.reserved])) def deserialize(self, data, cursor=0): payload_fields, cursor = self.PAYLOAD.deserialize(data, cursor) (version, relay_until, expiration, id, cancel, set_cancel, min_ver, max_ver, \ set_sub_ver, priority, comment, statusbar, reserved) = payload_fields return (AlertPayload(version, relay_until, expiration, id, cancel, set(set_cancel), min_ver, max_ver, set(set_sub_ver), priority, comment, statusbar, reserved), cursor)
class VersionMessageSerializer(Serializer): VERSION_STRUCT = Structure([ Field("<I", "version"), Field("<Q", "services"), Field("<Q", "timestamp"), NetAddrSerializer("addr_me"), NetAddrSerializer("addr_you"), Field("<Q", "nonce"), VarstrSerializer("sub_version_num"), Field("<I", "start_height") ], "version_message") def serialize(self, version_msg): return (self.VERSION_STRUCT.serialize([ version_msg.version, version_msg.services, version_msg.timestamp, version_msg.addr_me, version_msg.addr_you, version_msg.nonce, version_msg.sub_version_num, version_msg.start_height ])) def deserialize(self, data, cursor=0): result, cursor = self.VERSION_STRUCT.deserialize(data, cursor) return (VersionMessage(*result), cursor)
class BSDDBWalletDatabase(WalletDatabaseInterface): def __init__(self, bsddb_env, filename): self.bsddb_env = bsddb_env self.filename = filename self.varstr_serializer = VarstrSerializer() self.uint256_serializer = Uint256Serializer("") self.wallet_tx_serializer = WalletTxSerializer() self.master_key_serializer = MasterKeySerializer() self.reset_wallet() self.db = bsddb.db.DB(self.bsddb_env.dbenv) self.dbflags = bsddb.db.DB_THREAD def open(self): #self.bsddb_env.dbenv.fileid_reset(self.filename) self.dbtxn = self.bsddb_env.dbenv.txn_begin() self.db.open(self.filename, "main", bsddb.db.DB_BTREE, self.dbflags, txn=self.dbtxn) self.dbtxn.commit() self.dbtxn = None self._read_wallet() def create(self): #create empty database self.dbtxn = self.bsddb_env.dbenv.txn_begin() self.db.open(self.filename, "main", bsddb.db.DB_BTREE, self.dbflags | bsddb.db.DB_CREATE, txn=self.dbtxn) self.dbtxn.commit() self.dbtxn = None def begin_updates(self): self.dbtxn = self.bsddb_env.dbenv.txn_begin() def commit_updates(self): self.dbtxn.commit() #Synch to disk as wallet changes should not be lost self.db.sync() self.dbtxn = None def get_receive_key(self): if len(self.poolkeys) == 0: raise Exception("get_receive_key: No keys remaining") num, poolkey = next(self.poolkeys.iteritems()) return poolkey.public_key def allocate_key(self, public_key, address, label=None, ischange=False): num = self.poolkeys_by_public_key[public_key].poolnum if num is None: raise Exception("allocate_pool_key: Can't find pool public_key") del self.poolkeys_by_public_key[public_key] del self.poolkeys[num] self.db.delete("\x04pool" + struct.pack("<q", num), txn=self.dbtxn) if (label and not ischange): self.set_label(address, label) def reset_wallet(self): self.master_keys = {} self.crypted_keys = {} self.keys = {} self.names = {} self.settings = [] self.txs = {} self.poolkeys = {} self.poolkeys_by_public_key = {} def _read_entries(self, label): for key, value in self.db.items(): lab, key_cursor = self.varstr_serializer.deserialize(key, 0) if lab == label: yield (key, key_cursor, value, 0) def _read_keys(self): for key, key_cursor, value, value_cursor in self._read_entries("key"): public_key, _ = self.varstr_serializer.deserialize(key, key_cursor) private_key, _ = self.varstr_serializer.deserialize( value, value_cursor) self.keys[public_key] = WalletKeypair(public_key, private_key) def _read_crypted_keys(self): for key, key_cursor, value, value_cursor in self._read_entries("ckey"): public_key, _ = self.varstr_serializer.deserialize(key, key_cursor) crypted_secret, _ = self.varstr_serializer.deserialize( value, value_cursor) self.crypted_keys[public_key] = crypted_secret def _read_master_keys(self): for key, key_cursor, value, value_cursor in self._read_entries("mkey"): id, = struct.unpack_from("<I", key, key_cursor) self.master_keys[ id], cursor = self.master_key_serializer.deserialize( value, value_cursor) def _read_names(self): for key, key_cursor, value, value_cursor in self._read_entries("name"): address_bytestr, _ = self.varstr_serializer.deserialize( key, key_cursor) name, _ = self.varstr_serializer.deserialize(value, value_cursor) address = BitcoinAddress.from_base58addr(address_bytestr) self.names[address] = WalletName(name, address) def _read_txs(self): for key, key_cursor, value, value_cursor in self._read_entries("tx"): hash, _ = self.uint256_serializer.deserialize(key, key_cursor) wallet_tx, _ = self.wallet_tx_serializer.deserialize( value, value_cursor) self.txs[hash] = wallet_tx def _read_poolkeys(self): for key, key_cursor, value, value_cursor in self._read_entries("pool"): poolnum, = struct.unpack_from("<q", key, key_cursor) version, = struct.unpack_from("<I", value, 0) time, = struct.unpack_from("<q", value, 4) public_key, _ = self.varstr_serializer.deserialize(value, 12) self.poolkeys[poolnum] = WalletPoolKey(poolnum, version, time, public_key) self.poolkeys_by_public_key[public_key] = self.poolkeys[poolnum] def _read_wallet(self): self.reset_wallet() self._read_keys() self._read_crypted_keys() self._read_master_keys() self._read_names() self._read_txs() self._read_poolkeys() def get_keys(self): return self.keys def get_crypted_keys(self): return self.crypted_keys def get_wallet_txs(self): return self.txs def get_names(self): return self.names def get_poolkeys(self): return self.poolkeys def add_poolkey(self, poolkey): self.db.put("\x04pool" + struct.pack("<q", poolkey.poolnum), struct.pack("<I", poolkey.version) + \ struct.pack("<q", poolkey.time) + \ self.varstr_serializer.serialize(poolkey.public_key), txn=self.dbtxn) self.poolkeys[poolkey.poolnum] = poolkey self.poolkeys_by_public_key[poolkey.public_key] = self.poolkeys[ poolkey.poolnum] def set_label(self, address, label): self.names[address] = WalletName(label, address) address = self.varstr_serializer.serialize(address.to_base58addr()) name = self.varstr_serializer.serialize(label) self.db.put("\x04name" + address, name, txn=self.dbtxn) def add_name(self, wallet_name): pass def add_keypair(self, wallet_keypair): pass def set_transaction(self, hashtx, wallet_tx): self.txs[hashtx] = wallet_tx key = self.uint256_serializer.serialize(hashtx) value = self.wallet_tx_serializer.serialize(wallet_tx) self.db.put("\x02tx" + key, value, txn=self.dbtxn) def get_transaction(self, hashtx): return self.txs[hashtx] def del_transaction(self, hashtx): del self.txs[hashtx] self.db.delete("\x02tx" + self.uint256_serializer.serialize(hashtx), txn=self.dbtxn) def del_poolkey(self, num): del self.poolkeys[num] self.db.delete("\x04pool" + struct.pack("<I", num)) def add_master_key(self, master_key): id = max(self.master_keys.keys() + [0]) + 1 key = "\x04mkey" + struct.pack("<I", id) value = self.master_key_serializer.serialize(master_key) self.db.put(key, value, txn=self.dbtxn) self.master_keys[id] = master_key def add_crypted_key(self, public_key, crypted_secret): self.db.put("\x04ckey" + self.varstr_serializer.serialize(public_key), self.varstr_serializer.serialize(crypted_secret), txn=self.dbtxn) self.crypted_keys[public_key] = crypted_secret def get_master_keys(self): return (self.master_keys) def get_version(self): return (struct.unpack("<I", self.db["\x07version"])[0]) def set_version(self, version): self.db["\x07version"] = struct.pack("<I", version) """ Return wallet's BlockLocator or None if not found """ def get_block_locator(self): if self.db.has_key("\x09bestblock"): serializer = BlockLocatorSerializer() block_locator, cursor = serializer.deserialize( self.db["\x09bestblock"], 0) return block_locator def set_blocklocator(self, blocklocator): serializer = BlockLocatorSerializer() self.db["\x09bestblock"] = serializer.serialize(blocklocator) def __str__(self): keys_str = "\n".join(" " + str(k) for k in self.get_keypairs()) pool_keys_str = "\n".join(" " + str(k) for k in self.get_poolkeys()) names_str = "\n".join(" " + str(k) for k in self.get_names()) tx_str = "\n".join(" " + str(k) for k in self.get_wallet_txs()) return "Wallet\n keys:\n" + keys_str + "pool:\n" + pool_keys_str + "\n names:\n" + names_str + "\n txs:\n" + tx_str
def __init__(self): self.serializer = ScriptSerializer() self.strencoder = VarstrSerializer()
class BSDDBWalletDatabase(WalletDatabaseInterface): def __init__(self, bsddb_env, filename): self.bsddb_env = bsddb_env self.filename = filename self.varstr_serializer = VarstrSerializer() self.uint256_serializer = Uint256Serializer("") self.wallet_tx_serializer = WalletTxSerializer() self.master_key_serializer = MasterKeySerializer() self.reset_wallet() self.db = bsddb.db.DB(self.bsddb_env.dbenv) self.dbflags = bsddb.db.DB_THREAD def open(self): # self.bsddb_env.dbenv.fileid_reset(self.filename) self.dbtxn = self.bsddb_env.dbenv.txn_begin() self.db.open(self.filename, "main", bsddb.db.DB_BTREE, self.dbflags, txn=self.dbtxn) self.dbtxn.commit() self.dbtxn = None self._read_wallet() def create(self): # create empty database self.dbtxn = self.bsddb_env.dbenv.txn_begin() self.db.open(self.filename, "main", bsddb.db.DB_BTREE, self.dbflags | bsddb.db.DB_CREATE, txn=self.dbtxn) self.dbtxn.commit() self.dbtxn = None def begin_updates(self): self.dbtxn = self.bsddb_env.dbenv.txn_begin() def commit_updates(self): self.dbtxn.commit() # Synch to disk as wallet changes should not be lost self.db.sync() self.dbtxn = None def get_receive_key(self): if len(self.poolkeys) == 0: raise Exception("get_receive_key: No keys remaining") num, poolkey = next(self.poolkeys.iteritems()) return poolkey.public_key def allocate_key(self, public_key, address, label=None, ischange=False): num = self.poolkeys_by_public_key[public_key].poolnum if num is None: raise Exception("allocate_pool_key: Can't find pool public_key") del self.poolkeys_by_public_key[public_key] del self.poolkeys[num] self.db.delete("\x04pool" + struct.pack("<q", num), txn=self.dbtxn) if label and not ischange: self.set_label(address, label) def reset_wallet(self): self.master_keys = {} self.crypted_keys = {} self.keys = {} self.names = {} self.settings = [] self.txs = {} self.poolkeys = {} self.poolkeys_by_public_key = {} def _read_entries(self, label): for key, value in self.db.items(): lab, key_cursor = self.varstr_serializer.deserialize(key, 0) if lab == label: yield (key, key_cursor, value, 0) def _read_keys(self): for key, key_cursor, value, value_cursor in self._read_entries("key"): public_key, _ = self.varstr_serializer.deserialize(key, key_cursor) private_key, _ = self.varstr_serializer.deserialize(value, value_cursor) self.keys[public_key] = WalletKeypair(public_key, private_key) def _read_crypted_keys(self): for key, key_cursor, value, value_cursor in self._read_entries("ckey"): public_key, _ = self.varstr_serializer.deserialize(key, key_cursor) crypted_secret, _ = self.varstr_serializer.deserialize(value, value_cursor) self.crypted_keys[public_key] = crypted_secret def _read_master_keys(self): for key, key_cursor, value, value_cursor in self._read_entries("mkey"): id, = struct.unpack_from("<I", key, key_cursor) self.master_keys[id], cursor = self.master_key_serializer.deserialize(value, value_cursor) def _read_names(self): for key, key_cursor, value, value_cursor in self._read_entries("name"): address_bytestr, _ = self.varstr_serializer.deserialize(key, key_cursor) name, _ = self.varstr_serializer.deserialize(value, value_cursor) address = BitcoinAddress.from_base58addr(address_bytestr) self.names[address] = WalletName(name, address) def _read_txs(self): for key, key_cursor, value, value_cursor in self._read_entries("tx"): hash, _ = self.uint256_serializer.deserialize(key, key_cursor) wallet_tx, _ = self.wallet_tx_serializer.deserialize(value, value_cursor) self.txs[hash] = wallet_tx def _read_poolkeys(self): for key, key_cursor, value, value_cursor in self._read_entries("pool"): poolnum, = struct.unpack_from("<q", key, key_cursor) version, = struct.unpack_from("<I", value, 0) time, = struct.unpack_from("<q", value, 4) public_key, _ = self.varstr_serializer.deserialize(value, 12) self.poolkeys[poolnum] = WalletPoolKey(poolnum, version, time, public_key) self.poolkeys_by_public_key[public_key] = self.poolkeys[poolnum] def _read_wallet(self): self.reset_wallet() self._read_keys() self._read_crypted_keys() self._read_master_keys() self._read_names() self._read_txs() self._read_poolkeys() def get_keys(self): return self.keys def get_crypted_keys(self): return self.crypted_keys def get_wallet_txs(self): return self.txs def get_names(self): return self.names def get_poolkeys(self): return self.poolkeys def add_poolkey(self, poolkey): self.db.put( "\x04pool" + struct.pack("<q", poolkey.poolnum), struct.pack("<I", poolkey.version) + struct.pack("<q", poolkey.time) + self.varstr_serializer.serialize(poolkey.public_key), txn=self.dbtxn, ) self.poolkeys[poolkey.poolnum] = poolkey self.poolkeys_by_public_key[poolkey.public_key] = self.poolkeys[poolkey.poolnum] def set_label(self, address, label): self.names[address] = WalletName(label, address) address = self.varstr_serializer.serialize(address.to_base58addr()) name = self.varstr_serializer.serialize(label) self.db.put("\x04name" + address, name, txn=self.dbtxn) def add_name(self, wallet_name): pass def add_keypair(self, wallet_keypair): pass def set_transaction(self, hashtx, wallet_tx): self.txs[hashtx] = wallet_tx key = self.uint256_serializer.serialize(hashtx) value = self.wallet_tx_serializer.serialize(wallet_tx) self.db.put("\x02tx" + key, value, txn=self.dbtxn) def get_transaction(self, hashtx): return self.txs[hashtx] def del_transaction(self, hashtx): del self.txs[hashtx] self.db.delete("\x02tx" + self.uint256_serializer.serialize(hashtx), txn=self.dbtxn) def del_poolkey(self, num): del self.poolkeys[num] self.db.delete("\x04pool" + struct.pack("<I", num)) def add_master_key(self, master_key): id = max(self.master_keys.keys() + [0]) + 1 key = "\x04mkey" + struct.pack("<I", id) value = self.master_key_serializer.serialize(master_key) self.db.put(key, value, txn=self.dbtxn) self.master_keys[id] = master_key def add_crypted_key(self, public_key, crypted_secret): self.db.put( "\x04ckey" + self.varstr_serializer.serialize(public_key), self.varstr_serializer.serialize(crypted_secret), txn=self.dbtxn, ) self.crypted_keys[public_key] = crypted_secret def get_master_keys(self): return self.master_keys def get_version(self): return struct.unpack("<I", self.db["\x07version"])[0] def set_version(self, version): self.db["\x07version"] = struct.pack("<I", version) """ Return wallet's BlockLocator or None if not found """ def get_block_locator(self): if self.db.has_key("\x09bestblock"): serializer = BlockLocatorSerializer() block_locator, cursor = serializer.deserialize(self.db["\x09bestblock"], 0) return block_locator def set_blocklocator(self, blocklocator): serializer = BlockLocatorSerializer() self.db["\x09bestblock"] = serializer.serialize(blocklocator) def __str__(self): keys_str = "\n".join(" " + str(k) for k in self.get_keypairs()) pool_keys_str = "\n".join(" " + str(k) for k in self.get_poolkeys()) names_str = "\n".join(" " + str(k) for k in self.get_names()) tx_str = "\n".join(" " + str(k) for k in self.get_wallet_txs()) return ( "Wallet\n keys:\n" + keys_str + "pool:\n" + pool_keys_str + "\n names:\n" + names_str + "\n txs:\n" + tx_str )
def test_varstr_deserialize(self): str, _ = VarstrSerializer().deserialize(decodehexstr("0568656c6c6f")) self.assertEquals(str, "hello")
def test_varstr_serialize(self): self.assertEquals(hexstr(VarstrSerializer().serialize("hello")), "0568656c6c6f")