From 08df53730befccf2dbb23cc4a4e1ed668dda372a Mon Sep 17 00:00:00 2001 From: hvarona Date: Fri, 30 Nov 2018 20:58:13 -0400 Subject: [PATCH] Fix send bad request Change Send manager to send only the required amount from gtxio added error capture for estimatefee --- .../insightapi/GetEstimateFee.java | 8 +- .../InsightApiServiceGenerator.java | 4 +- .../application/CrystalApplication.java | 2 +- .../fragments/SendTransactionFragment.java | 2 + .../manager/GeneralAccountManager.java | 180 ++++++++++-------- .../requestmanagers/BitcoinSendRequest.java | 2 +- 6 files changed, 115 insertions(+), 83 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java index e827d73..45e7d03 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetEstimateFee.java @@ -35,14 +35,18 @@ public abstract class GetEstimateFee { call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { - listener.estimateFee((double) (response.body().get("2").getAsDouble())); + try { + listener.estimateFee((double) (response.body().get("2").getAsDouble())); + }catch (Exception e){ + e.printStackTrace(); + listener.fail(); + } } @Override public void onFailure(Call call, Throwable t) { listener.fail(); - listener.estimateFee(-1); } }); }catch(Exception e){ diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/InsightApiServiceGenerator.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/InsightApiServiceGenerator.java index 7eea5c6..714029b 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/InsightApiServiceGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/InsightApiServiceGenerator.java @@ -97,8 +97,8 @@ class InsightApiServiceGenerator { return chain.proceed(request); } }); - sClientBuilder.readTimeout(5, TimeUnit.MINUTES); - sClientBuilder.connectTimeout(5, TimeUnit.MINUTES); + sClientBuilder.readTimeout(30, TimeUnit.SECONDS); + sClientBuilder.connectTimeout(30, TimeUnit.SECONDS); OkHttpClient client = sClientBuilder.build(); Retrofit retrofit = sBuilder.client(client).build(); return retrofit.create(serviceClass); diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java index 4a96646..d576b44 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java +++ b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java @@ -52,8 +52,8 @@ public class CrystalApplication extends Application { public static final String BITCOIN_SERVER_URLS[] ={ + "https://testnet.blockexplorer.com/", "https://test-insight.bitpay.com", - //"https://testnet.blockexplorer.com/", //"https://insight.bitpay.com/" }; diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java index 1d764bc..4812dc8 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java @@ -545,6 +545,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat throwable.printStackTrace(); } } else { + crystalDialog.dismiss(); Toast.makeText(getContext(), getContext().getString(R.string.unable_to_send_amount), Toast.LENGTH_LONG); } } @@ -577,6 +578,7 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat throwable.printStackTrace(); } } else { + crystalDialog.dismiss(); Toast.makeText(getContext(), getContext().getString(R.string.unable_to_send_amount), Toast.LENGTH_LONG); } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java index 716c3a2..41f1877 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java @@ -241,11 +241,12 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf ccTransaction.setAccountId(address.getAccountId()); ccTransaction.setFrom(addr); ccTransaction.setInput(false); + amount -= (long) (txi.fee * Math.pow(10, cryptoCoin.getPrecision())); } - if (ccTransaction.getAccountId() == address.getAccountId()) { + //if (ccTransaction.getAccountId() == address.getAccountId()) { amount -= (long) (vin.value * Math.pow(10, cryptoCoin.getPrecision())); - } + //} } if (ccTransaction.getFrom() == null || ccTransaction.getFrom().isEmpty()) { @@ -280,9 +281,9 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf ccTransaction.setTo(addr); } - if (ccTransaction.getAccountId() == address.getAccountId()) { + //if (ccTransaction.getAccountId() == address.getAccountId()) { amount += (long) (vout.value * Math.pow(10, cryptoCoin.getPrecision())); - } + //} } else { //TOOD multiple send address if (ccTransaction.getTo() == null || ccTransaction.getTo().isEmpty()) { @@ -374,39 +375,52 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf //TODO check server connection //TODO validate to address + System.out.println("GeneralAccount Manager Send request, asking fee"); InsightApiGenerator.getEstimateFee(this.cryptoCoin,new ApiRequest(1, new ApiRequestListener() { @Override public void success(Object answer, int idPetition) { - Transaction tx = new Transaction(cryptoCoin.getParameters()); - long currentAmount = 0; - long fee = -1; - long feeRate = (long)(((double)answer) * Math.pow(10,cryptoCoin.getPrecision())); - fee = 226 * feeRate; + System.out.println("GeneralAccount Manager Send request, fee " + answer.toString()); + try { + Transaction tx = new Transaction(cryptoCoin.getParameters()); + long currentAmount = 0; + long fee = -1; + long feeRate = (long) (((double) answer) * Math.pow(10, cryptoCoin.getPrecision())); + fee = 226 * feeRate; - CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); - db.bitcoinTransactionDao(); + System.out.println("GeneralAccount Manager Send request getting utxos" ); + CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); + db.bitcoinTransactionDao(); - List utxos = getUtxos(request.getSourceAccount().getId(),db); + List utxos = getUtxos(request.getSourceAccount().getId(), db); + System.out.println("GeneralAccount Manager Send request utxos found " + utxos.size() ); + for(BitcoinTransactionGTxIO utxo : utxos){ + currentAmount += utxo.getAmount(); + if(currentAmount >= request.getAmount() + fee) { + break; + } + } - if(currentAmount< request.getAmount() + fee){ - request.setStatus(BitcoinSendRequest.StatusCode.NO_BALANCE); - return; - } - AccountSeed seed = db.accountSeedDao().findById(request.getSourceAccount().getSeedId()); - DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(), - new ChildNumber(44, true)); - DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey, - new ChildNumber(cryptoCoin.getCoinNumber(), true)); - DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey, - new ChildNumber(request.getSourceAccount().getAccountIndex(), true)); - DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, - new ChildNumber(0, false)); - DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey, - new ChildNumber(1, false)); + if (currentAmount < request.getAmount() + fee) { + System.out.println("GeneralAccount Manager Send request no balance" ); + request.setStatus(BitcoinSendRequest.StatusCode.NO_BALANCE); + return; + } - //String to an address - Address toAddr = Address.fromBase58(cryptoCoin.getParameters(), request.getToAccount()); - tx.addOutput(Coin.valueOf(request.getAmount()), toAddr); + AccountSeed seed = db.accountSeedDao().findById(request.getSourceAccount().getSeedId()); + DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(), + new ChildNumber(44, true)); + DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey, + new ChildNumber(cryptoCoin.getCoinNumber(), true)); + DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey, + new ChildNumber(request.getSourceAccount().getAccountIndex(), true)); + DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, + new ChildNumber(0, false)); + DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey, + new ChildNumber(1, false)); + + //String to an address + Address toAddr = Address.fromBase58(cryptoCoin.getParameters(), request.getToAccount()); + tx.addOutput(Coin.valueOf(request.getAmount()), toAddr); /*if(request.getMemo()!= null && !request.getMemo().isEmpty()){ String memo = request.getMemo(); @@ -421,62 +435,74 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf tx.addOutput(Coin.valueOf(0),memoScript); }*/ - //Change address - long remain = currentAmount - request.getAmount() - fee; - if( remain > 0 ) { - long index = db.bitcoinAddressDao().getLastChangeAddress(request.getSourceAccount().getId()); - BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index); - Address changeAddr; - if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){ + //Change address + long remain = currentAmount - request.getAmount() - fee; + if (remain > 0) { + long index = db.bitcoinAddressDao().getLastChangeAddress(request.getSourceAccount().getId()); + BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index); + Address changeAddr; + if (btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size() <= 0) { changeAddr = Address.fromBase58(cryptoCoin.getParameters(), btAddress.getAddress()); - }else{ - if(btAddress == null){ - index = 0; - }else{ - index++; + } else { + if (btAddress == null) { + index = 0; + } else { + index++; + } + btAddress = new BitcoinAddress(); + btAddress.setIndex(index); + btAddress.setAccountId(request.getSourceAccount().getId()); + btAddress.setChange(true); + btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString()); + db.bitcoinAddressDao().insertBitcoinAddresses(btAddress); + changeAddr = Address.fromBase58(cryptoCoin.getParameters(), btAddress.getAddress()); } - btAddress = new BitcoinAddress(); - btAddress.setIndex(index); - btAddress.setAccountId(request.getSourceAccount().getId()); - btAddress.setChange(true); - btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString()); - db.bitcoinAddressDao().insertBitcoinAddresses(btAddress); - changeAddr = Address.fromBase58(cryptoCoin.getParameters(), btAddress.getAddress()); + tx.addOutput(Coin.valueOf(remain), changeAddr); } - tx.addOutput(Coin.valueOf(remain), changeAddr); + + for (BitcoinTransactionGTxIO utxo : utxos) { + Sha256Hash txHash = Sha256Hash.wrap(utxo.getOriginalTxId()); + Script script = new Script(Util.hexToBytes(utxo.getScriptHex())); + TransactionOutPoint outPoint = new TransactionOutPoint(cryptoCoin.getParameters(), utxo.getIndex(), txHash); + BitcoinAddress btAddress = db.bitcoinAddressDao().getdadress(utxo.getAddress()); + ECKey addrKey; + + if (btAddress.isChange()) { + addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)); + } else { + addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) btAddress.getIndex(), true)); + } + tx.addSignedInput(outPoint, script, addrKey, Transaction.SigHash.ALL, true); + currentAmount -= utxo.getAmount(); + if(currentAmount<= 0){ + break; + } + } + + System.out.println("GeneralAccount Manager Send request rawtx " +Util.bytesToHex(tx.bitcoinSerialize()) ); + InsightApiGenerator.broadcastTransaction(cryptoCoin, Util.bytesToHex(tx.bitcoinSerialize()), new ApiRequest(1, new ApiRequestListener() { + @Override + public void success(Object answer, int idPetition) { + System.out.println("GeneralAccount MAnager succed send"); + request.setStatus(BitcoinSendRequest.StatusCode.SUCCEEDED); + } + + @Override + public void fail(int idPetition) { + System.out.println("GeneralAccount MAnager succed fail"); + request.setStatus(BitcoinSendRequest.StatusCode.PETITION_FAILED); + } + })); + }catch(Exception e){ + System.out.println("GeneralAccount Manager Send request error "); + e.printStackTrace(); } - - for(BitcoinTransactionGTxIO utxo: utxos) { - Sha256Hash txHash = Sha256Hash.wrap(utxo.getOriginalTxId()); - Script script = new Script(Util.hexToBytes(utxo.getScriptHex())); - TransactionOutPoint outPoint = new TransactionOutPoint(cryptoCoin.getParameters(), utxo.getIndex(), txHash); - BitcoinAddress btAddress = db.bitcoinAddressDao().getdadress(utxo.getAddress()); - ECKey addrKey; - - if(btAddress.isChange()){ - addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)); - }else{ - addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) btAddress.getIndex(), true)); - } - tx.addSignedInput(outPoint, script, addrKey, Transaction.SigHash.ALL, true); - } - - InsightApiGenerator.broadcastTransaction(cryptoCoin,Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() { - @Override - public void success(Object answer, int idPetition) { - request.setStatus(BitcoinSendRequest.StatusCode.SUCCEEDED); - } - - @Override - public void fail(int idPetition) { - request.setStatus(BitcoinSendRequest.StatusCode.PETITION_FAILED); - } - })); } @Override public void fail(int idPetition) { + System.out.println("GeneralAccount Manager Send request fee fail" ); request.setStatus(BitcoinSendRequest.StatusCode.NO_FEE); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java index 762d107..3d7cabb 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java +++ b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java @@ -89,7 +89,7 @@ public class BitcoinSendRequest extends CryptoNetInfoRequest { public void setStatus(StatusCode code){ this.status = code; - this._fireOnCarryOutEvent(); + this.validate(); } public StatusCode getStatus() {