forked from Qortal/qortal
WIP: trade-bot: initial API call for listing completed trades
Also: renamed trade bot field/column "receiving_public_key_hash" to "receiving_account_info" as Alice's trade bot uses it to store Alice's Qortal address, not PKH. Added some extra simplistic repository calls to support above, like BlockRepository.getTimestampFromHeight, ATRepository.getCreatorPublicKey(atAddress)
This commit is contained in:
parent
e9c85c946e
commit
ea9b0d4588
@ -0,0 +1,43 @@
|
||||
package org.qortal.api.model;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.qortal.data.crosschain.CrossChainTradeData;
|
||||
|
||||
// All properties to be converted to JSON via JAXB
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class CrossChainTradeSummary {
|
||||
|
||||
private long tradeTimestamp;
|
||||
|
||||
@XmlJavaTypeAdapter(value = org.qortal.api.AmountTypeAdapter.class)
|
||||
private long qortAmount;
|
||||
|
||||
@XmlJavaTypeAdapter(value = org.qortal.api.AmountTypeAdapter.class)
|
||||
private long btcAmount;
|
||||
|
||||
protected CrossChainTradeSummary() {
|
||||
/* For JAXB */
|
||||
}
|
||||
|
||||
public CrossChainTradeSummary(CrossChainTradeData crossChainTradeData, long timestamp) {
|
||||
this.tradeTimestamp = timestamp;
|
||||
this.qortAmount = crossChainTradeData.qortAmount;
|
||||
this.btcAmount = crossChainTradeData.expectedBitcoin;
|
||||
}
|
||||
|
||||
public long getTradeTimestamp() {
|
||||
return this.tradeTimestamp;
|
||||
}
|
||||
|
||||
public long getQortAmount() {
|
||||
return this.qortAmount;
|
||||
}
|
||||
|
||||
public long getBtcAmount() {
|
||||
return this.btcAmount;
|
||||
}
|
||||
|
||||
}
|
@ -43,6 +43,7 @@ import org.qortal.api.Security;
|
||||
import org.qortal.api.model.CrossChainCancelRequest;
|
||||
import org.qortal.api.model.CrossChainSecretRequest;
|
||||
import org.qortal.api.model.CrossChainTradeRequest;
|
||||
import org.qortal.api.model.CrossChainTradeSummary;
|
||||
import org.qortal.api.model.TradeBotCreateRequest;
|
||||
import org.qortal.api.model.TradeBotRespondRequest;
|
||||
import org.qortal.api.model.CrossChainBitcoinP2SHStatus;
|
||||
@ -57,6 +58,7 @@ import org.qortal.crosschain.BTCACCT;
|
||||
import org.qortal.crosschain.BTCP2SH;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.at.ATData;
|
||||
import org.qortal.data.at.ATStateData;
|
||||
import org.qortal.data.crosschain.CrossChainTradeData;
|
||||
import org.qortal.data.crosschain.TradeBotData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
@ -92,7 +94,6 @@ public class CrossChainResource {
|
||||
summary = "Find cross-chain trade offers",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
description = "automated transactions",
|
||||
content = @Content(
|
||||
array = @ArraySchema(
|
||||
schema = @Schema(
|
||||
@ -1099,6 +1100,54 @@ public class CrossChainResource {
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/trades")
|
||||
@Operation(
|
||||
summary = "Find completed cross-chain trades",
|
||||
description = "Returns summary info about successfully completed cross-chain trades",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
array = @ArraySchema(
|
||||
schema = @Schema(
|
||||
implementation = CrossChainTradeSummary.class
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE})
|
||||
public List<CrossChainTradeSummary> getCompletedTrades(
|
||||
@Parameter( ref = "limit") @QueryParam("limit") Integer limit,
|
||||
@Parameter( ref = "offset" ) @QueryParam("offset") Integer offset,
|
||||
@Parameter( ref = "reverse" ) @QueryParam("reverse") Boolean reverse) {
|
||||
// Impose a limit on 'limit'
|
||||
if (limit != null && limit > 100)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
|
||||
byte[] codeHash = BTCACCT.CODE_BYTES_HASH;
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
List<ATStateData> atStates = repository.getATRepository().getMatchingFinalATStates(codeHash, BTCACCT.MODE_BYTE_OFFSET, (long) BTCACCT.Mode.REDEEMED.value, limit, offset, reverse);
|
||||
|
||||
List<CrossChainTradeSummary> crossChainTrades = new ArrayList<>();
|
||||
for (ATStateData atState : atStates) {
|
||||
CrossChainTradeData crossChainTradeData = BTCACCT.populateTradeData(repository, atState);
|
||||
|
||||
// We also need block timestamp for use as trade timestamp
|
||||
long timestamp = repository.getBlockRepository().getTimestampFromHeight(atState.getHeight());
|
||||
|
||||
CrossChainTradeSummary crossChainTradeSummary = new CrossChainTradeSummary(crossChainTradeData, timestamp);
|
||||
crossChainTrades.add(crossChainTradeSummary);
|
||||
}
|
||||
|
||||
return crossChainTrades;
|
||||
} catch (DataException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
||||
}
|
||||
}
|
||||
|
||||
private ATData fetchAtDataWithChecking(Repository repository, String atAddress) throws DataException {
|
||||
ATData atData = repository.getATRepository().fromATAddress(atAddress);
|
||||
if (atData == null)
|
||||
|
@ -718,7 +718,7 @@ public class TradeBot {
|
||||
Coin redeemAmount = Coin.ZERO; // The real funds are in P2SH-A
|
||||
ECKey redeemKey = ECKey.fromPrivate(tradeBotData.getTradePrivateKey());
|
||||
List<TransactionOutput> fundingOutputs = BTC.getInstance().getUnspentOutputs(p2shAddress);
|
||||
byte[] receivePublicKeyHash = tradeBotData.getReceivingPublicKeyHash();
|
||||
byte[] receivePublicKeyHash = tradeBotData.getReceivingAccountInfo();
|
||||
|
||||
Transaction p2shRedeemTransaction = BTCP2SH.buildRedeemTransaction(redeemAmount, redeemKey, fundingOutputs, redeemScriptBytes, tradeBotData.getSecret(), receivePublicKeyHash);
|
||||
|
||||
@ -787,7 +787,7 @@ public class TradeBot {
|
||||
|
||||
// Send 'redeem' MESSAGE to AT using both secrets
|
||||
byte[] secretA = tradeBotData.getSecret();
|
||||
String qortalReceiveAddress = Base58.encode(tradeBotData.getReceivingPublicKeyHash()); // Actually contains whole address, not just PKH
|
||||
String qortalReceiveAddress = Base58.encode(tradeBotData.getReceivingAccountInfo()); // Actually contains whole address, not just PKH
|
||||
byte[] messageData = BTCACCT.buildRedeemMessage(secretA, secretB, qortalReceiveAddress);
|
||||
|
||||
PrivateKeyAccount sender = new PrivateKeyAccount(repository, tradeBotData.getTradePrivateKey());
|
||||
@ -873,7 +873,7 @@ public class TradeBot {
|
||||
Coin redeemAmount = Coin.valueOf(crossChainTradeData.expectedBitcoin);
|
||||
ECKey redeemKey = ECKey.fromPrivate(tradeBotData.getTradePrivateKey());
|
||||
List<TransactionOutput> fundingOutputs = BTC.getInstance().getUnspentOutputs(p2shAddress);
|
||||
byte[] receivePublicKeyHash = tradeBotData.getReceivingPublicKeyHash();
|
||||
byte[] receivePublicKeyHash = tradeBotData.getReceivingAccountInfo();
|
||||
|
||||
Transaction p2shRedeemTransaction = BTCP2SH.buildRedeemTransaction(redeemAmount, redeemKey, fundingOutputs, redeemScriptBytes, secretA, receivePublicKeyHash);
|
||||
|
||||
|
@ -108,6 +108,11 @@ public class BTCACCT {
|
||||
public static final int MIN_LOCKTIME = 1500000000;
|
||||
public static final byte[] CODE_BYTES_HASH = HashCode.fromString("fad14381b77ae1a2bfe7e16a1a8b571839c5f405fca0490ead08499ac170f65b").asBytes(); // SHA256 of AT code bytes
|
||||
|
||||
/** <b>Value</b> offset into AT segment where 'mode' variable (long) is stored. (Multiply by MachineState.VALUE_SIZE for byte offset). */
|
||||
private static final int MODE_VALUE_OFFSET = 63;
|
||||
/** <b>Byte</b> offset into AT state data where 'mode' variable (long) is stored. */
|
||||
public static final int MODE_BYTE_OFFSET = MachineState.HEADER_LENGTH + (MODE_VALUE_OFFSET * MachineState.VALUE_SIZE);
|
||||
|
||||
public static class OfferMessageData {
|
||||
public byte[] partnerBitcoinPKH;
|
||||
public byte[] hashOfSecretA;
|
||||
@ -235,6 +240,7 @@ public class BTCACCT {
|
||||
addrCounter += 4;
|
||||
|
||||
final int addrMode = addrCounter++;
|
||||
assert addrMode == MODE_VALUE_OFFSET : "MODE_VALUE_OFFSET does not match addrMode";
|
||||
|
||||
// Data segment
|
||||
ByteBuffer dataByteBuffer = ByteBuffer.allocate(addrCounter * MachineState.VALUE_SIZE);
|
||||
@ -584,18 +590,40 @@ public class BTCACCT {
|
||||
* @throws DataException
|
||||
*/
|
||||
public static CrossChainTradeData populateTradeData(Repository repository, ATData atData) throws DataException {
|
||||
String atAddress = atData.getATAddress();
|
||||
ATStateData atStateData = repository.getATRepository().getLatestATState(atData.getATAddress());
|
||||
return populateTradeData(repository, atData.getCreatorPublicKey(), atStateData);
|
||||
}
|
||||
|
||||
ATStateData atStateData = repository.getATRepository().getLatestATState(atAddress);
|
||||
byte[] stateData = atStateData.getStateData();
|
||||
/**
|
||||
* Returns CrossChainTradeData with useful info extracted from AT.
|
||||
*
|
||||
* @param repository
|
||||
* @param atAddress
|
||||
* @throws DataException
|
||||
*/
|
||||
public static CrossChainTradeData populateTradeData(Repository repository, ATStateData atStateData) throws DataException {
|
||||
byte[] creatorPublicKey = repository.getATRepository().getCreatorPublicKey(atStateData.getATAddress());
|
||||
return populateTradeData(repository, creatorPublicKey, atStateData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns CrossChainTradeData with useful info extracted from AT.
|
||||
*
|
||||
* @param repository
|
||||
* @param atAddress
|
||||
* @throws DataException
|
||||
*/
|
||||
public static CrossChainTradeData populateTradeData(Repository repository, byte[] creatorPublicKey, ATStateData atStateData) throws DataException {
|
||||
String atAddress = atStateData.getATAddress();
|
||||
|
||||
QortalAtLoggerFactory loggerFactory = QortalAtLoggerFactory.getInstance();
|
||||
byte[] stateData = atStateData.getStateData();
|
||||
byte[] dataBytes = MachineState.extractDataBytes(loggerFactory, stateData);
|
||||
|
||||
CrossChainTradeData tradeData = new CrossChainTradeData();
|
||||
tradeData.qortalAtAddress = atAddress;
|
||||
tradeData.qortalCreator = Crypto.toAddress(atData.getCreatorPublicKey());
|
||||
tradeData.creationTimestamp = atData.getCreation();
|
||||
tradeData.qortalCreator = Crypto.toAddress(creatorPublicKey);
|
||||
tradeData.creationTimestamp = atStateData.getCreation();
|
||||
|
||||
Account atAccount = new Account(repository, atAddress);
|
||||
tradeData.qortBalance = atAccount.getConfirmedBalance(Asset.QORT);
|
||||
|
@ -58,7 +58,7 @@ public class TradeBotData {
|
||||
private Integer lockTimeA;
|
||||
|
||||
// Could be Bitcoin or Qortal...
|
||||
private byte[] receivingPublicKeyHash;
|
||||
private byte[] receivingAccountInfo;
|
||||
|
||||
protected TradeBotData() {
|
||||
/* JAXB */
|
||||
@ -68,7 +68,7 @@ public class TradeBotData {
|
||||
byte[] tradeNativePublicKey, byte[] tradeNativePublicKeyHash, String tradeNativeAddress,
|
||||
byte[] secret, byte[] hashOfSecret,
|
||||
byte[] tradeForeignPublicKey, byte[] tradeForeignPublicKeyHash,
|
||||
long bitcoinAmount, String xprv58, byte[] lastTransactionSignature, Integer lockTimeA, byte[] receivingPublicKeyHash) {
|
||||
long bitcoinAmount, String xprv58, byte[] lastTransactionSignature, Integer lockTimeA, byte[] receivingAccountInfo) {
|
||||
this.tradePrivateKey = tradePrivateKey;
|
||||
this.tradeState = tradeState;
|
||||
this.atAddress = atAddress;
|
||||
@ -83,7 +83,7 @@ public class TradeBotData {
|
||||
this.xprv58 = xprv58;
|
||||
this.lastTransactionSignature = lastTransactionSignature;
|
||||
this.lockTimeA = lockTimeA;
|
||||
this.receivingPublicKeyHash = receivingPublicKeyHash;
|
||||
this.receivingAccountInfo = receivingAccountInfo;
|
||||
}
|
||||
|
||||
public byte[] getTradePrivateKey() {
|
||||
@ -158,8 +158,8 @@ public class TradeBotData {
|
||||
this.lockTimeA = lockTimeA;
|
||||
}
|
||||
|
||||
public byte[] getReceivingPublicKeyHash() {
|
||||
return this.receivingPublicKeyHash;
|
||||
public byte[] getReceivingAccountInfo() {
|
||||
return this.receivingAccountInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ public interface ATRepository {
|
||||
/** Returns where AT with passed address exists in repository */
|
||||
public boolean exists(String atAddress) throws DataException;
|
||||
|
||||
/** Returns AT creator's public key, or null if not found */
|
||||
public byte[] getCreatorPublicKey(String atAddress) throws DataException;
|
||||
|
||||
/** Returns list of executable ATs, empty if none found */
|
||||
public List<ATData> getAllExecutableATs() throws DataException;
|
||||
|
||||
@ -54,6 +57,24 @@ public interface ATRepository {
|
||||
*/
|
||||
public ATStateData getLatestATState(String atAddress) throws DataException;
|
||||
|
||||
/**
|
||||
* Returns final ATStateData for ATs matching codeHash (required)
|
||||
* and specific data segment value (optional).
|
||||
* <p>
|
||||
* If searching for specific data segment value, both <tt>dataByteOffset</tt>
|
||||
* and <tt>expectedValue</tt> need to be non-null.
|
||||
* <p>
|
||||
* Note that <tt>dataByteOffset</tt> starts from 0 and will typically be
|
||||
* a multiple of <tt>MachineState.VALUE_SIZE</tt>, which is usually 8:
|
||||
* width of a long.
|
||||
* <p>
|
||||
* Although <tt>expectedValue</tt>, if provided, is natively an unsigned long,
|
||||
* the data segment comparison is done via unsigned hex string.
|
||||
*/
|
||||
public List<ATStateData> getMatchingFinalATStates(byte[] codeHash,
|
||||
Integer dataByteOffset, Long expectedValue,
|
||||
Integer limit, Integer offset, Boolean reverse) throws DataException;
|
||||
|
||||
/**
|
||||
* Returns all ATStateData for a given block height.
|
||||
* <p>
|
||||
|
@ -60,6 +60,15 @@ public interface BlockRepository {
|
||||
*/
|
||||
public int getHeightFromTimestamp(long timestamp) throws DataException;
|
||||
|
||||
/**
|
||||
* Returns block timestamp for a given height.
|
||||
*
|
||||
* @param height
|
||||
* @return timestamp, or 0 if height is out of bounds.
|
||||
* @throws DataException
|
||||
*/
|
||||
public long getTimestampFromHeight(int height) throws DataException;
|
||||
|
||||
/**
|
||||
* Return highest block height from repository.
|
||||
*
|
||||
|
@ -68,6 +68,20 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getCreatorPublicKey(String atAddress) throws DataException {
|
||||
String sql = "SELECT creator FROM ATs WHERE AT_address = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, atAddress)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
return resultSet.getBytes(1);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch AT creator's public key from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ATData> getAllExecutableATs() throws DataException {
|
||||
String sql = "SELECT AT_address, creator, created_when, version, asset_id, code_bytes, code_hash, "
|
||||
@ -273,6 +287,68 @@ public class HSQLDBATRepository implements ATRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ATStateData> getMatchingFinalATStates(byte[] codeHash,
|
||||
Integer dataByteOffset, Long expectedValue,
|
||||
Integer limit, Integer offset, Boolean reverse) throws DataException {
|
||||
StringBuilder sql = new StringBuilder(1024);
|
||||
sql.append("SELECT AT_address, height, created_when, state_data, state_hash, fees, is_initial "
|
||||
+ "FROM ATs "
|
||||
+ "CROSS JOIN LATERAL("
|
||||
+ "SELECT height, created_when, state_data, state_hash, fees, is_initial "
|
||||
+ "FROM ATStates "
|
||||
+ "WHERE ATStates.AT_address = ATs.AT_address "
|
||||
+ "ORDER BY height DESC "
|
||||
+ "LIMIT 1"
|
||||
+ ") AS FinalATStates "
|
||||
+ "WHERE code_hash = ? AND is_finished ");
|
||||
|
||||
Object[] bindParams;
|
||||
|
||||
if (dataByteOffset != null && expectedValue != null) {
|
||||
sql.append("AND RAWTOHEX(SUBSTRING(state_data FROM ? FOR 8)) = ? ");
|
||||
|
||||
// We convert our long to hex Java-side to control endian
|
||||
String expectedHexValue = String.format("%016x", expectedValue); // left-zero-padding and conversion
|
||||
|
||||
// SQL binary data offsets start at 1
|
||||
bindParams = new Object[] { codeHash, dataByteOffset + 1, expectedHexValue };
|
||||
} else {
|
||||
bindParams = new Object[] { codeHash };
|
||||
}
|
||||
|
||||
sql.append(" ORDER BY height ");
|
||||
if (reverse != null && reverse)
|
||||
sql.append("DESC");
|
||||
|
||||
HSQLDBRepository.limitOffsetSql(sql, limit, offset);
|
||||
|
||||
List<ATStateData> atStates = new ArrayList<>();
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql.toString(), bindParams)) {
|
||||
if (resultSet == null)
|
||||
return atStates;
|
||||
|
||||
do {
|
||||
String atAddress = resultSet.getString(1);
|
||||
int height = resultSet.getInt(2);
|
||||
long created = resultSet.getLong(3);
|
||||
byte[] stateData = resultSet.getBytes(4); // Actually BLOB
|
||||
byte[] stateHash = resultSet.getBytes(5);
|
||||
long fees = resultSet.getLong(6);
|
||||
boolean isInitial = resultSet.getBoolean(7);
|
||||
|
||||
ATStateData atStateData = new ATStateData(atAddress, height, created, stateData, stateHash, fees, isInitial);
|
||||
|
||||
atStates.add(atStateData);
|
||||
} while (resultSet.next());
|
||||
|
||||
return atStates;
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch matching AT states from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ATStateData> getBlockATStatesAtHeight(int height) throws DataException {
|
||||
String sql = "SELECT AT_address, state_hash, fees, is_initial "
|
||||
|
@ -131,6 +131,20 @@ public class HSQLDBBlockRepository implements BlockRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestampFromHeight(int height) throws DataException {
|
||||
String sql = "SELECT minted_when FROM Blocks WHERE height = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, height)) {
|
||||
if (resultSet == null)
|
||||
return 0;
|
||||
|
||||
return resultSet.getLong(1);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Error obtaining block timestamp by height from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockchainHeight() throws DataException {
|
||||
String sql = "SELECT height FROM Blocks ORDER BY height DESC LIMIT 1";
|
||||
|
@ -23,7 +23,7 @@ public class HSQLDBCrossChainRepository implements CrossChainRepository {
|
||||
+ "trade_native_public_key, trade_native_public_key_hash, "
|
||||
+ "trade_native_address, secret, hash_of_secret, "
|
||||
+ "trade_foreign_public_key, trade_foreign_public_key_hash, "
|
||||
+ "bitcoin_amount, xprv58, last_transaction_signature, locktime_a, receiving_public_key_hash "
|
||||
+ "bitcoin_amount, xprv58, last_transaction_signature, locktime_a, receiving_account_info "
|
||||
+ "FROM TradeBotStates "
|
||||
+ "WHERE trade_private_key = ?";
|
||||
|
||||
@ -50,14 +50,14 @@ public class HSQLDBCrossChainRepository implements CrossChainRepository {
|
||||
Integer lockTimeA = resultSet.getInt(13);
|
||||
if (lockTimeA == 0 && resultSet.wasNull())
|
||||
lockTimeA = null;
|
||||
byte[] receivingPublicKeyHash = resultSet.getBytes(14);
|
||||
byte[] receivingAccountInfo = resultSet.getBytes(14);
|
||||
|
||||
return new TradeBotData(tradePrivateKey, tradeState,
|
||||
atAddress,
|
||||
tradeNativePublicKey, tradeNativePublicKeyHash, tradeNativeAddress,
|
||||
secret, hashOfSecret,
|
||||
tradeForeignPublicKey, tradeForeignPublicKeyHash,
|
||||
bitcoinAmount, xprv58, lastTransactionSignature, lockTimeA, receivingPublicKeyHash);
|
||||
bitcoinAmount, xprv58, lastTransactionSignature, lockTimeA, receivingAccountInfo);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch trade-bot trading state from repository", e);
|
||||
}
|
||||
@ -69,7 +69,7 @@ public class HSQLDBCrossChainRepository implements CrossChainRepository {
|
||||
+ "trade_native_public_key, trade_native_public_key_hash, "
|
||||
+ "trade_native_address, secret, hash_of_secret, "
|
||||
+ "trade_foreign_public_key, trade_foreign_public_key_hash, "
|
||||
+ "bitcoin_amount, xprv58, last_transaction_signature, locktime_a, receiving_public_key_hash "
|
||||
+ "bitcoin_amount, xprv58, last_transaction_signature, locktime_a, receiving_account_info "
|
||||
+ "FROM TradeBotStates";
|
||||
|
||||
List<TradeBotData> allTradeBotData = new ArrayList<>();
|
||||
@ -99,14 +99,14 @@ public class HSQLDBCrossChainRepository implements CrossChainRepository {
|
||||
Integer lockTimeA = resultSet.getInt(14);
|
||||
if (lockTimeA == 0 && resultSet.wasNull())
|
||||
lockTimeA = null;
|
||||
byte[] receivingPublicKeyHash = resultSet.getBytes(15);
|
||||
byte[] receivingAccountInfo = resultSet.getBytes(15);
|
||||
|
||||
TradeBotData tradeBotData = new TradeBotData(tradePrivateKey, tradeState,
|
||||
atAddress,
|
||||
tradeNativePublicKey, tradeNativePublicKeyHash, tradeNativeAddress,
|
||||
secret, hashOfSecret,
|
||||
tradeForeignPublicKey, tradeForeignPublicKeyHash,
|
||||
bitcoinAmount, xprv58, lastTransactionSignature, lockTimeA, receivingPublicKeyHash);
|
||||
bitcoinAmount, xprv58, lastTransactionSignature, lockTimeA, receivingAccountInfo);
|
||||
allTradeBotData.add(tradeBotData);
|
||||
} while (resultSet.next());
|
||||
|
||||
@ -133,7 +133,7 @@ public class HSQLDBCrossChainRepository implements CrossChainRepository {
|
||||
.bind("xprv58", tradeBotData.getXprv58())
|
||||
.bind("last_transaction_signature", tradeBotData.getLastTransactionSignature())
|
||||
.bind("locktime_a", tradeBotData.getLockTimeA())
|
||||
.bind("receiving_public_key_hash", tradeBotData.getReceivingPublicKeyHash());
|
||||
.bind("receiving_account_info", tradeBotData.getReceivingAccountInfo());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
|
@ -626,7 +626,19 @@ public class HSQLDBDatabaseUpdates {
|
||||
+ "trade_native_address QortalAddress NOT NULL, secret VARBINARY(32) NOT NULL, hash_of_secret VARBINARY(32) NOT NULL, "
|
||||
+ "trade_foreign_public_key VARBINARY(33) NOT NULL, trade_foreign_public_key_hash VARBINARY(32) NOT NULL, "
|
||||
+ "bitcoin_amount BIGINT NOT NULL, xprv58 VARCHAR(200), last_transaction_signature Signature, locktime_a BIGINT, "
|
||||
+ "receiving_public_key_hash VARBINARY(32) NOT NULL, PRIMARY KEY (trade_private_key))");
|
||||
+ "receiving_account_info VARBINARY(32) NOT NULL, PRIMARY KEY (trade_private_key))");
|
||||
break;
|
||||
|
||||
case 21:
|
||||
// AT functionality index
|
||||
stmt.execute("CREATE INDEX IF NOT EXISTS ATCodeHashIndex ON ATs (code_hash, is_finished)");
|
||||
break;
|
||||
|
||||
case 22:
|
||||
// XXX for testing only - do not merge in 'master'
|
||||
stmt.execute("ALTER TABLE TradeBotStates ADD COLUMN IF NOT EXISTS receiving_public_key_hash VARBINARY(32)");
|
||||
stmt.execute("ALTER TABLE TradeBotStates DROP COLUMN receiving_public_key_hash");
|
||||
stmt.execute("ALTER TABLE TradeBotStates ADD COLUMN IF NOT EXISTS receiving_account_info VARBINARY(32)");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user