def compose(db, source, order_match_id): tx0_hash, tx1_hash = order_match_id[:64], order_match_id[ 64:] # UTF-8 encoding means that the indices are doubled. destination, btc_quantity, escrowed_asset, escrowed_quantity, order_match, problems = validate( db, source, order_match_id, util.last_block(db)['block_index']) if problems: raise exceptions.ComposeError(problems) # Warn if down to the wire. time_left = order_match['match_expire_index'] - util.last_block( db)['block_index'] if time_left < 4: logging.warning( 'WARNING: Only {} blocks until that order match expires. The payment might not make into the blockchain in time.' .format(time_left)) if 10 - time_left < 4: logging.warning( 'WARNING: Order match has only {} confirmation(s).'.format( 10 - time_left)) tx0_hash_bytes, tx1_hash_bytes = binascii.unhexlify( bytes(tx0_hash, 'utf-8')), binascii.unhexlify(bytes(tx1_hash, 'utf-8')) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, tx0_hash_bytes, tx1_hash_bytes) return (source, [(destination, btc_quantity)], data)
def compose (db, source, fraction, asset): call_price, callback_total, outputs, problems = validate(db, source, fraction, asset, util.last_block(db)['block_time'], util.last_block(db)['block_index'], parse=False) if problems: raise exceptions.ComposeError(problems) logging.info('Total quantity to be called back: {} {}'.format(util.devise(db, callback_total, asset, 'output'), asset)) asset_id = util.get_asset_id(db, asset, util.last_block(db)['block_index']) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, fraction, asset_id) return (source, [], data)
def compose(db, source, offer_hash): # Check that offer exists. offer, offer_type, problems = validate(db, source, offer_hash) if problems: raise exceptions.ComposeError(problems) offer_hash_bytes = binascii.unhexlify(bytes(offer_hash, 'utf-8')) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, offer_hash_bytes) return (source, [], data)
def compose (db, source, give_asset, give_quantity, get_asset, get_quantity, expiration, fee_required): cursor = db.cursor() # Check balance. if give_asset != config.BTC: balances = list(cursor.execute('''SELECT * FROM balances WHERE (address = ? AND asset = ?)''', (source, give_asset))) if (not balances or balances[0]['quantity'] < give_quantity): raise exceptions.ComposeError('insufficient funds') problems = validate(db, source, give_asset, give_quantity, get_asset, get_quantity, expiration, fee_required, util.last_block(db)['block_index']) if problems: raise exceptions.ComposeError(problems) give_id = util.get_asset_id(db, give_asset, util.last_block(db)['block_index']) get_id = util.get_asset_id(db, get_asset, util.last_block(db)['block_index']) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, give_id, give_quantity, get_id, get_quantity, expiration, fee_required) cursor.close() return (source, [], data)
def compose(db, source, possible_moves, wager, move_random_hash, expiration): problems = validate(db, source, possible_moves, wager, move_random_hash, expiration, util.last_block(db)['block_index']) if problems: raise exceptions.ComposeError(problems) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, possible_moves, wager, binascii.unhexlify(move_random_hash), expiration) return (source, [], data)
def compose (db, source, quantity_per_unit, asset, dividend_asset): dividend_total, outputs, problems, fee = validate(db, source, quantity_per_unit, asset, dividend_asset, util.last_block(db)['block_index']) if problems: raise exceptions.ComposeError(problems) logging.info('Total quantity to be distributed in dividends: {} {}'.format(util.devise(db, dividend_total, dividend_asset, 'output'), dividend_asset)) if dividend_asset == config.BTC: return (source, [(output['address'], output['dividend_quantity']) for output in outputs], None) asset_id = util.get_asset_id(db, asset, util.last_block(db)['block_index']) dividend_asset_id = util.get_asset_id(db, dividend_asset, util.last_block(db)['block_index']) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT_2, quantity_per_unit, asset_id, dividend_asset_id) return (source, [], data)
def compose(db, source, quantity, overburn=False): cursor = db.cursor() destination = config.UNSPENDABLE problems = validate(db, source, destination, quantity, util.last_block(db)['block_index'], overburn=overburn) if problems: raise exceptions.ComposeError(problems) # Check that a maximum of 1 BTC total is burned per address. burns = list( cursor.execute( '''SELECT * FROM burns WHERE (status = ? AND source = ?)''', ('valid', source))) already_burned = sum([burn['burned'] for burn in burns]) if quantity > (1 * config.UNIT - already_burned) and not overburn: raise exceptions.ComposeError('1 {} may be burned per address'.format( config.BTC)) cursor.close() return (source, [(destination, quantity)], None)
def compose(db, source, feed_address, bet_type, deadline, wager_quantity, counterwager_quantity, target_value, leverage, expiration): problems, leverage = validate(db, source, feed_address, bet_type, deadline, wager_quantity, counterwager_quantity, target_value, leverage, expiration, util.last_block(db)['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 compose(db, source, timestamp, value, fee_fraction, text): # Store the fee fraction as an integer. fee_fraction_int = int(fee_fraction * 1e8) problems = validate(db, source, timestamp, value, fee_fraction_int, text, util.last_block(db)['block_index']) if problems: raise exceptions.ComposeError(problems) data = struct.pack(config.TXTYPE_FORMAT, ID) if len(text) <= 52: curr_format = FORMAT + '{}p'.format(len(text) + 1) else: curr_format = FORMAT + '{}s'.format(len(text)) data += struct.pack(curr_format, timestamp, value, fee_fraction_int, text.encode('utf-8')) return (source, [], data)
def compose(db, source, move, random, rps_match_id): tx0_hash, tx1_hash = util.parse_id(rps_match_id) txn, rps_match, problems = validate(db, source, move, random, rps_match_id) if problems: raise exceptions.ComposeError(problems) # Warn if down to the wire. time_left = rps_match['match_expire_index'] - util.last_block( db)['block_index'] if time_left < 4: logger.warning( 'Only {} blocks until that rps match expires. The conclusion might not make into the blockchain in time.' .format(time_left)) tx0_hash_bytes = binascii.unhexlify(bytes(tx0_hash, 'utf-8')) tx1_hash_bytes = binascii.unhexlify(bytes(tx1_hash, 'utf-8')) random_bytes = binascii.unhexlify(bytes(random, 'utf-8')) data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, move, random_bytes, tx0_hash_bytes, tx1_hash_bytes) return (source, [], data)
def compose(db, source, transfer_destination, asset, quantity, divisible, description): callable_, call_date, call_price = False, 0, 0.0 call_date, call_price, problems, fee, description, divisible, reissuance = validate( db, source, transfer_destination, asset, quantity, divisible, callable_, call_date, call_price, description, util.last_block(db)['block_index']) if problems: raise exceptions.ComposeError(problems) asset_id = util.generate_asset_id(asset, util.last_block(db)['block_index']) data = struct.pack(config.TXTYPE_FORMAT, ID) if len(description) <= 42: curr_format = FORMAT_2 + '{}p'.format(len(description) + 1) else: curr_format = FORMAT_2 + '{}s'.format(len(description)) data += struct.pack(curr_format, asset_id, quantity, 1 if divisible else 0, 1 if callable_ else 0, call_date or 0, call_price or 0.0, description.encode('utf-8')) if transfer_destination: destination_outputs = [(transfer_destination, None)] else: destination_outputs = [] return (source, destination_outputs, data)