package com.google.bitcoin.core; import java.math.BigInteger; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.index.Index; import org.neo4j.graphdb.index.IndexManager; public class GraphTransactionInput extends TransactionInput implements GraphSaveable, Nodeable, Indexable, AddressListable { private Node node; public BigInteger value; public BigInteger coinbaseValue=BigInteger.ZERO; public int index; private GraphTransaction transaction; GraphTransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] scriptBytes) { super(params, parentTransaction, scriptBytes); // TODO Auto-generated constructor stub } public GraphTransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] payload, int offset) throws ProtocolException { super(params, parentTransaction, payload, offset); } public GraphTransactionInput(NetworkParameters params, Transaction parentTransaction, TransactionOutput output) { super(params,parentTransaction,output); } public TransactionOutPoint outpoint(){ if(outpoint!=null){ return outpoint; } Relationship prevOutputRelationship=node.getSingleRelationship(GraphRelationships.PREV_OUTPUT,Direction.OUTGOING); if(prevOutputRelationship!=null){ Node o=prevOutputRelationship.getEndNode(); Relationship t=o.getSingleRelationship(GraphRelationships.TRANSACTION_OUTPUT, Direction.INCOMING); if(t==null){ throw new RuntimeException("Unable to load previous output node transaction"); } Node trans=t.getStartNode(); try { outpoint=new TransactionOutPoint(params, (byte[]) trans.getProperty("hash"),(Long) t.getProperty(("index"))); } catch (ProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); throw new RuntimeException("Should never happen!!!"); } } return outpoint; } public byte[] getScriptBytes() { if(scriptBytes==null){ scriptBytes=(byte[]) node.getProperty("scriptBytes"); } return scriptBytes; } public GraphTransactionInput(NetworkParameters params, Node n){ super(params); node=n; // outpoint is lazy loaded by the outpoint() method, most of the time we don't need it if(node.hasProperty("value")){ value=BigInteger.valueOf((Long) node.getProperty("value")); } else{ value=BigInteger.ZERO; } coinbase=node.equals(GraphWallet.coinbaseWallet(n.getGraphDatabase()).node()); } public GraphAddress address(){ Relationship r=node.getSingleRelationship(GraphRelationships.TO_ADDRESS, Direction.OUTGOING); if(r==null){ return null; } try { return new GraphAddress(r.getEndNode()); } catch (AddressFormatException e) { return null; } } public Node transactionNode(){ Relationship t=node.getSingleRelationship(GraphRelationships.TRANSACTION_INPUT, Direction.INCOMING); if(t==null){ return null; } return t.getStartNode(); } public GraphTransaction transaction(){ if(transaction==null){ Node n=transactionNode(); if(n==null){ throw new RuntimeException("Can't find parent transaction"); } transaction=new GraphTransaction(params,n); } return transaction; } @Override public Node node() { // TODO Auto-generated method stub return node; } @Override public void save(GraphDatabaseService graph) { IndexManager index=graph.index(); Index<Node> transactionIndex=index.forNodes("transactions"); if(!isCoinBase()){ Node transactionNode=GraphTransaction.findTransactionNode(graph, Utils.bytesToHexString(outpoint.hash)); if(transactionNode==null){ throw new RuntimeException("Can't find transaction when looking for outpoint"); } Iterable<Relationship> i=transactionNode.getRelationships(Direction.OUTGOING, GraphRelationships.TRANSACTION_OUTPUT); Node previousOutpoint = null; int index_i=((int) (outpoint.index)); for(Relationship r : i){ boolean hasIndex=r.hasProperty("index"); if((index_i==0 && !hasIndex) || (index_i!=0 && hasIndex && r.getProperty("index").equals(index_i))){ Node e=r.getEndNode(); previousOutpoint=e; break; } } if(previousOutpoint==null){ throw new RuntimeException("Can't find output index when looking for outpoint - "+Utils.bytesToHexString(outpoint.hash)+" : "+outpoint.index); } node=previousOutpoint; } else{ node=GraphWallet.coinbaseWallet(graph).node(); } } @Override public Integer index() { // TODO Auto-generated method stub return index; } @Override public BigInteger value() { // TODO Auto-generated method stub return value; } public void save(){ save(node().getGraphDatabase()); } }