Compare commits

...

6 Commits

Author SHA1 Message Date
tecnovert 0bc3226ed9 build, guix: update packed version 2026-06-09 16:51:09 +02:00
tecnovert 1aa53e38f9 build: raise version to 0.16.5 2026-06-09 16:45:29 +02:00
tecnovert 379eaaf0db test: add test for underfunded itx 2026-06-09 16:42:49 +02:00
tecnovert 304e88646f Merge pull request #497 from tecnovert/fix2
fix: verify follower's script chain lock refund tx sig
2026-06-09 14:32:31 +00:00
tecnovert 597cdcbff5 fix: verify follower's script chain lock refund tx sig 2026-06-09 14:51:50 +02:00
tecnovert 176fc48ba2 Merge pull request #494 from basicswap/cryptoguard-patch-2
Update release-notes.md
2026-06-09 12:48:51 +00:00
7 changed files with 84 additions and 48 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
name = "basicswap"
__version__ = "0.16.4"
__version__ = "0.16.5"
+38 -18
View File
@@ -6906,7 +6906,16 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
self.log.debug(
f"Create initiate txn for coin {ci.coin_name()} to {addr_to} for bid {self.log.id(bid_id)}"
)
txn_signed = ci.createRawSignedTransaction(addr_to, bid.amount)
amount_from: int = bid.amount
if bid.debug_ind == DebugTypes.MAKE_INVALID_ITX:
amount_from -= 100
self.logBidEvent(
bid.bid_id,
EventLogTypes.DEBUG_TWEAK_APPLIED,
f"Make invalid ITx for testing: {bid.debug_ind}",
None,
)
txn_signed = ci.createRawSignedTransaction(addr_to, amount_from)
txjs = ci.describeTx(txn_signed)
vout = getVoutByAddress(txjs, addr_to)
@@ -6997,13 +7006,10 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
if bid.debug_ind == DebugTypes.MAKE_INVALID_PTX:
amount_to -= 1
self.log.debug(
f"bid {self.log.id(bid_id)}: Make invalid PTx for testing: {bid.debug_ind}."
)
self.logBidEvent(
bid.bid_id,
EventLogTypes.DEBUG_TWEAK_APPLIED,
"ind {}".format(bid.debug_ind),
f"Make invalid PTx for testing: {bid.debug_ind}",
None,
)
@@ -11671,8 +11677,11 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
txid_hex = ci_from.publishTx(lock_tx_signed)
if txid_hex != b2h(xmr_swap.a_lock_tx_id):
if not self.isBchXmrSwap(offer):
raise ValueError("Coin A lock tx txid changed after sending!")
self.log.info(
"Recomputing refund transactions and txids after lock tx publish."
f"Recomputing {ci_from.coin_name()} refund transactions and txids after lock tx publish."
)
xmr_swap.a_lock_tx = lock_tx_signed
xmr_swap.a_lock_tx_id = bytes.fromhex(txid_hex)
@@ -12464,6 +12473,19 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
)
if not self.isBchXmrSwap(offer):
self.log.info("Checking follower's lock refund tx signature.")
prevout_amount = ci_from.getLockTxSwapOutputValue(bid, xmr_swap)
v = ci_from.verifyTxSig(
xmr_swap.a_lock_refund_tx,
xmr_swap.af_lock_refund_tx_sig,
xmr_swap.pkaf,
0,
xmr_swap.a_lock_tx_script,
prevout_amount,
)
ensure(v, "Invalid coin A lock refund tx leader sig")
xmr_swap_1.addLockRefundSigs(self, xmr_swap, ci_from)
# segwit coins sign the transaction
xmr_swap.af_lock_refund_spend_tx_sig = ci_from.decryptOtVES(
kbsl, xmr_swap.af_lock_refund_spend_tx_esig
@@ -12478,7 +12500,16 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
xmr_swap.a_lock_refund_tx_script,
prevout_amount,
)
self.log.info("Checking follower's lock refund spend tx signature.")
v = ci_from.verifyTxSig(
xmr_swap.a_lock_refund_spend_tx,
xmr_swap.af_lock_refund_spend_tx_sig,
xmr_swap.pkaf,
0,
xmr_swap.a_lock_refund_tx_script,
prevout_amount,
)
ensure(v, "Invalid follower signature for lock refund spend txn")
self.log.debug("Setting lock refund spend tx sigs.")
witness_stack = []
if coin_from not in (Coins.DCR,):
@@ -12496,17 +12527,6 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
)
ensure(signed_tx, "setTxSignature failed")
xmr_swap.a_lock_refund_spend_tx = signed_tx
v = ci_from.verifyTxSig(
xmr_swap.a_lock_refund_spend_tx,
xmr_swap.af_lock_refund_spend_tx_sig,
xmr_swap.pkaf,
0,
xmr_swap.a_lock_refund_tx_script,
prevout_amount,
)
ensure(v, "Invalid signature for lock refund spend txn")
xmr_swap_1.addLockRefundSigs(self, xmr_swap, ci_from)
else:
# BCH signs the output pkh
+1
View File
@@ -232,6 +232,7 @@ class DebugTypes(IntEnum):
BID_DONT_SPEND_COIN_A_LOCK_REFUND2 = auto() # continues
CREATE_INVALID_COIN_B_LOCK = auto()
BUYER_STOP_AFTER_ITX = auto()
MAKE_INVALID_ITX = auto()
MAKE_INVALID_PTX = auto()
DONT_SPEND_ITX = auto()
SKIP_LOCK_TX_REFUND = auto()
+1
View File
@@ -5,6 +5,7 @@
- Updated docker base images to Debian Trixie.
- By default reject secret hash type offers where the coin pair could use adaptor sig swap.
- override with "strict_swap_type" setting.
- Verify follower's script chain lock refund tx sig.
0.16.4
+3 -3
View File
@@ -135,15 +135,15 @@
(define-public basicswap
(package
(name "basicswap")
(version "0.16.4")
(version "0.16.5")
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/basicswap/basicswap")
(commit "136b311dc68f11b9c12ebd6877c5f718d705603a")))
(commit "1aa53e38f96ffa753cc6eeaee1cc9fccbd0ce5dd")))
(sha256
(base32
"0ikr8ik9rklvafd1j8zj0y38vric02qhmj7pvp3kvzbmd2fxx95p"))
"0k2r16f0imyzh0x90a2a37m41imnd183vdlf9b8nrx4l884h543y"))
(file-name (git-file-name name version))))
(build-system pyproject-build-system)
+39 -23
View File
@@ -26,11 +26,13 @@ from basicswap.basicswap import (
TxStates,
)
from basicswap.basicswap_util import (
EventLogTypes,
TxLockTypes,
)
from basicswap.chainparams import (
chainparams,
)
from basicswap.db import Concepts
from basicswap.util import (
COIN,
make_int,
@@ -47,6 +49,7 @@ from tests.basicswap.common import (
wait_for_balance,
wait_for_bid,
wait_for_bid_tx_state,
wait_for_event,
wait_for_in_progress,
wait_for_offer,
wait_for_unspent,
@@ -850,7 +853,6 @@ class Test(BaseTest):
swap_clients = self.swap_clients
swap_value = make_int(random.uniform(0.001, 10.0), scale=8, r=1)
logging.info("swap_value {}".format(format_amount(swap_value, 8)))
offer_id = swap_clients[0].postOffer(
Coins.LTC,
Coins.BTC,
@@ -879,15 +881,15 @@ class Test(BaseTest):
)
wait_for_bid(
test_delay_event,
swap_clients[1],
swap_clients[0],
bid_id,
BidStates.SWAP_COMPLETED,
sent=True,
wait_for=30,
)
js_0_bid = read_json_api(1800, "bids/{}".format(bid_id.hex()))
js_1_bid = read_json_api(1801, "bids/{}".format(bid_id.hex()))
js_0_bid = read_json_api(1800, f"bids/{bid_id.hex()}")
js_1_bid = read_json_api(1801, f"bids/{bid_id.hex()}")
assert js_0_bid["itx_state"] == "Refunded"
assert js_1_bid["ptx_state"] == "Refunded"
@@ -904,38 +906,52 @@ class Test(BaseTest):
assert compare_bid_states(offerer_states, self.states_offerer_sh[1]) is True
assert compare_bid_states(bidder_states, self.states_bidder_sh[1]) is True
"""
def test_11_refund(self):
# Seller submits initiate txn, buyer doesn't respond, repeat of test 5 using debug_ind
logging.info('---------- Test refund, LTC to BTC')
def test_11_bad_itx(self):
# Invalid ITx sent, PTx should not be sent
logging.info("---------- Test bad ITx, LTC to BTC")
swap_clients = self.swap_clients
swap_value = make_int(random.uniform(0.001, 10.0), scale=8, r=1)
logging.info('swap_value {}'.format(format_amount(swap_value, 8)))
offer_id = swap_clients[0].postOffer(Coins.LTC, Coins.BTC, swap_value, 0.1 * COIN, swap_value, SwapTypes.SELLER_FIRST,
TxLockTypes.SEQUENCE_LOCK_BLOCKS, 10)
offer_id = swap_clients[0].postOffer(
Coins.LTC,
Coins.BTC,
swap_value,
0.1 * COIN,
swap_value,
SwapTypes.SELLER_FIRST,
TxLockTypes.SEQUENCE_LOCK_BLOCKS,
18,
)
wait_for_offer(test_delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
swap_clients[1].setBidDebugInd(bid_id, DebugTypes.BUYER_STOP_AFTER_ITX)
wait_for_bid(test_delay_event, swap_clients[0], bid_id)
swap_clients[0].setBidDebugInd(bid_id, DebugTypes.MAKE_INVALID_ITX)
swap_clients[0].acceptBid(bid_id)
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=120)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=30)
event = wait_for_event(
test_delay_event,
swap_clients[1],
Concepts.BID,
bid_id,
event_type=EventLogTypes.ERROR,
wait_for=120,
)
assert "Incorrect output amount in initiate txn " in event.event_msg
js_0_bid = read_json_api(1800, 'bids/{}'.format(bid_id.hex()))
js_1_bid = read_json_api(1801, 'bids/{}'.format(bid_id.hex()))
assert (js_0_bid['itx_state'] == 'Refunded')
assert (js_1_bid['ptx_state'] == 'Unknown')
wait_for_bid(
test_delay_event,
swap_clients[1],
bid_id,
BidStates.BID_ERROR,
sent=True,
wait_for=30,
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert (js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert (js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
"""
js_1_bid = read_json_api(1801, f"bids/{bid_id.hex()}")
assert js_1_bid["ptx_state"] == "Unknown"
def test_12_withdrawal(self):
logging.info("---------- Test LTC withdrawals")
+1 -3
View File
@@ -23,9 +23,7 @@ from copy import deepcopy
from coincurve.keys import PrivateKey
import basicswap.config as cfg
from basicswap.db import (
Concepts,
)
from basicswap.db import Concepts
from basicswap.basicswap import (
Coins,
BasicSwap,