Program: 10957
Project: 10957
Buggy source:
public Tx buildTx(Address address,String changeAddress,List<Tx> unspendTxs,Tx tx){
  List<Out> outs=TxBuilder.getUnspendOuts(unspendTxs);
  Collections.sort(outs,new Comparator<Out>(){
    public int compare(    Out out1,    Out out2){
      int depth1=0;
      int depth2=0;
      long coinDepth1=BlockChain.getInstance().lastBlock.getBlockNo() * out1.getOutValue() - out1.getCoinDepth() + out1.getOutValue();
      long coinDepth2=BlockChain.getInstance().lastBlock.getBlockNo() * out2.getOutValue() - out2.getCoinDepth() + out2.getOutValue();
      if (coinDepth1 != coinDepth2) {
        return (int)(coinDepth1 - coinDepth2);
      }
 else {
        BigInteger hash1=new BigInteger(1,out1.getTxHash());
        BigInteger hash2=new BigInteger(1,out2.getTxHash());
        int result=hash1.compareTo(hash2);
        if (result != 0) {
          return result;
        }
 else {
          return out1.getOutSn() - out2.getOutSn();
        }
      }
    }
  }
);
  long additionalValueForNextCategory=0;
  List<Out> selection3=null;
  List<Out> selection2=null;
  Out selection2Change=null;
  List<Out> selection1=null;
  Out selection1Change=null;
  int lastCalculatedSize=0;
  long valueNeeded;
  long value=0;
  for (  Out out : tx.getOuts()) {
    value+=out.getOutValue();
  }
  boolean needAtLeastReferenceFee=TxBuilder.needMinFee(tx.getOuts());
  List<Out> bestCoinSelection=null;
  Out bestChangeOutput=null;
  while (true) {
    long fees=0;
    if (lastCalculatedSize >= 1000) {
      fees+=(lastCalculatedSize / 1000 + 1) * Utils.getFeeBase();
    }
    if (needAtLeastReferenceFee && fees < Utils.getFeeBase())     fees=Utils.getFeeBase();
    valueNeeded=value + fees;
    if (additionalValueForNextCategory > 0)     valueNeeded+=additionalValueForNextCategory;
    long additionalValueSelected=additionalValueForNextCategory;
    List<Out> selectedOuts=this.selectOuts(outs,valueNeeded);
    if (TxBuilder.getAmount(selectedOuts) < valueNeeded)     break;
    if (!needAtLeastReferenceFee) {
      long total=TxBuilder.getAmount(selectedOuts);
      if (total - value < Utils.CENT && total - value >= Utils.getFeeBase()) {
        needAtLeastReferenceFee=true;
        continue;
      }
      int s=TxBuilder.estimationTxSize(selectedOuts.size(),tx.getOuts().size());
      if (total - value > Utils.CENT)       s+=34;
      if (TxBuilder.getCoinDepth(selectedOuts) <= TxBuilder.TX_FREE_MIN_PRIORITY * s) {
        needAtLeastReferenceFee=true;
        continue;
      }
    }
    boolean eitherCategory2Or3=false;
    boolean isCategory3=false;
    long change=TxBuilder.getAmount(selectedOuts) - valueNeeded;
    if (additionalValueSelected > 0)     change+=additionalValueSelected;
    if (BitherjSettings.ensureMinRequiredFee && change != 0 && change < Utils.CENT && fees < Utils.getFeeBase()) {
      eitherCategory2Or3=true;
      additionalValueForNextCategory=Utils.CENT;
      change-=Utils.getFeeBase() - fees;
    }
    int size=0;
    Out changeOutput=null;
    if (change > 0) {
      changeOutput=new Out();
      changeOutput.setOutValue(change);
      changeOutput.setOutAddress(changeAddress);
      if (BitherjSettings.ensureMinRequiredFee && Tx.MIN_NONDUST_OUTPUT >= change) {
        isCategory3=true;
        additionalValueForNextCategory=Utils.getFeeBase() + Tx.MIN_NONDUST_OUTPUT + 1;
      }
 else {
        size+=34;
        if (!eitherCategory2Or3)         additionalValueForNextCategory=0;
      }
    }
 else {
      if (eitherCategory2Or3) {
        isCategory3=true;
        additionalValueForNextCategory=Utils.getFeeBase() + 1;
      }
    }
    size+=TxBuilder.estimationTxSize(selectedOuts.size(),tx.getOuts().size());
    if (size / 1000 > lastCalculatedSize / 1000 && Utils.getFeeBase() > 0) {
      lastCalculatedSize=size;
      additionalValueForNextCategory=additionalValueSelected;
      continue;
    }
    if (isCategory3) {
      if (selection3 == null)       selection3=selectedOuts;
    }
 else     if (eitherCategory2Or3) {
      if (selection2 != null) {
        long oldFee=TxBuilder.getAmount(selection2) - selection2Change.getOutValue() - value;
        long newFee=TxBuilder.getAmount(selectedOuts) - changeOutput.getOutValue() - value;
        if (newFee <= oldFee) {
          selection2=selectedOuts;
          selection2Change=changeOutput;
        }
      }
 else {
        selection2=selectedOuts;
        selection2Change=changeOutput;
      }
    }
 else {
      if (selection1 != null) {
        long oldFee=TxBuilder.getAmount(selection1) - value;
        if (selection1Change != null) {
          oldFee-=selection1Change.getOutValue();
        }
        long newFee=TxBuilder.getAmount(selectedOuts) - value;
        if (changeOutput != null) {
          newFee-=changeOutput.getOutValue();
        }
        if (newFee <= oldFee) {
          selection1=selectedOuts;
          selection1Change=changeOutput;
        }
      }
 else {
        selection1=selectedOuts;
        selection1Change=changeOutput;
      }
    }
    if (additionalValueForNextCategory > 0) {
      continue;
    }
    break;
  }
  if (selection3 == null && selection2 == null && selection1 == null) {
    return null;
  }
  long lowestFee=0;
  if (selection1 != null) {
    if (selection1Change != null)     lowestFee=TxBuilder.getAmount(selection1) - selection1Change.getOutValue() - value;
 else     lowestFee=TxBuilder.getAmount(selection1) - value;
    bestCoinSelection=selection1;
    bestChangeOutput=selection1Change;
  }
  if (selection2 != null) {
    long fee=TxBuilder.getAmount(selection2) - selection2Change.getOutValue() - value;
    if (lowestFee == 0 || fee < lowestFee) {
      lowestFee=fee;
      bestCoinSelection=selection2;
      bestChangeOutput=selection2Change;
    }
  }
  if (selection3 != null) {
    if (lowestFee == 0 || TxBuilder.getAmount(selection3) - value < lowestFee) {
      bestCoinSelection=selection3;
      bestChangeOutput=null;
    }
  }
  if (bestChangeOutput != null) {
    tx.addOutput(bestChangeOutput.getOutValue(),bestChangeOutput.getOutAddress());
  }
  for (  Out out : bestCoinSelection) {
    tx.addInput(out);
  }
  tx.setSource(Tx.SourceType.self.getValue());
  return tx;
}

