/*
* Follow the Bitcoin Analysis
* Copyright (C) 2014 Danno Ferrin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.shemnon.btc.analysis;
import com.shemnon.btc.model.ICoin;
import com.shemnon.btc.model.ITx;
import java.util.ArrayList;
import java.util.List;
/**
*
* Created by shemnon on 18 Mar 2014.
*/
public class SpendAndChange {
public static boolean isSpendAndChange(ITx tx) {
// idiot check
if (tx == null) return false;
// Spend and change must have:
// * 2 outputs
// * one output is 10x more than the other
List<ICoin> outputs = tx.getOutputs();
if (outputs.size() != 2) return false;
for (int i = 0; i < outputs.size(); i++) {
for (int j = i+1; j < outputs.size(); j++) {
double ratio = outputs.get(i).getValue() / outputs.get(j).getValue();
if (ratio > 0.1 && ratio < 10.0) return false;
}
}
return true;
}
public static List<ITx> climbSpendAndChange(ITx tx, int limit) {
List<ITx> upwards = new ArrayList<>();
ITx step = tx;
while (step != null && (limit-- > 0)) {
if (!isSpendAndChange(step)) break;
upwards.add(step);
ICoin coin = step.getInputs().stream().reduce((c1, c2) -> {
try {
if (c1.getValue() > c2.getValue()) {
return c1;
} else {
return c2;
}
} catch (Throwable e) {
System.out.println(":((");
e.printStackTrace();
throw e;
}
}).orElseGet(() -> {
try {
return tx.getOutputs().get(0);
} catch (Throwable e) {
System.out.println(":((");
e.printStackTrace();
return null;
}
});
step = coin.getSourceTX();
System.out.println("limit=" + limit);
System.out.print(".");
}
System.out.println();
System.out.println(":)");
return upwards;
}
public static List<ITx> descendSpendAndChange(ITx tx, int limit) {
try {
List<ITx> downwards = new ArrayList<>();
ITx step = tx;
System.out.println(":)");
while (step != null && (limit-- > 0)) {
if (!isSpendAndChange(step)) break;
downwards.add(step);
ICoin coin = step.getOutputs().stream().reduce((c1, c2) -> {
try {
if (c1.getValue() > c2.getValue()) {
return c1;
} else {
return c2;
}
} catch (Throwable e) {
System.out.println(":((");
e.printStackTrace();
throw e;
}
}).orElseGet(() -> {
try {
return tx.getOutputs().get(0);
} catch (Throwable e) {
System.out.println(":((");
e.printStackTrace();
return null;
}
});
step = coin.getTargetTX();
System.out.print(".");
}
System.out.println("limit=" + limit);
return downwards;
} catch (Throwable e) {
System.out.println(":(");
e.printStackTrace();
throw e;
}
}
}