Check for duplicate pubkeys.

Add test for 'non-BIP68-final'.
This commit is contained in:
tecnovert 2020-12-10 12:07:26 +02:00
parent 4bde19fe33
commit 645571e47c
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
8 changed files with 111 additions and 49 deletions

View File

@ -36,7 +36,6 @@ from .util import (
format_amount,
encodeAddress,
decodeAddress,
SerialiseNum,
DeserialiseNum,
decodeWif,
toWIF,
@ -80,10 +79,14 @@ from .db import (
XmrSwap,
XmrSplitData,
)
from .explorers import ExplorerInsight, ExplorerBitAps, ExplorerChainz
import basicswap.config as cfg
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
@ -348,37 +351,6 @@ def decodeSequence(lock_value):
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):
return script[7:39]
@ -748,7 +720,7 @@ class BasicSwap(BaseApp):
self.db_version = db_version
kv = session.query(DBKVInt).filter_by(key='db_version').first()
if not kv:
kv = DBKVInt(key=str_key, value=db_version)
kv = DBKVInt(key='db_version', value=db_version)
else:
kv.value = db_version
session.add(kv)
@ -1658,14 +1630,14 @@ class BasicSwap(BaseApp):
else:
if offer.lock_type < ABS_LOCK_BLOCKS:
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:
if offer.lock_type == ABS_LOCK_BLOCKS:
lock_value = self.callcoinrpc(coin_from, 'getblockchaininfo')['blocks'] + offer.lock_value
else:
lock_value = int(time.time()) + offer.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']
@ -2061,7 +2033,7 @@ class BasicSwap(BaseApp):
lock_value = offer.lock_value // 2
if offer.lock_type < ABS_LOCK_BLOCKS:
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:
# Lock from the height or time of the block containing the initiate txn
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)
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)
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
def createParticipateTxn(self, bid_id, bid, offer, participate_script):
@ -3630,6 +3602,15 @@ class BasicSwap(BaseApp):
if not ci_from.verifyPubkey(xmr_swap.pkarl):
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)
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)

View File

@ -19,13 +19,14 @@ class ECCParameters():
self.o = o
ep = ECCParameters( \
p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, \
a = 0x0, \
b = 0x7, \
Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, \
Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, \
o = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141) # noqa: E221,E251,E502
ep = ECCParameters(
p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
a=0x0,
b=0x7,
Gx=0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
Gy=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
o=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141)
curve_secp256k1 = CurveFp(ep.p, ep.a, ep.b)
G = Point(curve_secp256k1, ep.Gx, ep.Gy, ep.o)

View File

@ -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(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')
fee_paid = locked_coin - tx.vout[0].nValue

View File

@ -159,6 +159,8 @@ class XMRInterface(CoinInterface):
return(i < edf.l and i > 8)
def verifyPubkey(self, pubkey_bytes):
# Calls ed25519_decode_check_point() in secp256k1
# Checks for small order
return verify_ed25519_point(pubkey_bytes)
def proveDLEAG(self, key):
@ -240,13 +242,13 @@ class XMRInterface(CoinInterface):
except Exception as e:
logging.info('rpc_cb failed %s', str(e))
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'}
rv = self.rpc_wallet_cb('incoming_transfers', params)
if 'transfers' in rv:
for transfer in rv['transfers']:
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']}
else:
logging.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))

View File

View 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

View 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.

View File

@ -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[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__':
unittest.main()