Check for duplicate pubkeys.
Add test for 'non-BIP68-final'.
This commit is contained in:
parent
4bde19fe33
commit
645571e47c
@ -36,7 +36,6 @@ from .util import (
|
|||||||
format_amount,
|
format_amount,
|
||||||
encodeAddress,
|
encodeAddress,
|
||||||
decodeAddress,
|
decodeAddress,
|
||||||
SerialiseNum,
|
|
||||||
DeserialiseNum,
|
DeserialiseNum,
|
||||||
decodeWif,
|
decodeWif,
|
||||||
toWIF,
|
toWIF,
|
||||||
@ -80,10 +79,14 @@ from .db import (
|
|||||||
XmrSwap,
|
XmrSwap,
|
||||||
XmrSplitData,
|
XmrSplitData,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .explorers import ExplorerInsight, ExplorerBitAps, ExplorerChainz
|
|
||||||
import basicswap.config as cfg
|
|
||||||
from .base import BaseApp
|
from .base import BaseApp
|
||||||
|
from .explorers import (
|
||||||
|
ExplorerInsight,
|
||||||
|
ExplorerBitAps,
|
||||||
|
ExplorerChainz,
|
||||||
|
)
|
||||||
|
import basicswap.config as cfg
|
||||||
|
import basicswap.protocols.atomic_swap_1 as atomic_swap_1
|
||||||
|
|
||||||
|
|
||||||
MIN_OFFER_VALID_TIME = 60 * 10
|
MIN_OFFER_VALID_TIME = 60 * 10
|
||||||
@ -348,37 +351,6 @@ def decodeSequence(lock_value):
|
|||||||
return lock_value & SEQUENCE_LOCKTIME_MASK
|
return lock_value & SEQUENCE_LOCKTIME_MASK
|
||||||
|
|
||||||
|
|
||||||
def buildContractScript(lock_val, secret_hash, pkh_redeem, pkh_refund, op_lock=OpCodes.OP_CHECKSEQUENCEVERIFY):
|
|
||||||
script = bytearray([
|
|
||||||
OpCodes.OP_IF,
|
|
||||||
OpCodes.OP_SIZE,
|
|
||||||
0x01, 0x20, # 32
|
|
||||||
OpCodes.OP_EQUALVERIFY,
|
|
||||||
OpCodes.OP_SHA256,
|
|
||||||
0x20]) \
|
|
||||||
+ secret_hash \
|
|
||||||
+ bytearray([
|
|
||||||
OpCodes.OP_EQUALVERIFY,
|
|
||||||
OpCodes.OP_DUP,
|
|
||||||
OpCodes.OP_HASH160,
|
|
||||||
0x14]) \
|
|
||||||
+ pkh_redeem \
|
|
||||||
+ bytearray([OpCodes.OP_ELSE, ]) \
|
|
||||||
+ SerialiseNum(lock_val) \
|
|
||||||
+ bytearray([
|
|
||||||
op_lock,
|
|
||||||
OpCodes.OP_DROP,
|
|
||||||
OpCodes.OP_DUP,
|
|
||||||
OpCodes.OP_HASH160,
|
|
||||||
0x14]) \
|
|
||||||
+ pkh_refund \
|
|
||||||
+ bytearray([
|
|
||||||
OpCodes.OP_ENDIF,
|
|
||||||
OpCodes.OP_EQUALVERIFY,
|
|
||||||
OpCodes.OP_CHECKSIG])
|
|
||||||
return script
|
|
||||||
|
|
||||||
|
|
||||||
def extractScriptSecretHash(script):
|
def extractScriptSecretHash(script):
|
||||||
return script[7:39]
|
return script[7:39]
|
||||||
|
|
||||||
@ -748,7 +720,7 @@ class BasicSwap(BaseApp):
|
|||||||
self.db_version = db_version
|
self.db_version = db_version
|
||||||
kv = session.query(DBKVInt).filter_by(key='db_version').first()
|
kv = session.query(DBKVInt).filter_by(key='db_version').first()
|
||||||
if not kv:
|
if not kv:
|
||||||
kv = DBKVInt(key=str_key, value=db_version)
|
kv = DBKVInt(key='db_version', value=db_version)
|
||||||
else:
|
else:
|
||||||
kv.value = db_version
|
kv.value = db_version
|
||||||
session.add(kv)
|
session.add(kv)
|
||||||
@ -1658,14 +1630,14 @@ class BasicSwap(BaseApp):
|
|||||||
else:
|
else:
|
||||||
if offer.lock_type < ABS_LOCK_BLOCKS:
|
if offer.lock_type < ABS_LOCK_BLOCKS:
|
||||||
sequence = getExpectedSequence(offer.lock_type, offer.lock_value, coin_from)
|
sequence = getExpectedSequence(offer.lock_type, offer.lock_value, coin_from)
|
||||||
script = buildContractScript(sequence, secret_hash, bid.pkhash_buyer, pkhash_refund)
|
script = atomic_swap_1.buildContractScript(sequence, secret_hash, bid.pkhash_buyer, pkhash_refund)
|
||||||
else:
|
else:
|
||||||
if offer.lock_type == ABS_LOCK_BLOCKS:
|
if offer.lock_type == ABS_LOCK_BLOCKS:
|
||||||
lock_value = self.callcoinrpc(coin_from, 'getblockchaininfo')['blocks'] + offer.lock_value
|
lock_value = self.callcoinrpc(coin_from, 'getblockchaininfo')['blocks'] + offer.lock_value
|
||||||
else:
|
else:
|
||||||
lock_value = int(time.time()) + offer.lock_value
|
lock_value = int(time.time()) + offer.lock_value
|
||||||
self.log.debug('Initiate %s lock_value %d %d', coin_from, offer.lock_value, lock_value)
|
self.log.debug('Initiate %s lock_value %d %d', coin_from, offer.lock_value, lock_value)
|
||||||
script = buildContractScript(lock_value, secret_hash, bid.pkhash_buyer, pkhash_refund, OpCodes.OP_CHECKLOCKTIMEVERIFY)
|
script = atomic_swap_1.buildContractScript(lock_value, secret_hash, bid.pkhash_buyer, pkhash_refund, OpCodes.OP_CHECKLOCKTIMEVERIFY)
|
||||||
|
|
||||||
p2sh = self.callcoinrpc(Coins.PART, 'decodescript', [script.hex()])['p2sh']
|
p2sh = self.callcoinrpc(Coins.PART, 'decodescript', [script.hex()])['p2sh']
|
||||||
|
|
||||||
@ -2061,7 +2033,7 @@ class BasicSwap(BaseApp):
|
|||||||
lock_value = offer.lock_value // 2
|
lock_value = offer.lock_value // 2
|
||||||
if offer.lock_type < ABS_LOCK_BLOCKS:
|
if offer.lock_type < ABS_LOCK_BLOCKS:
|
||||||
sequence = getExpectedSequence(offer.lock_type, lock_value, coin_to)
|
sequence = getExpectedSequence(offer.lock_type, lock_value, coin_to)
|
||||||
participate_script = buildContractScript(sequence, secret_hash, pkhash_seller, pkhash_buyer_refund)
|
participate_script = atomic_swap_1.buildContractScript(sequence, secret_hash, pkhash_seller, pkhash_buyer_refund)
|
||||||
else:
|
else:
|
||||||
# Lock from the height or time of the block containing the initiate txn
|
# Lock from the height or time of the block containing the initiate txn
|
||||||
coin_from = Coins(offer.coin_from)
|
coin_from = Coins(offer.coin_from)
|
||||||
@ -2092,7 +2064,7 @@ class BasicSwap(BaseApp):
|
|||||||
self.log.debug('Setting lock value from time of block %s %s', coin_from, initiate_tx_block_hash)
|
self.log.debug('Setting lock value from time of block %s %s', coin_from, initiate_tx_block_hash)
|
||||||
contract_lock_value = initiate_tx_block_time + lock_value
|
contract_lock_value = initiate_tx_block_time + lock_value
|
||||||
self.log.debug('participate %s lock_value %d %d', coin_to, lock_value, contract_lock_value)
|
self.log.debug('participate %s lock_value %d %d', coin_to, lock_value, contract_lock_value)
|
||||||
participate_script = buildContractScript(contract_lock_value, secret_hash, pkhash_seller, pkhash_buyer_refund, OpCodes.OP_CHECKLOCKTIMEVERIFY)
|
participate_script = atomic_swap_1.buildContractScript(contract_lock_value, secret_hash, pkhash_seller, pkhash_buyer_refund, OpCodes.OP_CHECKLOCKTIMEVERIFY)
|
||||||
return participate_script
|
return participate_script
|
||||||
|
|
||||||
def createParticipateTxn(self, bid_id, bid, offer, participate_script):
|
def createParticipateTxn(self, bid_id, bid, offer, participate_script):
|
||||||
@ -3630,6 +3602,15 @@ class BasicSwap(BaseApp):
|
|||||||
if not ci_from.verifyPubkey(xmr_swap.pkarl):
|
if not ci_from.verifyPubkey(xmr_swap.pkarl):
|
||||||
raise ValueError('Invalid pubkey.')
|
raise ValueError('Invalid pubkey.')
|
||||||
|
|
||||||
|
if xmr_swap.pkbvl == xmr_swap.pkbvf:
|
||||||
|
raise ValueError('Duplicate scriptless view pubkey.')
|
||||||
|
if xmr_swap.pkbsl == xmr_swap.pkbsf:
|
||||||
|
raise ValueError('Duplicate scriptless spend pubkey.')
|
||||||
|
if xmr_swap.pkal == xmr_swap.pkaf:
|
||||||
|
raise ValueError('Duplicate script spend pubkey.')
|
||||||
|
if xmr_swap.pkarl == xmr_swap.pkarf:
|
||||||
|
raise ValueError('Duplicate script spend pubkey.')
|
||||||
|
|
||||||
bid.setState(BidStates.SWAP_DELAYING)
|
bid.setState(BidStates.SWAP_DELAYING)
|
||||||
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
||||||
|
|
||||||
|
@ -19,13 +19,14 @@ class ECCParameters():
|
|||||||
self.o = o
|
self.o = o
|
||||||
|
|
||||||
|
|
||||||
ep = ECCParameters( \
|
ep = ECCParameters(
|
||||||
p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, \
|
p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
|
||||||
a = 0x0, \
|
a=0x0,
|
||||||
b = 0x7, \
|
b=0x7,
|
||||||
Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, \
|
Gx=0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
|
||||||
Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, \
|
Gy=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
|
||||||
o = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141) # noqa: E221,E251,E502
|
o=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141)
|
||||||
|
|
||||||
|
|
||||||
curve_secp256k1 = CurveFp(ep.p, ep.a, ep.b)
|
curve_secp256k1 = CurveFp(ep.p, ep.a, ep.b)
|
||||||
G = Point(curve_secp256k1, ep.Gx, ep.Gy, ep.o)
|
G = Point(curve_secp256k1, ep.Gx, ep.Gy, ep.o)
|
||||||
|
@ -670,7 +670,7 @@ class BTCInterface(CoinInterface):
|
|||||||
assert_cond(tx.vin[0].prevout.hash == b2i(lock_tx_id) and tx.vin[0].prevout.n == locked_n, 'Input prevout mismatch')
|
assert_cond(tx.vin[0].prevout.hash == b2i(lock_tx_id) and tx.vin[0].prevout.n == locked_n, 'Input prevout mismatch')
|
||||||
|
|
||||||
assert_cond(len(tx.vout) == 1, 'tx doesn\'t have one output')
|
assert_cond(len(tx.vout) == 1, 'tx doesn\'t have one output')
|
||||||
p2wpkh = self.getScriptForPubkeyHash(a_pkhash_f)
|
p2wpkh = self.getScriptForPubkeyHash(a_pkhash_f)
|
||||||
assert_cond(tx.vout[0].scriptPubKey == p2wpkh, 'Bad output destination')
|
assert_cond(tx.vout[0].scriptPubKey == p2wpkh, 'Bad output destination')
|
||||||
|
|
||||||
fee_paid = locked_coin - tx.vout[0].nValue
|
fee_paid = locked_coin - tx.vout[0].nValue
|
||||||
|
@ -159,6 +159,8 @@ class XMRInterface(CoinInterface):
|
|||||||
return(i < edf.l and i > 8)
|
return(i < edf.l and i > 8)
|
||||||
|
|
||||||
def verifyPubkey(self, pubkey_bytes):
|
def verifyPubkey(self, pubkey_bytes):
|
||||||
|
# Calls ed25519_decode_check_point() in secp256k1
|
||||||
|
# Checks for small order
|
||||||
return verify_ed25519_point(pubkey_bytes)
|
return verify_ed25519_point(pubkey_bytes)
|
||||||
|
|
||||||
def proveDLEAG(self, key):
|
def proveDLEAG(self, key):
|
||||||
@ -240,13 +242,13 @@ class XMRInterface(CoinInterface):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.info('rpc_cb failed %s', str(e))
|
logging.info('rpc_cb failed %s', str(e))
|
||||||
current_height = None # If the transfer is available it will be deep enough
|
current_height = None # If the transfer is available it will be deep enough
|
||||||
|
# and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
|
||||||
'''
|
'''
|
||||||
params = {'transfer_type': 'available'}
|
params = {'transfer_type': 'available'}
|
||||||
rv = self.rpc_wallet_cb('incoming_transfers', params)
|
rv = self.rpc_wallet_cb('incoming_transfers', params)
|
||||||
if 'transfers' in rv:
|
if 'transfers' in rv:
|
||||||
for transfer in rv['transfers']:
|
for transfer in rv['transfers']:
|
||||||
if transfer['amount'] == cb_swap_value:
|
if transfer['amount'] == cb_swap_value:
|
||||||
# and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
|
|
||||||
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
|
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
|
||||||
else:
|
else:
|
||||||
logging.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))
|
logging.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))
|
||||||
|
0
basicswap/protocols/__init__.py
Normal file
0
basicswap/protocols/__init__.py
Normal file
43
basicswap/protocols/atomic_swap_1.py
Normal file
43
basicswap/protocols/atomic_swap_1.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2020 tecnovert
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
from basicswap.util import (
|
||||||
|
SerialiseNum,
|
||||||
|
)
|
||||||
|
from basicswap.script import (
|
||||||
|
OpCodes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def buildContractScript(lock_val, secret_hash, pkh_redeem, pkh_refund, op_lock=OpCodes.OP_CHECKSEQUENCEVERIFY):
|
||||||
|
script = bytearray([
|
||||||
|
OpCodes.OP_IF,
|
||||||
|
OpCodes.OP_SIZE,
|
||||||
|
0x01, 0x20, # 32
|
||||||
|
OpCodes.OP_EQUALVERIFY,
|
||||||
|
OpCodes.OP_SHA256,
|
||||||
|
0x20]) \
|
||||||
|
+ secret_hash \
|
||||||
|
+ bytearray([
|
||||||
|
OpCodes.OP_EQUALVERIFY,
|
||||||
|
OpCodes.OP_DUP,
|
||||||
|
OpCodes.OP_HASH160,
|
||||||
|
0x14]) \
|
||||||
|
+ pkh_redeem \
|
||||||
|
+ bytearray([OpCodes.OP_ELSE, ]) \
|
||||||
|
+ SerialiseNum(lock_val) \
|
||||||
|
+ bytearray([
|
||||||
|
op_lock,
|
||||||
|
OpCodes.OP_DROP,
|
||||||
|
OpCodes.OP_DUP,
|
||||||
|
OpCodes.OP_HASH160,
|
||||||
|
0x14]) \
|
||||||
|
+ pkh_refund \
|
||||||
|
+ bytearray([
|
||||||
|
OpCodes.OP_ENDIF,
|
||||||
|
OpCodes.OP_EQUALVERIFY,
|
||||||
|
OpCodes.OP_CHECKSIG])
|
||||||
|
return script
|
5
basicswap/protocols/xmr_swap_1.py
Normal file
5
basicswap/protocols/xmr_swap_1.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2020 tecnovert
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
@ -760,6 +760,36 @@ class Test(unittest.TestCase):
|
|||||||
self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
|
self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
|
||||||
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
|
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
|
||||||
|
|
||||||
|
def test_10_locked_refundtx(self):
|
||||||
|
logging.info('---------- Test Refund tx is locked')
|
||||||
|
swap_clients = self.swap_clients
|
||||||
|
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP)
|
||||||
|
self.wait_for_offer(swap_clients[1], offer_id)
|
||||||
|
offers = swap_clients[1].listOffers(filters={'offer_id': offer_id})
|
||||||
|
offer = offers[0]
|
||||||
|
|
||||||
|
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
|
||||||
|
|
||||||
|
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED)
|
||||||
|
|
||||||
|
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
|
||||||
|
assert(xmr_swap)
|
||||||
|
|
||||||
|
swap_clients[1].setBidDebugInd(bid_id, DebugTypes.BID_STOP_AFTER_COIN_A_LOCK)
|
||||||
|
|
||||||
|
swap_clients[0].acceptXmrBid(bid_id)
|
||||||
|
|
||||||
|
self.wait_for_bid(swap_clients[0], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, wait_for=180)
|
||||||
|
|
||||||
|
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
|
||||||
|
assert(xmr_swap)
|
||||||
|
|
||||||
|
try:
|
||||||
|
swap_clients[0].ci(Coins.BTC).publishTx(xmr_swap.a_lock_refund_tx)
|
||||||
|
assert(False), 'Lock refund tx should be locked'
|
||||||
|
except Exception as e:
|
||||||
|
assert('non-BIP68-final' in str(e))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
Reference in New Issue
Block a user