def validate(db, source, destination, asset, quantity, block_index): try: util.get_asset_id(db, asset, block_index) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') try: script.validate(destination) except AddressError: raise ValidateError('destination address invalid') if asset == config.BTC: raise ValidateError('cannot send {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('quantity too large') if quantity <= 0: raise ValidateError('quantity non‐positive') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient')
def validate(db, source, destination, asset, quantity): try: util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') if destination: raise ValidateError('destination exists') if asset == config.BTC: raise ValidateError('cannot destroy {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('integer overflow, quantity too large') if quantity < 0: raise ValidateError('quantity negative') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient')
def validate (db, source, destination, asset, quantity): try: util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') if destination: raise ValidateError('destination exists') if asset == config.BTC: raise ValidateError('cannot destroy {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('integer overflow, quantity too large') if quantity < 0: raise ValidateError('quantity negative') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient')
def validate(db, source, destination, asset, quantity, block_index): try: util.get_asset_id(db, asset, block_index) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') try: script.validate(destination) except AddressError: raise ValidateError('destination address invalid') if asset == config.BTC: raise ValidateError('cannot send {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('quantity too large') if quantity <= 0: raise ValidateError('quantity non‐positive') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient') if util.enabled('options_require_memo'): # Check destination address options cursor = db.cursor() try: results = cursor.execute( 'SELECT options FROM addresses WHERE address=?', (destination, )) if results: result = results.fetchone() if result and result[ 'options'] & config.ADDRESS_OPTION_REQUIRE_MEMO: raise ValidateError('destination requires memo') finally: cursor.close()
def compose (db, source, feed_address, bet_type, deadline, wager_quantity, counterwager_quantity, target_value, leverage, expiration): if util.get_balance(db, source, config.XCP) < wager_quantity: raise exceptions.ComposeError('insufficient funds') problems, leverage = validate(db, source, feed_address, bet_type, deadline, wager_quantity, counterwager_quantity, target_value, leverage, expiration, util.CURRENT_BLOCK_INDEX) if util.date_passed(deadline): problems.append('deadline passed') if problems: raise exceptions.ComposeError(problems) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, bet_type, deadline, wager_quantity, counterwager_quantity, target_value, leverage, expiration) return (source, [(feed_address, None)], data)
def get_balance(self, address, asset=config.XCP): return util.get_balance(self.db, address, asset)
def test_alice_bob(server_db): alice = ADDR[0] bob = "miJqNkHhC5xsB61gsiSWXeTLnEGSQnWbXB" # check alices UTXOs utxos = util.api('get_unspent_txouts', {"address": alice}) assert len(utxos) == 1 assert utxos[0]['address'] == alice assert utxos[0][ 'txid'] == "ae241be7be83ebb14902757ad94854f787d9730fc553d6f695346c9375c0d8c1" assert utxos[0]['amount'] == 1.9990914 assert utxos[0]['confirmations'] == 74 # balance before send alice_balance = util.get_balance(server_db, alice, 'XCP') bob_balance = util.get_balance(server_db, bob, 'XCP') assert alice_balance == 91875000000 assert bob_balance == 0 # create send v = int(100 * 1e8) send1hex = util.api('create_send', { 'source': alice, 'destination': bob, 'asset': 'XCP', 'quantity': v }) assert send1hex == "0100000001c1d8c075936c3495f6d653c50f73d987f75448d97a750249b1eb83bee71b24ae000000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788acffffffff0336150000000000001976a9141e9d9c2c34d4dda3cd71603d9ce1e447c3cc5c0588ac00000000000000001e6a1c8a5dda15fb6f05628a061e67576e926dc71a7fa2f0cceb951120a9322f30ea0b000000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788ac00000000" # insert send, this automatically also creates a block tx1hash, tx1 = util_test.insert_raw_transaction(send1hex, server_db) # balances after send alice_balance2 = util.get_balance(server_db, alice, 'XCP') bob_balance2 = util.get_balance(server_db, bob, 'XCP') assert alice_balance2 == alice_balance - v assert bob_balance2 == bob_balance + v # check API result result = util.api( "get_balances", { "filters": [ { 'field': 'address', 'op': '==', 'value': alice }, { 'field': 'asset', 'op': '==', 'value': 'XCP' }, ] }) assert result[0]['quantity'] == alice_balance2 # -- do another TX # check alices UTXOs utxos = util.api('get_unspent_txouts', {"address": alice}) assert len(utxos) == 1 assert utxos[0]['address'] == alice assert utxos[0]['txid'] == tx1['tx_hash'] assert utxos[0]['amount'] == 1.99897135 assert utxos[0]['confirmations'] == 1 # balances before send alice_balance = util.get_balance(server_db, alice, 'XCP') bob_balance = util.get_balance(server_db, bob, 'XCP') assert alice_balance == alice_balance2 assert bob_balance == bob_balance2 # create send v = int(100 * 1e8) send2hex = util.api('create_send', { 'source': alice, 'destination': bob, 'asset': 'XCP', 'quantity': v }) assert send2hex == "0100000001cd2d431037d1d0cfe05daeb1d08b975f27488e383f7f169e09d2f405fb618f39020000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788acffffffff0336150000000000001976a9141e9d9c2c34d4dda3cd71603d9ce1e447c3cc5c0588ac00000000000000001e6a1c8a5dda15fb6f05628a061e67576e926dc71a7fa2f0cceb951120a9324a01ea0b000000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788ac00000000" # insert send, this automatically also creates a block tx2hash, tx2 = util_test.insert_raw_transaction(send2hex, server_db) # balances after send alice_balance2 = util.get_balance(server_db, alice, 'XCP') bob_balance2 = util.get_balance(server_db, bob, 'XCP') assert alice_balance2 == alice_balance - v assert bob_balance2 == bob_balance + v # -- do another TX, now unconfirmed # check alices UTXOs utxos = util.api('get_unspent_txouts', {"address": alice}) assert len(utxos) == 1 assert utxos[0]['address'] == alice assert utxos[0]['txid'] == tx2['tx_hash'] assert utxos[0]['amount'] == 1.9988513 assert utxos[0]['confirmations'] == 1 # balances before send alice_balance = util.get_balance(server_db, alice, 'XCP') bob_balance = util.get_balance(server_db, bob, 'XCP') assert alice_balance == alice_balance2 assert bob_balance == bob_balance2 # create send v = int(100 * 1e8) send3hex = util.api('create_send', { 'source': alice, 'destination': bob, 'asset': 'XCP', 'quantity': v }) assert send3hex == "01000000019aea7b78c8fffa50c51bbadb87824a202b3e6b53727e543e9c6846845205b5ce020000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788acffffffff0336150000000000001976a9141e9d9c2c34d4dda3cd71603d9ce1e447c3cc5c0588ac00000000000000001e6a1c8a5dda15fb6f05628a061e67576e926dc71a7fa2f0cceb951120a93265d2e90b000000001976a9144838d8b3588c4c7ba7c1d06f866e9b3739c6303788ac00000000" # insert send, as unconfirmed! won't create a block! tx3 = util_test.insert_unconfirmed_raw_transaction(send3hex, server_db) # balances after send, unaffected alice_balance2 = util.get_balance(server_db, alice, 'XCP') bob_balance2 = util.get_balance(server_db, bob, 'XCP') assert alice_balance2 == alice_balance assert bob_balance2 == bob_balance # no confirmed UTXOs left, we use the 1 we had utxos = util.api('get_unspent_txouts', {"address": alice}) assert len(utxos) == 0 # unconfirmed UTXO is there, we can use it! utxos = util.api('get_unspent_txouts', { "address": alice, "unconfirmed": True }) assert len(utxos) == 1 assert utxos[0]['address'] == alice assert utxos[0]['txid'] == tx3['tx_hash'] assert utxos[0]['amount'] == 1.99873125 assert utxos[0]['confirmations'] == 0 # atm there's no way to confirm this unconfirmed TX # even doing this won't make it confirmed because it just mocks an empty block util_test.create_next_block(server_db) utxos = util.api('get_unspent_txouts', {"address": alice}) assert len(utxos) == 1 assert utxos[0]['address'] == alice assert utxos[0]['txid'] == tx3['tx_hash'] assert utxos[0]['amount'] == 1.99873125 assert utxos[0]['confirmations'] == 1 # we can eventually make this mocking better to be able to do that, # but for now you'll have to micro manage if you want to confirm a unconfirmed TX in 1 test # by just calling the `insert_raw_transaction` again for it tx3bhash, tx3b = util_test.insert_raw_transaction(send3hex, server_db) # balances after send alice_balance2 = util.get_balance(server_db, alice, 'XCP') bob_balance2 = util.get_balance(server_db, bob, 'XCP') assert alice_balance2 == alice_balance - v assert bob_balance2 == bob_balance + v