Fixed version (ground truth):
public Tx buildTx(Address address,String changeAddress,List<Tx> unspendTxs,Tx tx){
  List<Out> outs=TxBuilder.getUnspendOuts(unspendTxs);
  Collections.sort(outs,new Comparator<Out>(){
    public int compare(    Out out1,    Out out2){
      int depth1=0;
      int depth2=0;
      long coinDepth1=BlockChain.getInstance().lastBlock.getBlockNo() * out1.getOutValue() - out1.getCoinDepth() + out1.getOutValue();
      long coinDepth2=BlockChain.getInstance().lastBlock.getBlockNo() * out2.getOutValue() - out2.getCoinDepth() + out2.getOutValue();
      if (coinDepth1 != coinDepth2) {
        if (coinDepth2 > coinDepth1)         return 1;
 else         return -1;
      }
 else       if (out1.getOutValue() != out2.getOutValue()) {
        if (out2.getOutValue() > out1.getOutValue())         return 1;
 else         return -1;
      }
 else {
        BigInteger hash1=new BigInteger(1,out1.getTxHash());
        BigInteger hash2=new BigInteger(1,out2.getTxHash());
        int result=hash1.compareTo(hash2);
        if (result != 0) {
          return result;
        }
 else {
          return out1.getOutSn() - out2.getOutSn();
        }
      }
    }
  }
);
  long additionalValueForNextCategory=0;
  List<Out> selection3=null;
  List<Out> selection2=null;
  Out selection2Change=null;
  List<Out> selection1=null;
  Out selection1Change=null;
  int lastCalculatedSize=0;
  long valueNeeded;
  long value=0;
  for (  Out out : tx.getOuts()) {
    value+=out.getOutValue();
  }
  boolean needAtLeastReferenceFee=TxBuilder.needMinFee(tx.getOuts());
  List<Out> bestCoinSelection=null;
  Out bestChangeOutput=null;
  while (true) {
    long fees=0;
    if (lastCalculatedSize >= 1000) {
      fees+=(lastCalculatedSize / 1000 + 1) * Utils.getFeeBase();
    }
    if (needAtLeastReferenceFee && fees < Utils.getFeeBase())     fees=Utils.getFeeBase();
    valueNeeded=value + fees;
    if (additionalValueForNextCategory > 0)     valueNeeded+=additionalValueForNextCategory;
    long additionalValueSelected=additionalValueForNextCategory;
    List<Out> selectedOuts=this.selectOuts(outs,valueNeeded);
    if (TxBuilder.getAmount(selectedOuts) < valueNeeded)     break;
    if (!needAtLeastReferenceFee) {
      long total=TxBuilder.getAmount(selectedOuts);
      if (total - value < Utils.CENT && total - value >= Utils.getFeeBase()) {
        needAtLeastReferenceFee=true;
        continue;
      }
      int s=TxBuilder.estimationTxSize(selectedOuts.size(),tx.getOuts().size());
      if (total - value > Utils.CENT)       s+=34;
      if (TxBuilder.getCoinDepth(selectedOuts) <= TxBuilder.TX_FREE_MIN_PRIORITY * s) {
        needAtLeastReferenceFee=true;
        continue;
      }
    }
    boolean eitherCategory2Or3=false;
    boolean isCategory3=false;
    long change=TxBuilder.getAmount(selectedOuts) - valueNeeded;
    if (additionalValueSelected > 0)     change+=additionalValueSelected;
    if (BitherjSettings.ensureMinRequiredFee && change != 0 && change < Utils.CENT && fees < Utils.getFeeBase()) {
      eitherCategory2Or3=true;
      additionalValueForNextCategory=Utils.CENT;
      change-=Utils.getFeeBase() - fees;
    }
    int size=0;
    Out changeOutput=null;
    if (change > 0) {
      changeOutput=new Out();
      changeOutput.setOutValue(change);
      changeOutput.setOutAddress(changeAddress);
      if (BitherjSettings.ensureMinRequiredFee && Tx.MIN_NONDUST_OUTPUT >= change) {
        isCategory3=true;
        additionalValueForNextCategory=Utils.getFeeBase() + Tx.MIN_NONDUST_OUTPUT + 1;
      }
 else {
        size+=34;
        if (!eitherCategory2Or3)         additionalValueForNextCategory=0;
      }
    }
 else {
      if (eitherCategory2Or3) {
        isCategory3=true;
        additionalValueForNextCategory=Utils.getFeeBase() + 1;
      }
    }
    size+=TxBuilder.estimationTxSize(selectedOuts.size(),tx.getOuts().size());
    if (size / 1000 > lastCalculatedSize / 1000 && Utils.getFeeBase() > 0) {
      lastCalculatedSize=size;
      additionalValueForNextCategory=additionalValueSelected;
      continue;
    }
    if (isCategory3) {
      if (selection3 == null)       selection3=selectedOuts;
    }
 else     if (eitherCategory2Or3) {
      if (selection2 != null) {
        long oldFee=TxBuilder.getAmount(selection2) - selection2Change.getOutValue() - value;
        long newFee=TxBuilder.getAmount(selectedOuts) - changeOutput.getOutValue() - value;
        if (newFee <= oldFee) {
          selection2=selectedOuts;
          selection2Change=changeOutput;
        }
      }
 else {
        selection2=selectedOuts;
        selection2Change=changeOutput;
      }
    }
 else {
      if (selection1 != null) {
        long oldFee=TxBuilder.getAmount(selection1) - value;
        if (selection1Change != null) {
          oldFee-=selection1Change.getOutValue();
        }
        long newFee=TxBuilder.getAmount(selectedOuts) - value;
        if (changeOutput != null) {
          newFee-=changeOutput.getOutValue();
        }
        if (newFee <= oldFee) {
          selection1=selectedOuts;
          selection1Change=changeOutput;
        }
      }
 else {
        selection1=selectedOuts;
        selection1Change=changeOutput;
      }
    }
    if (additionalValueForNextCategory > 0) {
      continue;
    }
    break;
  }
  if (selection3 == null && selection2 == null && selection1 == null) {
    return null;
  }
  long lowestFee=0;
  if (selection1 != null) {
    if (selection1Change != null)     lowestFee=TxBuilder.getAmount(selection1) - selection1Change.getOutValue() - value;
 else     lowestFee=TxBuilder.getAmount(selection1) - value;
    bestCoinSelection=selection1;
    bestChangeOutput=selection1Change;
  }
  if (selection2 != null) {
    long fee=TxBuilder.getAmount(selection2) - selection2Change.getOutValue() - value;
    if (lowestFee == 0 || fee < lowestFee) {
      lowestFee=fee;
      bestCoinSelection=selection2;
      bestChangeOutput=selection2Change;
    }
  }
  if (selection3 != null) {
    if (lowestFee == 0 || TxBuilder.getAmount(selection3) - value < lowestFee) {
      bestCoinSelection=selection3;
      bestChangeOutput=null;
    }
  }
  if (bestChangeOutput != null) {
    tx.addOutput(bestChangeOutput.getOutValue(),bestChangeOutput.getOutAddress());
  }
  for (  Out out : bestCoinSelection) {
    tx.addInput(out);
  }
  tx.setSource(Tx.SourceType.self.getValue());
  return tx;
}