Fix ALICE-based PRESENCE transactions.

PRESENCE transactions were previously validated using Bob's trade key (in address form).
But as PRESENCE transactions are already emitted by Alice, her trade key is also used
(if present in trade data by virtue of AT being locked to Alice).

Similarly, Alice's trade-bot won't even try to build PRESENCE transactions if her
trade key isn't publicly visible to other peers, i.e. after AT is locked to Alice.
This commit is contained in:
catbref 2020-12-28 12:00:11 +00:00
parent 35b0ac78b8
commit 332c917c94
4 changed files with 38 additions and 21 deletions

View File

@ -387,32 +387,32 @@ public class BitcoinACCTv1TradeBot implements AcctTradeBot {
break;
case ALICE_WAITING_FOR_P2SH_A:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleAliceWaitingForP2shA(repository, tradeBotData, atData, tradeData);
break;
case BOB_WAITING_FOR_MESSAGE:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleBobWaitingForMessage(repository, tradeBotData, atData, tradeData);
break;
case ALICE_WAITING_FOR_AT_LOCK:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleAliceWaitingForAtLock(repository, tradeBotData, atData, tradeData);
break;
case BOB_WAITING_FOR_P2SH_B:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleBobWaitingForP2shB(repository, tradeBotData, atData, tradeData);
break;
case ALICE_WATCH_P2SH_B:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleAliceWatchingP2shB(repository, tradeBotData, atData, tradeData);
break;
case BOB_WAITING_FOR_AT_REDEEM:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleBobWaitingForAtRedeem(repository, tradeBotData, atData, tradeData);
break;
@ -421,12 +421,12 @@ public class BitcoinACCTv1TradeBot implements AcctTradeBot {
break;
case ALICE_REFUNDING_B:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleAliceRefundingP2shB(repository, tradeBotData, atData, tradeData);
break;
case ALICE_REFUNDING_A:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleAliceRefundingP2shA(repository, tradeBotData, atData, tradeData);
break;

View File

@ -384,17 +384,17 @@ public class LitecoinACCTv1TradeBot implements AcctTradeBot {
break;
case BOB_WAITING_FOR_MESSAGE:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleBobWaitingForMessage(repository, tradeBotData, atData, tradeData);
break;
case ALICE_WAITING_FOR_AT_LOCK:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleAliceWaitingForAtLock(repository, tradeBotData, atData, tradeData);
break;
case BOB_WAITING_FOR_AT_REDEEM:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleBobWaitingForAtRedeem(repository, tradeBotData, atData, tradeData);
break;
@ -403,7 +403,7 @@ public class LitecoinACCTv1TradeBot implements AcctTradeBot {
break;
case ALICE_REFUNDING_A:
TradeBot.getInstance().updatePresence(repository, tradeBotData);
TradeBot.getInstance().updatePresence(repository, tradeBotData, tradeData);
handleAliceRefundingP2shA(repository, tradeBotData, atData, tradeData);
break;

View File

@ -307,20 +307,32 @@ public class TradeBot implements Listener {
}
// PRESENCE-related
/*package*/ void updatePresence(Repository repository, TradeBotData tradeBotData) throws DataException {
String key = tradeBotData.getAtAddress();
/*package*/ void updatePresence(Repository repository, TradeBotData tradeBotData, CrossChainTradeData tradeData)
throws DataException {
String atAddress = tradeBotData.getAtAddress();
PrivateKeyAccount tradeNativeAccount = new PrivateKeyAccount(repository, tradeBotData.getTradePrivateKey());
String signerAddress = tradeNativeAccount.getAddress();
/*
* There's no point in Alice trying to build a PRESENCE transaction
* for an AT that isn't locked to her, as other peers won't be able
* to validate the PRESENCE transaction as signing public key won't
* be visible.
*/
if (!signerAddress.equals(tradeData.qortalCreatorTradeAddress) && !signerAddress.equals(tradeData.qortalPartnerAddress))
// Signer is neither Bob, nor Alice, or trade not yet locked to Alice
return;
long now = NTP.getTime();
long threshold = now - PresenceType.TRADE_BOT.getLifetime();
long timestamp = presenceTimestampsByAtAddress.compute(key, (k, v) -> (v == null || v < threshold) ? now : v);
long timestamp = presenceTimestampsByAtAddress.compute(atAddress, (k, v) -> (v == null || v < threshold) ? now : v);
// If timestamp hasn't been updated then nothing to do
if (timestamp != now)
return;
PrivateKeyAccount tradeNativeAccount = new PrivateKeyAccount(repository, tradeBotData.getTradePrivateKey());
int txGroupId = Group.NO_GROUP;
byte[] reference = new byte[TransactionTransformer.SIGNATURE_LENGTH];
byte[] creatorPublicKey = tradeNativeAccount.getPublicKey();

View File

@ -168,15 +168,15 @@ public class PresenceTransaction extends Transaction {
if (!Crypto.verify(this.transactionData.getCreatorPublicKey(), timestampSignature, timestampBytes))
return ValidationResult.INVALID_TIMESTAMP_SIGNATURE;
// Check signer is known trade address
String signerAddress = Crypto.toAddress(this.transactionData.getCreatorPublicKey());
Map<ByteArray, Supplier<ACCT>> acctSuppliersByCodeHash = SupportedBlockchain.getAcctMap();
Set<ByteArray> codeHashes = acctSuppliersByCodeHash.keySet();
boolean isExecutable = true;
List<ATData> atsData = repository.getATRepository().getAllATsByFunctionality(codeHashes, isExecutable);
// Convert signer's public key to address form
String signerAddress = Crypto.toAddress(this.transactionData.getCreatorPublicKey());
for (ATData atData : atsData) {
ByteArray atCodeHash = new ByteArray(atData.getCodeHash());
Supplier<ACCT> acctSupplier = acctSuppliersByCodeHash.get(atCodeHash);
@ -185,7 +185,12 @@ public class PresenceTransaction extends Transaction {
CrossChainTradeData crossChainTradeData = acctSupplier.get().populateTradeData(repository, atData);
if (crossChainTradeData.qortalCreatorTradeAddress.equals(signerAddress))
// OK if signer's public key (in address form) matches Bob's trade public key (in address form)
if (signerAddress.equals(crossChainTradeData.qortalCreatorTradeAddress))
return ValidationResult.OK;
// OK if signer's public key (in address form) matches Alice's trade public key (in address form)
if (signerAddress.equals(crossChainTradeData.qortalPartnerAddress))
return ValidationResult.OK;
}