mirror of
https://github.com/basicswap/basicswap.git
synced 2025-11-06 02:38:11 +01:00
ui: Expose bid valid for.
Set smsgsregtestadjust to false in tests. Fix offer smsg valid for. Set active_ind on bid records. api: All times returned should be in unix-time.
This commit is contained in:
@@ -100,12 +100,6 @@ import basicswap.network as bsn
|
||||
import basicswap.protocols.atomic_swap_1 as atomic_swap_1
|
||||
|
||||
|
||||
MIN_OFFER_VALID_TIME = 60 * 10
|
||||
MAX_OFFER_VALID_TIME = 60 * 60 * 48
|
||||
MIN_BID_VALID_TIME = 60 * 10
|
||||
MAX_BID_VALID_TIME = 60 * 60 * 48
|
||||
|
||||
|
||||
class MessageTypes(IntEnum):
|
||||
OFFER = auto()
|
||||
BID = auto()
|
||||
@@ -228,9 +222,6 @@ class DebugTypes(IntEnum):
|
||||
MAKE_INVALID_PTX = auto()
|
||||
|
||||
|
||||
INITIATE_TX_TIMEOUT = 40 * 60 # TODO: make variable per coin
|
||||
|
||||
|
||||
def strOfferState(state):
|
||||
if state == OfferStates.OFFER_SENT:
|
||||
return 'Sent'
|
||||
@@ -477,7 +468,7 @@ class BasicSwap(BaseApp):
|
||||
|
||||
self.swaps_in_progress = dict()
|
||||
|
||||
self.SMSG_SECONDS_IN_HOUR = 60 * 2 if self.chain == 'regtest' else 60 * 60
|
||||
self.SMSG_SECONDS_IN_HOUR = 60 * 60 # Note: Set smsgsregtestadjust=0 for regtest
|
||||
|
||||
self.delay_event = threading.Event()
|
||||
self.threads = []
|
||||
@@ -1102,12 +1093,20 @@ class BasicSwap(BaseApp):
|
||||
else:
|
||||
raise ValueError('Unknown locktype')
|
||||
|
||||
def validateOfferValidTime(self, coin_from, coin_to, valid_for_seconds):
|
||||
if valid_for_seconds < 60 * 60: # SMSG_MIN_TTL
|
||||
def validateOfferValidTime(self, offer_type, coin_from, coin_to, valid_for_seconds):
|
||||
# TODO: adjust
|
||||
if valid_for_seconds < 10 * 60:
|
||||
raise ValueError('Offer TTL too low')
|
||||
if valid_for_seconds > 48 * 60 * 60:
|
||||
raise ValueError('Offer TTL too high')
|
||||
|
||||
def validateBidValidTime(self, offer_type, coin_from, coin_to, valid_for_seconds):
|
||||
# TODO: adjust
|
||||
if valid_for_seconds < 10 * 60:
|
||||
raise ValueError('Bid TTL too low')
|
||||
if valid_for_seconds > 24 * 60 * 60:
|
||||
raise ValueError('Bid TTL too high')
|
||||
|
||||
def postOffer(self, coin_from, coin_to, amount, rate, min_bid_amount, swap_type,
|
||||
lock_type=SEQUENCE_LOCK_TIME, lock_value=48 * 60 * 60, auto_accept_bids=False, addr_send_from=None, extra_options={}):
|
||||
# Offer to send offer.amount_from of coin_from in exchange for offer.amount_from * offer.rate of coin_to
|
||||
@@ -1129,7 +1128,7 @@ class BasicSwap(BaseApp):
|
||||
self.validateSwapType(coin_from_t, coin_to_t, swap_type)
|
||||
self.validateOfferAmounts(coin_from_t, coin_to_t, amount, rate, min_bid_amount)
|
||||
self.validateOfferLockValue(coin_from_t, coin_to_t, lock_type, lock_value)
|
||||
self.validateOfferValidTime(coin_from_t, coin_to_t, valid_for_seconds)
|
||||
self.validateOfferValidTime(swap_type, coin_from_t, coin_to_t, valid_for_seconds)
|
||||
|
||||
self.mxDB.acquire()
|
||||
session = None
|
||||
@@ -1196,7 +1195,7 @@ class BasicSwap(BaseApp):
|
||||
|
||||
self.callrpc('smsgaddlocaladdress', [offer_addr]) # Enable receiving smsg
|
||||
options = {'decodehex': True, 'ttl_is_seconds': True}
|
||||
msg_valid = self.SMSG_SECONDS_IN_HOUR * 1
|
||||
msg_valid = max(self.SMSG_SECONDS_IN_HOUR * 1, valid_for_seconds)
|
||||
ro = self.callrpc('smsgsend', [offer_addr, self.network_addr, payload_hex, False, msg_valid, False, options])
|
||||
msg_id = ro['msgid']
|
||||
|
||||
@@ -1725,13 +1724,16 @@ class BasicSwap(BaseApp):
|
||||
assert(offer.expire_at > int(time.time())), 'Offer has expired'
|
||||
|
||||
if offer.swap_type == SwapTypes.XMR_SWAP:
|
||||
return self.postXmrBid(offer_id, amount, addr_send_from)
|
||||
return self.postXmrBid(offer_id, amount, addr_send_from, extra_options)
|
||||
|
||||
valid_for_seconds = extra_options.get('valid_for_seconds', 60 * 10)
|
||||
self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, valid_for_seconds)
|
||||
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
msg_buf = BidMessage()
|
||||
msg_buf.offer_msg_id = offer_id
|
||||
msg_buf.time_valid = extra_options.get('time_valid', 60 * 10)
|
||||
msg_buf.time_valid = valid_for_seconds
|
||||
msg_buf.amount = int(amount) # amount of coin_from
|
||||
|
||||
coin_from = Coins(offer.coin_from)
|
||||
@@ -1762,12 +1764,13 @@ class BasicSwap(BaseApp):
|
||||
bid_addr = addr_send_from
|
||||
self.callrpc('smsgaddlocaladdress', [bid_addr]) # Enable receiving smsg
|
||||
options = {'decodehex': True, 'ttl_is_seconds': True}
|
||||
msg_valid = self.SMSG_SECONDS_IN_HOUR * 1
|
||||
msg_valid = max(self.SMSG_SECONDS_IN_HOUR * 1, valid_for_seconds)
|
||||
ro = self.callrpc('smsgsend', [bid_addr, offer.addr_from, payload_hex, False, msg_valid, False, options])
|
||||
msg_id = ro['msgid']
|
||||
|
||||
bid_id = bytes.fromhex(msg_id)
|
||||
bid = Bid(
|
||||
active_ind=1,
|
||||
bid_id=bid_id,
|
||||
offer_id=offer_id,
|
||||
amount=msg_buf.amount,
|
||||
@@ -2031,7 +2034,7 @@ class BasicSwap(BaseApp):
|
||||
self.saveBid(bid_id, bid)
|
||||
self.swaps_in_progress[bid_id] = (bid, offer)
|
||||
|
||||
def postXmrBid(self, offer_id, amount, addr_send_from=None):
|
||||
def postXmrBid(self, offer_id, amount, addr_send_from=None, extra_options={}):
|
||||
# Bid to send bid.amount * offer.rate of coin_to in exchange for bid.amount of coin_from
|
||||
# Send MSG1L F -> L
|
||||
self.log.debug('postXmrBid %s', offer_id.hex())
|
||||
@@ -2044,6 +2047,9 @@ class BasicSwap(BaseApp):
|
||||
assert(xmr_offer), 'XMR offer not found: {}.'.format(offer_id.hex())
|
||||
assert(offer.expire_at > int(time.time())), 'Offer has expired'
|
||||
|
||||
valid_for_seconds = extra_options.get('valid_for_seconds', 60 * 10)
|
||||
self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, valid_for_seconds)
|
||||
|
||||
coin_from = Coins(offer.coin_from)
|
||||
coin_to = Coins(offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
@@ -2053,7 +2059,7 @@ class BasicSwap(BaseApp):
|
||||
|
||||
msg_buf = XmrBidMessage()
|
||||
msg_buf.offer_msg_id = offer_id
|
||||
msg_buf.time_valid = 60 * 10
|
||||
msg_buf.time_valid = valid_for_seconds
|
||||
msg_buf.amount = int(amount) # Amount of coin_from
|
||||
|
||||
address_out = self.getReceiveAddressFromPool(coin_from, offer_id, TxTypes.XMR_SWAP_A_LOCK)
|
||||
@@ -2110,7 +2116,7 @@ class BasicSwap(BaseApp):
|
||||
bid_addr = addr_send_from
|
||||
self.callrpc('smsgaddlocaladdress', [bid_addr]) # Enable receiving smsg
|
||||
options = {'decodehex': True, 'ttl_is_seconds': True}
|
||||
msg_valid = self.SMSG_SECONDS_IN_HOUR * 1
|
||||
msg_valid = max(self.SMSG_SECONDS_IN_HOUR * 1, valid_for_seconds)
|
||||
ro = self.callrpc('smsgsend', [bid_addr, offer.addr_from, payload_hex, False, msg_valid, False, options])
|
||||
xmr_swap.bid_id = bytes.fromhex(ro['msgid'])
|
||||
|
||||
@@ -2138,6 +2144,7 @@ class BasicSwap(BaseApp):
|
||||
xmr_swap.bid_msg_id3 = bytes.fromhex(ro['msgid'])
|
||||
|
||||
bid = Bid(
|
||||
active_ind=1,
|
||||
bid_id=xmr_swap.bid_id,
|
||||
offer_id=offer_id,
|
||||
amount=msg_buf.amount,
|
||||
@@ -3135,7 +3142,7 @@ class BasicSwap(BaseApp):
|
||||
|
||||
# Bid times out if buyer doesn't see tx in chain within INITIATE_TX_TIMEOUT seconds
|
||||
if bid.initiate_tx is None and \
|
||||
bid.state_time + INITIATE_TX_TIMEOUT < int(time.time()):
|
||||
bid.state_time + atomic_swap_1.INITIATE_TX_TIMEOUT < int(time.time()):
|
||||
self.log.info('Swap timed out waiting for initiate tx for bid %s', bid_id.hex())
|
||||
bid.setState(BidStates.SWAP_TIMEDOUT, 'Timed out waiting for initiate tx')
|
||||
self.saveBid(bid_id, bid)
|
||||
@@ -3630,9 +3637,8 @@ class BasicSwap(BaseApp):
|
||||
self.validateSwapType(coin_from, coin_to, offer_data.swap_type)
|
||||
self.validateOfferAmounts(coin_from, coin_to, offer_data.amount_from, offer_data.rate, offer_data.min_bid_amount)
|
||||
self.validateOfferLockValue(coin_from, coin_to, offer_data.lock_type, offer_data.lock_value)
|
||||
self.validateOfferValidTime(coin_from, coin_to, offer_data.time_valid)
|
||||
self.validateOfferValidTime(offer_data.swap_type, coin_from, coin_to, offer_data.time_valid)
|
||||
|
||||
assert(offer_data.time_valid >= MIN_OFFER_VALID_TIME and offer_data.time_valid <= MAX_OFFER_VALID_TIME), 'Invalid time_valid'
|
||||
assert(msg['sent'] + offer_data.time_valid >= now), 'Offer expired'
|
||||
|
||||
if offer_data.swap_type == SwapTypes.SELLER_FIRST:
|
||||
@@ -3752,17 +3758,17 @@ class BasicSwap(BaseApp):
|
||||
|
||||
# Validate data
|
||||
assert(len(bid_data.offer_msg_id) == 28), 'Bad offer_id length'
|
||||
assert(bid_data.time_valid >= MIN_BID_VALID_TIME and bid_data.time_valid <= MAX_BID_VALID_TIME), 'Invalid time_valid'
|
||||
|
||||
offer_id = bid_data.offer_msg_id
|
||||
offer = self.getOffer(offer_id, sent=True)
|
||||
assert(offer and offer.was_sent), 'Unknown offerid'
|
||||
assert(offer and offer.was_sent), 'Unknown offer'
|
||||
|
||||
assert(offer.state == OfferStates.OFFER_RECEIVED), 'Bad offer state'
|
||||
assert(msg['to'] == offer.addr_from), 'Received on incorrect address'
|
||||
assert(now <= offer.expire_at), 'Offer expired'
|
||||
assert(bid_data.amount >= offer.min_bid_amount), 'Bid amount below minimum'
|
||||
assert(bid_data.amount <= offer.amount_from), 'Bid amount above offer amount'
|
||||
self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, bid_data.time_valid)
|
||||
assert(now <= msg['sent'] + bid_data.time_valid), 'Bid expired'
|
||||
|
||||
# TODO: Allow higher bids
|
||||
@@ -3800,6 +3806,7 @@ class BasicSwap(BaseApp):
|
||||
bid = self.getBid(bid_id)
|
||||
if bid is None:
|
||||
bid = Bid(
|
||||
active_ind=1,
|
||||
bid_id=bid_id,
|
||||
offer_id=offer_id,
|
||||
amount=bid_data.amount,
|
||||
@@ -3885,7 +3892,7 @@ class BasicSwap(BaseApp):
|
||||
if offer.lock_type == ABS_LOCK_BLOCKS:
|
||||
self.log.warning('TODO: validate absolute lock values')
|
||||
else:
|
||||
assert(script_lock_value <= bid.created_at + offer.lock_value + INITIATE_TX_TIMEOUT), 'script lock time too high'
|
||||
assert(script_lock_value <= bid.created_at + offer.lock_value + atomic_swap_1.INITIATE_TX_TIMEOUT), 'script lock time too high'
|
||||
assert(script_lock_value >= bid.created_at + offer.lock_value), 'script lock time too low'
|
||||
|
||||
assert(len(scriptvalues[3]) == 40), 'pkhash_refund bad length'
|
||||
@@ -4033,12 +4040,12 @@ class BasicSwap(BaseApp):
|
||||
|
||||
# Validate data
|
||||
assert(len(bid_data.offer_msg_id) == 28), 'Bad offer_id length'
|
||||
assert(bid_data.time_valid >= MIN_BID_VALID_TIME and bid_data.time_valid <= MAX_BID_VALID_TIME), 'Invalid time_valid'
|
||||
|
||||
offer_id = bid_data.offer_msg_id
|
||||
offer, xmr_offer = self.getXmrOffer(offer_id, sent=True)
|
||||
assert(offer and offer.was_sent), 'Offer not found: {}.'.format(offer_id.hex())
|
||||
assert(xmr_offer), 'XMR offer not found: {}.'.format(offer_id.hex())
|
||||
|
||||
ci_from = self.ci(offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_to)
|
||||
|
||||
@@ -4047,10 +4054,9 @@ class BasicSwap(BaseApp):
|
||||
assert(now <= offer.expire_at), 'Offer expired'
|
||||
assert(bid_data.amount >= offer.min_bid_amount), 'Bid amount below minimum'
|
||||
assert(bid_data.amount <= offer.amount_from), 'Bid amount above offer amount'
|
||||
self.validateBidValidTime(offer.swap_type, offer.coin_from, offer.coin_to, bid_data.time_valid)
|
||||
assert(now <= msg['sent'] + bid_data.time_valid), 'Bid expired'
|
||||
|
||||
self.log.debug('TODO: xmr bid validation')
|
||||
|
||||
assert(ci_to.verifyKey(bid_data.kbvf))
|
||||
assert(ci_from.verifyPubkey(bid_data.pkaf))
|
||||
|
||||
@@ -4059,6 +4065,7 @@ class BasicSwap(BaseApp):
|
||||
bid, xmr_swap = self.getXmrBid(bid_id)
|
||||
if bid is None:
|
||||
bid = Bid(
|
||||
active_ind=1,
|
||||
bid_id=bid_id,
|
||||
offer_id=offer_id,
|
||||
amount=bid_data.amount,
|
||||
@@ -4839,6 +4846,8 @@ class BasicSwap(BaseApp):
|
||||
|
||||
if now - self._last_checked_watched >= self.check_watched_seconds:
|
||||
for k, c in self.coin_clients.items():
|
||||
if k == Coins.PART_ANON:
|
||||
continue
|
||||
if len(c['watched_outputs']) > 0:
|
||||
self.checkForSpends(k, c)
|
||||
self._last_checked_watched = now
|
||||
@@ -5132,25 +5141,29 @@ class BasicSwap(BaseApp):
|
||||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def listBids(self, sent=False, offer_id=None, for_html=False):
|
||||
def listBids(self, sent=False, offer_id=None, for_html=False, filters={}):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
rv = []
|
||||
now = int(time.time())
|
||||
session = scoped_session(self.session_factory)
|
||||
|
||||
query_str = 'SELECT bids.created_at, bids.bid_id, bids.offer_id, bids.amount, bids.state, bids.was_received, tx1.state, tx2.state, offers.coin_from FROM bids ' + \
|
||||
query_str = 'SELECT bids.created_at, bids.expire_at, bids.bid_id, bids.offer_id, bids.amount, bids.state, bids.was_received, tx1.state, tx2.state, offers.coin_from FROM bids ' + \
|
||||
'LEFT JOIN offers ON offers.offer_id = bids.offer_id ' + \
|
||||
'LEFT JOIN transactions AS tx1 ON tx1.bid_id = bids.bid_id AND tx1.tx_type = {} '.format(TxTypes.ITX) + \
|
||||
'LEFT JOIN transactions AS tx2 ON tx2.bid_id = bids.bid_id AND tx2.tx_type = {} '.format(TxTypes.PTX)
|
||||
|
||||
query_str += 'WHERE bids.active_ind = 1 '
|
||||
filter_bid_id = filters.get('bid_id', None)
|
||||
if filter_bid_id is not None:
|
||||
query_str += 'AND bids.bid_id = x\'{}\' '.format(filter_bid_id.hex())
|
||||
if offer_id is not None:
|
||||
query_str += 'WHERE bids.offer_id = x\'{}\' '.format(offer_id.hex())
|
||||
query_str += 'AND bids.offer_id = x\'{}\' '.format(offer_id.hex())
|
||||
elif sent:
|
||||
query_str += 'WHERE bids.was_sent = 1 '
|
||||
query_str += 'AND bids.was_sent = 1 '
|
||||
else:
|
||||
query_str += 'WHERE bids.was_received = 1 '
|
||||
query_str += 'ORDER BY bids.created_at DESC'
|
||||
query_str += 'AND bids.was_received = 1 '
|
||||
query_str += ' ORDER BY bids.created_at DESC'
|
||||
|
||||
q = session.execute(query_str)
|
||||
for row in q:
|
||||
|
||||
Reference in New Issue
Block a user