package com.google.bitcoin.core; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; 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 GraphAddress extends Address implements Noteable, Nodeable, Accountable { private Node node; public String label=""; public String notes=""; private static MapCache<String,GraphAddress> cache=new MapCache<String,GraphAddress>(2000); public GraphAddress(NetworkParameters params, byte[] hash160) throws AddressFormatException { super(params, hash160); // TODO Auto-generated constructor stub } public GraphAddress(NetworkParameters params, String address) throws AddressFormatException { super(params, address); // TODO Auto-generated constructor stub } public GraphAddress(Node a) throws AddressFormatException { super(NetworkParameters.prodNet(),(byte[]) a.getProperty("hash")); node=a; label=""; notes=""; if(node.hasProperty("label")){ label=(String) a.getProperty("label"); } if(node.hasProperty("notes")){ notes=(String) a.getProperty("notes"); } } @Override public Node node() { // TODO Auto-generated method stub return node; } public static GraphAddress findOrCreateAddress(GraphDatabaseService graph, NetworkParameters p, String base58hash) throws AddressFormatException{ if(cache.containsKey(base58hash)){ return cache.get(base58hash); } IndexManager index=graph.index(); Index<Node> addressIndex=index.forNodes("addresses"); Node a=addressIndex.get("hash", base58hash).getSingle(); GraphAddress address; if(a!=null){ address=new GraphAddress(a); } else{ org.neo4j.graphdb.Transaction tx = graph.beginTx(); try{ address=new GraphAddress(p,base58hash); address.save(graph); tx.success(); } finally{ tx.finish(); } } cache.put(base58hash, address); return address; } public ArrayList<GraphTransaction> transactions(){ ArrayList<GraphTransaction> trans=new ArrayList<GraphTransaction>(); HashMap<Node,Boolean> outWalletMap=new HashMap<Node,Boolean>(); HashMap<Node,Boolean> inWalletMap=new HashMap<Node,Boolean>(); for(Relationship r : node.getRelationships(Direction.INCOMING, GraphRelationships.TO_ADDRESS)){ Node n=r.getStartNode(); Relationship r2=n.getSingleRelationship(GraphRelationships.TRANSACTION_OUTPUT, Direction.INCOMING); Node n2=r2.getStartNode(); GraphTransaction t=new GraphTransaction(n2); if(!trans.contains(t)){ trans.add(t); for(GraphWallet w : t.getIncomingWallets()){ inWalletMap.put(w.node(), true); } for(GraphWallet w : t.getOutgoingWallets()){ outWalletMap.put(w.node(), true); } } r2=n.getSingleRelationship(GraphRelationships.TRANSACTION_INPUT, Direction.INCOMING); if(r2!=null){ n2=r2.getStartNode(); t=new GraphTransaction(n2); if(!trans.contains(t)){ trans.add(t); for(GraphWallet w : t.getIncomingWallets()){ inWalletMap.put(w.node(), true); } for(GraphWallet w : t.getOutgoingWallets()){ outWalletMap.put(w.node(), true); } } } } Collections.sort(trans, Timeable.TIME_ORDER); GraphTransaction f=trans.get(0); if(f!=null){ f.incomingWallets=inWalletMap.size(); f.outgoingWallets=outWalletMap.size(); } return trans; } public GraphWallet wallet(){ Relationship r=node.getSingleRelationship(GraphRelationships.HAS_ADDRESS, Direction.INCOMING); if(r==null){ return new GraphWallet(r.getStartNode()); } return new GraphWallet(r.getStartNode()); } @Override public void save(GraphDatabaseService graph) { IndexManager index=graph.index(); Index<Node> addressIndex=index.forNodes("addresses"); org.neo4j.graphdb.Transaction tx = graph.beginTx(); try{ if(node==null){ node=graph.createNode(); node.setProperty("hash",this.getHash160()); if(!label.equals("")){ node.setProperty("label",label); addressIndex.add(node, "label", label); } if(!notes.equals("")){ node.setProperty("notes",notes); } addressIndex.add(node,"hash",this.toString()); GraphWallet w=new GraphWallet(); if(!label.equals("")){ w.label=label; w.notes=notes; } w.save(graph); w.node().createRelationshipTo(node, GraphRelationships.HAS_ADDRESS); } else{ if(node.hasProperty("label")){ node.removeProperty("label"); addressIndex.remove(node,"label"); } if(node.hasProperty("notes")){ node.removeProperty("notes"); } if(!label.equals("")){ node.setProperty("label",label); addressIndex.add(node, "label", label); } if(!notes.equals("")){ node.setProperty("notes",notes); } GraphWallet w=wallet(); if(!label.equals("") && w.label.equals("")){ w.label=label; w.notes=notes; w.save(graph); } } tx.success(); } finally { tx.finish(); } } @Override public BigInteger incomingAmount(GraphTransaction t) { // TODO Auto-generated method stub return t.incomingAmountForAddress(this); } @Override public BigInteger outgoingAmount(GraphTransaction t) { // TODO Auto-generated method stub return t.outgoingAmountForAddress(this); } @Override public void setLabel(String label) { this.label=label; } @Override public void setNotes(String notes) { this.notes=notes; } @Override public String getLabel() { // TODO Auto-generated method stub return label; } @Override public String getNotes() { // TODO Auto-generated method stub return notes; } public void save(){ save(node().getGraphDatabase()); } @Override public BigInteger cachedTotalIncoming() { // TODO Auto-generated method stub return null; } @Override public BigInteger cachedTotalOutgoing() { // TODO Auto-generated method stub return null; } }