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

Complete new trade protocol #3340

Merged
3 changes: 2 additions & 1 deletion common/src/main/proto/pb.proto
Expand Up @@ -762,6 +762,7 @@ message Dispute {
string dispute_payout_tx_id = 23;
SupportType support_type = 24;
string mediators_dispute_result = 25;
string delayed_payout_tx_id = 26;
}

message Attachment {
Expand Down Expand Up @@ -813,7 +814,7 @@ message Contract {
int64 trade_amount = 2;
int64 trade_price = 3;
string taker_fee_tx_id = 4;
NodeAddress arbitrator_node_address = 5;
reserved 5; // WAS: arbitrator_node_address
bool is_buyer_maker_and_seller_taker = 6;
string maker_account_id = 7;
string taker_account_id = 8;
Expand Down
7 changes: 2 additions & 5 deletions core/src/main/java/bisq/core/app/BisqSetup.java
Expand Up @@ -309,11 +309,8 @@ public void addBisqSetupCompleteListener(BisqSetupCompleteListener listener) {
}

public void start() {
if (log.isDebugEnabled()) {
UserThread.runPeriodically(() -> {
log.debug("1 second heartbeat");
}, 1);
}
UserThread.runPeriodically(() -> {
}, 1);
maybeReSyncSPVChain();
maybeShowTac();
}
Expand Down
34 changes: 0 additions & 34 deletions core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java
Expand Up @@ -33,13 +33,11 @@
import org.bitcoinj.core.Address;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput;
Expand Down Expand Up @@ -1168,38 +1166,6 @@ public void broadcastTx(Transaction tx, TxBroadcaster.Callback callback, int tim
// Misc
///////////////////////////////////////////////////////////////////////////////////////////

/**
* @param transaction The transaction to be added to the wallet
* @return The transaction we added to the wallet, which is different as the one we passed as argument!
* @throws VerificationException
*/
public Transaction addTxToWallet(Transaction transaction) throws VerificationException {
// We need to recreate the transaction otherwise we get a null pointer...
Transaction tx = new Transaction(params, transaction.bitcoinSerialize());
tx.getConfidence(Context.get()).setSource(TransactionConfidence.Source.SELF);

if (wallet != null) {
wallet.receivePending(tx, null, true);
}
return tx;
}

/**
* @param serializedTransaction The serialized transaction to be added to the wallet
* @return The transaction we added to the wallet, which is different as the one we passed as argument!
* @throws VerificationException
*/
public Transaction addTxToWallet(byte[] serializedTransaction) throws VerificationException {
// We need to recreate the tx otherwise we get a null pointer...
Transaction transaction = new Transaction(params, serializedTransaction);
transaction.getConfidence(Context.get()).setSource(TransactionConfidence.Source.NETWORK);

if (wallet != null) {
wallet.receivePending(transaction, null, true);
}
return transaction;
}

/**
* @param txId The transaction ID of the transaction we want to lookup
* @return Returns local existing wallet transaction
Expand Down
58 changes: 55 additions & 3 deletions core/src/main/java/bisq/core/btc/wallet/WalletService.java
Expand Up @@ -34,6 +34,7 @@
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.BlockChain;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.NetworkParameters;
Expand All @@ -43,6 +44,7 @@
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.core.listeners.NewBestBlockListener;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.KeyCrypter;
Expand Down Expand Up @@ -102,6 +104,7 @@ public abstract class WalletService {
protected final CopyOnWriteArraySet<AddressConfidenceListener> addressConfidenceListeners = new CopyOnWriteArraySet<>();
protected final CopyOnWriteArraySet<TxConfidenceListener> txConfidenceListeners = new CopyOnWriteArraySet<>();
protected final CopyOnWriteArraySet<BalanceListener> balanceListeners = new CopyOnWriteArraySet<>();
@Getter
protected Wallet wallet;
@Getter
protected KeyParameter aesKey;
Expand Down Expand Up @@ -223,7 +226,9 @@ public static void checkAllScriptSignaturesForTx(Transaction transaction) throws
}
}

public static void checkScriptSig(Transaction transaction, TransactionInput input, int inputIndex) throws TransactionVerificationException {
public static void checkScriptSig(Transaction transaction,
TransactionInput input,
int inputIndex) throws TransactionVerificationException {
try {
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
input.getScriptSig().correctlySpends(transaction, inputIndex, input.getConnectedOutput().getScriptPubKey(), Script.ALL_VERIFY_FLAGS);
Expand All @@ -245,7 +250,11 @@ public static void removeSignatures(Transaction transaction) {
// Sign tx
///////////////////////////////////////////////////////////////////////////////////////////

public static void signTransactionInput(Wallet wallet, KeyParameter aesKey, Transaction tx, TransactionInput txIn, int index) {
public static void signTransactionInput(Wallet wallet,
KeyParameter aesKey,
Transaction tx,
TransactionInput txIn,
int index) {
KeyBag maybeDecryptingKeyBag = new DecryptingKeyBag(wallet, aesKey);
if (txIn.getConnectedOutput() != null) {
try {
Expand Down Expand Up @@ -475,7 +484,10 @@ public boolean isAddressUnused(Address address) {
// Empty complete Wallet
///////////////////////////////////////////////////////////////////////////////////////////

public void emptyWallet(String toAddress, KeyParameter aesKey, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler)
public void emptyWallet(String toAddress,
KeyParameter aesKey,
ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler)
throws InsufficientMoneyException, AddressFormatException {
SendRequest sendRequest = SendRequest.emptyWallet(Address.fromBase58(params, toAddress));
sendRequest.fee = Coin.ZERO;
Expand Down Expand Up @@ -675,6 +687,46 @@ public static String getAddressStringFromOutput(TransactionOutput output) {
}


/**
* @param serializedTransaction The serialized transaction to be added to the wallet
* @return The transaction we added to the wallet, which is different as the one we passed as argument!
* @throws VerificationException
*/
public static Transaction maybeAddTxToWallet(byte[] serializedTransaction,
Wallet wallet,
TransactionConfidence.Source source) throws VerificationException {
Transaction tx = new Transaction(wallet.getParams(), serializedTransaction);
Transaction walletTransaction = wallet.getTransaction(tx.getHash());
log.error("maybeAddTxToWallet id={}, is walletTransaction==null? {}", tx.getHashAsString(), walletTransaction == null);

if (walletTransaction == null) {
// We need to recreate the transaction otherwise we get a null pointer...
tx.getConfidence(Context.get()).setSource(source);
//wallet.maybeCommitTx(tx);
wallet.receivePending(tx, null, true);
return tx;
} else {
return walletTransaction;
}
}

public static Transaction maybeAddNetworkTxToWallet(byte[] serializedTransaction,
Wallet wallet) throws VerificationException {
return maybeAddTxToWallet(serializedTransaction, wallet, TransactionConfidence.Source.NETWORK);
}

public static Transaction maybeAddSelfTxToWallet(Transaction transaction,
Wallet wallet) throws VerificationException {
return maybeAddTxToWallet(transaction, wallet, TransactionConfidence.Source.SELF);
}

public static Transaction maybeAddTxToWallet(Transaction transaction,
Wallet wallet,
TransactionConfidence.Source source) throws VerificationException {
return maybeAddTxToWallet(transaction.bitcoinSerialize(), wallet, source);
}


///////////////////////////////////////////////////////////////////////////////////////////
// bisqWalletEventListener
///////////////////////////////////////////////////////////////////////////////////////////
Expand Down
8 changes: 5 additions & 3 deletions core/src/main/java/bisq/core/offer/OpenOfferManager.java
Expand Up @@ -20,6 +20,7 @@
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.TradeWalletService;
import bisq.core.dao.DaoFacade;
import bisq.core.exceptions.TradePriceOutOfToleranceException;
import bisq.core.offer.availability.DisputeAgentSelection;
import bisq.core.offer.messages.OfferAvailabilityRequest;
Expand Down Expand Up @@ -107,6 +108,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
private final ArbitratorManager arbitratorManager;
private final MediatorManager mediatorManager;
private final RefundAgentManager refundAgentManager;
private final DaoFacade daoFacade;
private final Storage<TradableList<OpenOffer>> openOfferTradableListStorage;
private final Map<String, OpenOffer> offersToBeEdited = new HashMap<>();
private boolean stopped;
Expand All @@ -133,6 +135,7 @@ public OpenOfferManager(KeyRing keyRing,
ArbitratorManager arbitratorManager,
MediatorManager mediatorManager,
RefundAgentManager refundAgentManager,
DaoFacade daoFacade,
Storage<TradableList<OpenOffer>> storage) {
this.keyRing = keyRing;
this.user = user;
Expand All @@ -148,6 +151,7 @@ public OpenOfferManager(KeyRing keyRing,
this.arbitratorManager = arbitratorManager;
this.mediatorManager = mediatorManager;
this.refundAgentManager = refundAgentManager;
this.daoFacade = daoFacade;

openOfferTradableListStorage = storage;

Expand Down Expand Up @@ -344,6 +348,7 @@ public void placeOffer(Offer offer,
offerBookService,
arbitratorManager,
tradeStatisticsManager,
daoFacade,
user);
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
model,
Expand Down Expand Up @@ -590,9 +595,6 @@ private void handleOfferAvailabilityRequest(OfferAvailabilityRequest request, No
if (preferences.getIgnoreTradersList().stream().noneMatch(fullAddress -> fullAddress.equals(peer.getFullAddress()))) {
availabilityResult = AvailabilityResult.AVAILABLE;

arbitratorNodeAddress = DisputeAgentSelection.getLeastUsedArbitrator(tradeStatisticsManager, arbitratorManager).getNodeAddress();
openOffer.setArbitratorNodeAddress(arbitratorNodeAddress);

mediatorNodeAddress = DisputeAgentSelection.getLeastUsedMediator(tradeStatisticsManager, mediatorManager).getNodeAddress();
openOffer.setMediatorNodeAddress(mediatorNodeAddress);

Expand Down
Expand Up @@ -93,13 +93,13 @@ private OfferAvailabilityResponse(String offerId,
public protobuf.NetworkEnvelope toProtoNetworkEnvelope() {
final protobuf.OfferAvailabilityResponse.Builder builder = protobuf.OfferAvailabilityResponse.newBuilder()
.setOfferId(offerId)
.setAvailabilityResult(protobuf.AvailabilityResult.valueOf(availabilityResult.name()))
.setArbitrator(arbitrator.toProtoMessage());
.setAvailabilityResult(protobuf.AvailabilityResult.valueOf(availabilityResult.name()));

Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities)));
Optional.ofNullable(uid).ifPresent(e -> builder.setUid(uid));
Optional.ofNullable(mediator).ifPresent(e -> builder.setMediator(mediator.toProtoMessage()));
Optional.ofNullable(refundAgent).ifPresent(e -> builder.setRefundAgent(refundAgent.toProtoMessage()));
Optional.ofNullable(arbitrator).ifPresent(e -> builder.setArbitrator(arbitrator.toProtoMessage()));

return getNetworkEnvelopeBuilder()
.setOfferAvailabilityResponse(builder)
Expand All @@ -112,7 +112,7 @@ public static OfferAvailabilityResponse fromProto(protobuf.OfferAvailabilityResp
Capabilities.fromIntList(proto.getSupportedCapabilitiesList()),
messageVersion,
proto.getUid().isEmpty() ? null : proto.getUid(),
NodeAddress.fromProto(proto.getArbitrator()),
proto.hasArbitrator() ? NodeAddress.fromProto(proto.getArbitrator()) : null,
proto.hasMediator() ? NodeAddress.fromProto(proto.getMediator()) : null,
proto.hasRefundAgent() ? NodeAddress.fromProto(proto.getRefundAgent()) : null);
}
Expand Down
Expand Up @@ -20,6 +20,7 @@
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.TradeWalletService;
import bisq.core.dao.DaoFacade;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferBookService;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
Expand Down Expand Up @@ -48,6 +49,7 @@ public class PlaceOfferModel implements Model {
private final OfferBookService offerBookService;
private final ArbitratorManager arbitratorManager;
private final TradeStatisticsManager tradeStatisticsManager;
private final DaoFacade daoFacade;
private final User user;

// Mutable
Expand All @@ -65,6 +67,7 @@ public PlaceOfferModel(Offer offer,
OfferBookService offerBookService,
ArbitratorManager arbitratorManager,
TradeStatisticsManager tradeStatisticsManager,
DaoFacade daoFacade,
User user) {
this.offer = offer;
this.reservedFundsForOffer = reservedFundsForOffer;
Expand All @@ -75,6 +78,7 @@ public PlaceOfferModel(Offer offer,
this.offerBookService = offerBookService;
this.arbitratorManager = arbitratorManager;
this.tradeStatisticsManager = tradeStatisticsManager;
this.daoFacade = daoFacade;
this.user = user;
}

Expand Down
Expand Up @@ -25,11 +25,10 @@
import bisq.core.btc.wallet.TxBroadcaster;
import bisq.core.btc.wallet.WalletService;
import bisq.core.dao.exceptions.DaoDisabledException;
import bisq.core.dao.governance.param.Param;
import bisq.core.dao.state.model.blockchain.TxType;
import bisq.core.offer.Offer;
import bisq.core.offer.availability.DisputeAgentSelection;
import bisq.core.offer.placeoffer.PlaceOfferModel;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;

import bisq.common.UserThread;
import bisq.common.taskrunner.Task;
Expand All @@ -45,7 +44,6 @@

public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
private static final Logger log = LoggerFactory.getLogger(CreateMakerFeeTx.class);
private Transaction tradeFeeTx = null;

@SuppressWarnings({"unused"})
public CreateMakerFeeTx(TaskRunner taskHandler, PlaceOfferModel model) {
Expand All @@ -62,25 +60,23 @@ protected void run() {
String id = offer.getId();
BtcWalletService walletService = model.getWalletService();

Arbitrator arbitrator = DisputeAgentSelection.getLeastUsedArbitrator(model.getTradeStatisticsManager(),
model.getArbitratorManager());

Address fundingAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING).getAddress();
Address reservedForTradeAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE).getAddress();
Address changeAddress = walletService.getFreshAddressEntry().getAddress();

final TradeWalletService tradeWalletService = model.getTradeWalletService();
TradeWalletService tradeWalletService = model.getTradeWalletService();
String feeReceiver = model.getDaoFacade().getParamValue(Param.RECIPIENT_BTC_ADDRESS);

if (offer.isCurrencyForMakerFeeBtc()) {
tradeFeeTx = tradeWalletService.createBtcTradingFeeTx(
tradeWalletService.createBtcTradingFeeTx(
fundingAddress,
reservedForTradeAddress,
changeAddress,
model.getReservedFundsForOffer(),
model.isUseSavingsWallet(),
offer.getMakerFee(),
offer.getTxFee(),
arbitrator.getBtcAddress(),
feeReceiver,
true,
new TxBroadcaster.Callback() {
@Override
Expand Down