Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: send raw tx data in audit and match_status requests #804

Merged
merged 5 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/asset/bch/bch.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ func (bch *BCHWallet) Address() (string, error) {
// AuditContract modifies the *asset.Contract returned by the ExchangeWallet
// AuditContract method by converting the Recipient to the Cash Address
// encoding.
func (bch *BCHWallet) AuditContract(coinID, contract dex.Bytes) (*asset.AuditInfo, error) { // AuditInfo has address
ai, err := bch.ExchangeWallet.AuditContract(coinID, contract)
func (bch *BCHWallet) AuditContract(coinID, contract, txData dex.Bytes) (*asset.AuditInfo, error) { // AuditInfo has address
ai, err := bch.ExchangeWallet.AuditContract(coinID, contract, txData)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion client/asset/btc/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -1613,7 +1613,7 @@ func (btc *ExchangeWallet) SignMessage(coin asset.Coin, msg dex.Bytes) (pubkeys,
// AuditContract retrieves information about a swap contract on the blockchain.
// AuditContract would be used to audit the counter-party's contract during a
// swap.
func (btc *ExchangeWallet) AuditContract(coinID dex.Bytes, contract dex.Bytes) (*asset.AuditInfo, error) {
func (btc *ExchangeWallet) AuditContract(coinID, contract, txData dex.Bytes) (*asset.AuditInfo, error) {
txHash, vout, err := decodeCoinID(coinID)
if err != nil {
return nil, err
Expand Down
8 changes: 4 additions & 4 deletions client/asset/btc/btc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1668,7 +1668,7 @@ func testAuditContract(t *testing.T, segwit bool) {
},
}

audit, err := wallet.AuditContract(toCoinID(tTxHash, vout), contract)
audit, err := wallet.AuditContract(toCoinID(tTxHash, vout), contract, nil)
if err != nil {
t.Fatalf("audit error: %v", err)
}
Expand All @@ -1683,14 +1683,14 @@ func testAuditContract(t *testing.T, segwit bool) {
}

// Invalid txid
_, err = wallet.AuditContract(make([]byte, 15), contract)
_, err = wallet.AuditContract(make([]byte, 15), contract, nil)
if err == nil {
t.Fatalf("no error for bad txid")
}

// GetTxOut error
node.txOutErr = tErr
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), contract)
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), contract, nil)
if err == nil {
t.Fatalf("no error for unknown txout")
}
Expand All @@ -1700,7 +1700,7 @@ func testAuditContract(t *testing.T, segwit bool) {
pkh, _ := hex.DecodeString("c6a704f11af6cbee8738ff19fc28cdc70aba0b82")
wrongAddr, _ := btcutil.NewAddressPubKeyHash(pkh, &chaincfg.MainNetParams)
badContract, _ := txscript.PayToAddrScript(wrongAddr)
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), badContract)
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), badContract, nil)
if err == nil {
t.Fatalf("no error for wrong contract")
}
Expand Down
2 changes: 1 addition & 1 deletion client/asset/btc/livetest/livetest.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ func Run(t *testing.T, newWallet WalletConstructor, address string, dexAsset *de
makeRedemption := func(swapVal uint64, receipt asset.Receipt, secret []byte) *asset.Redemption {
t.Helper()
// Alpha should be able to redeem.
ci, err := rig.alpha().AuditContract(receipt.Coin().ID(), receipt.Contract())
ci, err := rig.alpha().AuditContract(receipt.Coin().ID(), receipt.Contract(), nil)
if err != nil {
t.Fatalf("error auditing contract: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion client/asset/dcr/dcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ func (dcr *ExchangeWallet) SignMessage(coin asset.Coin, msg dex.Bytes) (pubkeys,
// AuditContract retrieves information about a swap contract on the
// blockchain. This would be used to verify the counter-party's contract
// during a swap.
func (dcr *ExchangeWallet) AuditContract(coinID, contract dex.Bytes) (*asset.AuditInfo, error) {
func (dcr *ExchangeWallet) AuditContract(coinID, contract, txData dex.Bytes) (*asset.AuditInfo, error) {
txHash, vout, err := decodeCoinID(coinID)
if err != nil {
return nil, err
Expand Down
8 changes: 4 additions & 4 deletions client/asset/dcr/dcr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,7 @@ func TestAuditContract(t *testing.T) {

node.txOutRes[newOutPoint(tTxHash, vout)] = makeGetTxOutRes(1, 5, pkScript)

audit, err := wallet.AuditContract(toCoinID(tTxHash, vout), contract)
audit, err := wallet.AuditContract(toCoinID(tTxHash, vout), contract, nil)
if err != nil {
t.Fatalf("audit error: %v", err)
}
Expand All @@ -1494,14 +1494,14 @@ func TestAuditContract(t *testing.T) {
}

// Invalid txid
_, err = wallet.AuditContract(make([]byte, 15), contract)
_, err = wallet.AuditContract(make([]byte, 15), contract, nil)
if err == nil {
t.Fatalf("no error for bad txid")
}

// GetTxOut error
node.txOutErr = tErr
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), contract)
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), contract, nil)
if err == nil {
t.Fatalf("no error for unknown txout")
}
Expand All @@ -1514,7 +1514,7 @@ func TestAuditContract(t *testing.T) {
if err != nil {
t.Fatalf("bad address %s (%T)", wrongAddr, wrongAddr)
}
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), badContract)
_, err = wallet.AuditContract(toCoinID(tTxHash, vout), badContract, nil)
if err == nil {
t.Fatalf("no error for wrong contract")
}
Expand Down
2 changes: 1 addition & 1 deletion client/asset/dcr/simnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ func runTest(t *testing.T, splitTx bool) {
makeRedemption := func(swapVal uint64, receipt asset.Receipt, secret []byte) *asset.Redemption {
t.Helper()
swapOutput := receipt.Coin()
ci, err := rig.alpha().AuditContract(swapOutput.ID(), receipt.Contract())
ci, err := rig.alpha().AuditContract(swapOutput.ID(), receipt.Contract(), nil)
if err != nil {
t.Fatalf("error auditing contract: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion client/asset/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ type Wallet interface {
// during a swap. If the coin cannot be found for the coin ID, the
// ExchangeWallet should return CoinNotFoundError. This enables the client
// to properly handle network latency.
AuditContract(coinID, contract dex.Bytes) (*AuditInfo, error)
AuditContract(coinID, contract, txData dex.Bytes) (*AuditInfo, error)
// LocktimeExpired returns true if the specified contract's locktime has
// expired, making it possible to issue a Refund. The contract expiry time
// is also returned, but reaching this time does not necessarily mean the
Expand Down
8 changes: 5 additions & 3 deletions client/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -3812,18 +3812,20 @@ func (c *Core) resumeTrades(dc *dexConnection, trackers []*trackedTrade) assetMa
notifyErr(SubjectMatchStatusError, "Match %s for order %s is in state %s, but has no maker swap coin.", dbMatch.Side, tracker.token(), dbMatch.Status)
continue
}
counterContract := metaData.Proof.CounterScript
counterContract := metaData.Proof.CounterContract
if len(counterContract) == 0 {
match.swapErr = fmt.Errorf("missing counter-contract, order %s, match %s", tracker.ID(), match.id)
notifyErr(SubjectMatchStatusError, "Match %s for order %s is in state %s, but has no maker swap contract.", dbMatch.Side, tracker.token(), dbMatch.Status)
continue
}
counterTxData := metaData.Proof.CounterTxData

// Obtaining AuditInfo will fail if it's unmined AND gone from
// mempool, or the wallet is otherwise not ready. Note that this
// does not actually audit the contract's value, recipient,
// expiration, or secret hash (if maker), as that was already
// done when it was initially stored as CounterScript.
auditInfo, err := wallets.toWallet.AuditContract(counterSwap, counterContract)
auditInfo, err := wallets.toWallet.AuditContract(counterSwap, counterContract, counterTxData)
if err != nil {
contractStr := coinIDString(wallets.toAsset.ID, counterSwap)
c.log.Warnf("Starting search for counterparty contract %v (%s)", contractStr, unbip(wallets.toAsset.ID))
Expand All @@ -3832,7 +3834,7 @@ func (c *Core) resumeTrades(dc *dexConnection, trackers []*trackedTrade) assetMa
// searching since matchTracker.counterSwap is not yet set.
match.swapErr = fmt.Errorf("audit in progress, please wait") // don't frighten the users
go func(tracker *trackedTrade, match *matchTracker) {
auditInfo, err := tracker.searchAuditInfo(match, counterSwap, counterContract)
auditInfo, err := tracker.searchAuditInfo(match, counterSwap, counterContract, counterTxData)
tracker.mtx.Lock()
defer tracker.mtx.Unlock()
if err != nil {
Expand Down
39 changes: 22 additions & 17 deletions client/core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ func (w *TXCWallet) SignMessage(asset.Coin, dex.Bytes) (pubkeys, sigs []dex.Byte
return nil, nil, w.signCoinErr
}

func (w *TXCWallet) AuditContract(coinID, contract dex.Bytes) (*asset.AuditInfo, error) {
func (w *TXCWallet) AuditContract(coinID, contract, txData dex.Bytes) (*asset.AuditInfo, error) {
defer func() {
if w.auditChan != nil {
w.auditChan <- struct{}{}
Expand Down Expand Up @@ -1750,6 +1750,7 @@ func TestLogin(t *testing.T) {
MakerContract: missedContract,
MakerSwap: encode.RandomBytes(36),
Active: true,
MakerTxData: []byte{0x01},
}}, nil)
f(resp)
return nil
Expand Down Expand Up @@ -1806,8 +1807,8 @@ func TestLogin(t *testing.T) {
tracker.mtx.Lock()
defer tracker.mtx.Unlock()
match = tracker.matches[extraID]
if !bytes.Equal(match.MetaData.Proof.CounterScript, missedContract) {
t.Errorf("Missed maker contract not retrieved, %s, %s", match.id, hex.EncodeToString(match.MetaData.Proof.CounterScript))
if !bytes.Equal(match.MetaData.Proof.CounterContract, missedContract) {
t.Errorf("Missed maker contract not retrieved, %s, %s", match.id, hex.EncodeToString(match.MetaData.Proof.CounterContract))
}
}

Expand Down Expand Up @@ -2818,15 +2819,15 @@ func TestTradeTracking(t *testing.T) {

// Check audit errors.
tBtcWallet.auditErr = tErr
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no maker error for AuditContract error")
}

// Check expiration error.
match.MetaData.Proof.SelfRevoked = true // keeps trying unless revoked
tBtcWallet.auditErr = asset.CoinNotFoundError
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no maker error for AuditContract expiration")
}
Expand All @@ -2838,28 +2839,28 @@ func TestTradeTracking(t *testing.T) {
match.MetaData.Proof.SelfRevoked = false

auditInfo.Coin.(*tCoin).val = auditQty - 1
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no maker error for low value")
}
auditInfo.Coin.(*tCoin).val = auditQty

auditInfo.SecretHash = []byte{0x01}
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no maker error for wrong secret hash")
}
auditInfo.SecretHash = proof.SecretHash

auditInfo.Recipient = "wrong address"
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no maker error for wrong address")
}
auditInfo.Recipient = addr

auditInfo.Expiration = matchTime.Add(tracker.lockTimeTaker - time.Hour)
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no maker error for early lock time")
}
Expand All @@ -2879,7 +2880,7 @@ func TestTradeTracking(t *testing.T) {
if match.counterSwap == nil {
t.Fatalf("counter-swap not set")
}
if !bytes.Equal(proof.CounterScript, audit.Contract) {
if !bytes.Equal(proof.CounterContract, audit.Contract) {
t.Fatalf("counter-script not recorded")
}
if !bytes.Equal(proof.TakerSwap, audit.CoinID) {
Expand Down Expand Up @@ -2971,7 +2972,7 @@ func TestTradeTracking(t *testing.T) {
tBtcWallet.auditInfo = auditInfo
// early lock time
auditInfo.Expiration = matchTime.Add(tracker.lockTimeMaker - time.Hour)
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no taker error for early lock time")
}
Expand Down Expand Up @@ -3517,7 +3518,7 @@ func TestRefunds(t *testing.T) {

// Check audit errors.
tBtcWallet.auditErr = tErr
err = tracker.auditContract(match, audit.CoinID, audit.Contract)
err = tracker.auditContract(match, audit.CoinID, audit.Contract, nil)
if err == nil {
t.Fatalf("no maker error for AuditContract error")
}
Expand Down Expand Up @@ -3678,9 +3679,9 @@ func TestResolveActiveTrades(t *testing.T) {
MetaData: &db.MatchMetaData{
Status: order.MakerSwapCast,
Proof: db.MatchProof{
CounterScript: encode.RandomBytes(50),
SecretHash: encode.RandomBytes(32),
MakerSwap: encode.RandomBytes(32),
CounterContract: encode.RandomBytes(50),
SecretHash: encode.RandomBytes(32),
MakerSwap: encode.RandomBytes(32),
Auth: db.MatchAuth{
MatchSig: encode.RandomBytes(32),
},
Expand Down Expand Up @@ -5334,6 +5335,7 @@ func TestMatchStatusResolution(t *testing.T) {

tBytes := encode.RandomBytes(2)
tCoinID := encode.RandomBytes(36)
tTxData := encode.RandomBytes(1)

setAuthSigs := func(status order.MatchStatus) {
isMaker := match.Match.Side == order.Maker
Expand Down Expand Up @@ -5390,13 +5392,13 @@ func TestMatchStatusResolution(t *testing.T) {
proof.Script = tBytes
proof.Secret = secret
} else {
proof.CounterScript = tBytes
proof.CounterContract = tBytes
}
}
if status >= order.TakerSwapCast {
proof.TakerSwap = tCoinID
if isMaker {
proof.CounterScript = tBytes
proof.CounterContract = tBytes
} else {
proof.Script = tBytes
}
Expand Down Expand Up @@ -5428,6 +5430,9 @@ func TestMatchStatusResolution(t *testing.T) {
tMatchResults.MakerContract = tBytes
tMatchResults.MakerSwap = tCoinID
}
if status == order.MakerSwapCast || status == order.TakerSwapCast {
tMatchResults.TakerTxData = tTxData
}
if status >= order.TakerSwapCast {
tMatchResults.TakerContract = tBytes
tMatchResults.TakerSwap = tCoinID
Expand Down
4 changes: 2 additions & 2 deletions client/core/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func resolveMissedMakerAudit(dc *dexConnection, trade *trackedTrade, match *matc
}

go func() {
err := trade.auditContract(match, srvData.MakerSwap, srvData.MakerContract)
err := trade.auditContract(match, srvData.MakerSwap, srvData.MakerContract, srvData.MakerTxData)
if err != nil {
dc.log.Errorf("auditContract error during match status resolution (revoking match). %s: %v", logID, err)
trade.mtx.Lock()
Expand Down Expand Up @@ -236,7 +236,7 @@ func resolveMissedTakerAudit(dc *dexConnection, trade *trackedTrade, match *matc
}

go func() {
err := trade.auditContract(match, srvData.TakerSwap, srvData.TakerContract)
err := trade.auditContract(match, srvData.TakerSwap, srvData.TakerContract, srvData.TakerTxData)
if err != nil {
dc.log.Errorf("auditContract error during match status resolution (revoking match). %s: %v", logID, err)
trade.mtx.Lock()
Expand Down
17 changes: 9 additions & 8 deletions client/core/trade.go
Original file line number Diff line number Diff line change
Expand Up @@ -1925,7 +1925,7 @@ func (t *trackedTrade) processAuditMsg(msgID uint64, audit *msgjson.Audit) error
// data are updated.
go func() {
// Search until it's known to be revoked.
err := t.auditContract(match, audit.CoinID, audit.Contract)
err := t.auditContract(match, audit.CoinID, audit.Contract, audit.TxData)
if err != nil {
contractID := coinIDString(t.wallets.toAsset.ID, audit.CoinID)
t.dc.log.Error("Failed to audit contract coin %v (%s) for match %v: %v",
Expand Down Expand Up @@ -1969,7 +1969,7 @@ func (t *trackedTrade) processAuditMsg(msgID uint64, audit *msgjson.Audit) error
// counterparty contract data again except on reconnect. This may block for a
// long time and should be run in a goroutine. The trackedTrade mtx must NOT be
// locked.
func (t *trackedTrade) searchAuditInfo(match *matchTracker, coinID []byte, contract []byte) (*asset.AuditInfo, error) {
func (t *trackedTrade) searchAuditInfo(match *matchTracker, coinID []byte, contract, txData []byte) (*asset.AuditInfo, error) {
errChan := make(chan error, 1)
var auditInfo *asset.AuditInfo
var tries int
Expand All @@ -1978,7 +1978,7 @@ func (t *trackedTrade) searchAuditInfo(match *matchTracker, coinID []byte, contr
Expiration: time.Now().Add(24 * time.Hour), // effectively forever
TryFunc: func() bool {
var err error
auditInfo, err = t.wallets.toWallet.AuditContract(coinID, contract)
auditInfo, err = t.wallets.toWallet.AuditContract(coinID, contract, txData)
if err == nil {
// Success.
errChan <- nil
Expand Down Expand Up @@ -2029,8 +2029,8 @@ func (t *trackedTrade) searchAuditInfo(match *matchTracker, coinID []byte, contr
// fields are set. This may block for a long period, and should be run in a
// goroutine. The trackedTrade mtx must NOT be locked. The match is updated in
// the DB if the audit succeeds.
func (t *trackedTrade) auditContract(match *matchTracker, coinID []byte, contract []byte) error {
auditInfo, err := t.searchAuditInfo(match, coinID, contract)
func (t *trackedTrade) auditContract(match *matchTracker, coinID, contract, txData []byte) error {
auditInfo, err := t.searchAuditInfo(match, coinID, contract, txData)
if err != nil {
return err
}
Expand Down Expand Up @@ -2090,16 +2090,17 @@ func (t *trackedTrade) auditContract(match *matchTracker, coinID []byte, contrac
match.SetStatus(order.MakerSwapCast)
proof.MakerSwap = coinID
}
proof.CounterScript = contract
proof.CounterTxData = txData
proof.CounterContract = contract
match.counterSwap = auditInfo

err = t.db.UpdateMatch(&match.MetaMatch)
if err != nil {
t.dc.log.Errorf("Error updating database for match %v: %v", match.id, err)
}

t.dc.log.Infof("Audited contract (%s: %v) paying to %s for order %s, match %s",
t.wallets.toAsset.Symbol, auditInfo.Coin, auditInfo.Recipient, t.ID(), match.id)
t.dc.log.Infof("Audited contract (%s: %v) paying to %s for order %s, match %s, with tx data = %t",
t.wallets.toAsset.Symbol, auditInfo.Coin, auditInfo.Recipient, t.ID(), match.id, len(txData) > 0)

return nil
}
Expand Down
Binary file added client/db/bolt/testdata/v2.db.gz
Binary file not shown.
Loading