Android Open Source - bitcoin-wallet Sql Block Store






From Project

Back to project page bitcoin-wallet.

License

The source code is released under:

Copyright (C) 2011 by Caleb Anderson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the ...

If you think the Android project bitcoin-wallet listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.dirtyfilthy.bitcoin.wallet;
// w w w .jav  a 2 s  .  com
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQuery;
import android.database.sqlite.SQLiteStatement;
import net.dirtyfilthy.bitcoin.core.Block;
import net.dirtyfilthy.bitcoin.core.BlockChain;
import net.dirtyfilthy.bitcoin.core.BlockExistsException;
import net.dirtyfilthy.bitcoin.core.BlockStore;
import net.dirtyfilthy.bitcoin.protocol.ProtocolVersion;
import net.dirtyfilthy.bitcoin.util.MyHex;
import net.dirtyfilthy.bouncycastle.util.Arrays;
import net.dirtyfilthy.bouncycastle.util.encoders.Hex;

public class SqlBlockStore extends BlockStore {
  private SQLiteDatabase db;
  private Block lastStored;
  private StringBuilder sql=new StringBuilder(200); 
  private LinkedList<Block> getByHashCache=new LinkedList<Block>();
  private SQLiteStatement insertStatement;
  private ExposedSQLiteCursor hashCursor;
  private HashMap<Block,Block> previousHashMap=new HashMap<Block,Block>(); 
  
  
  public SqlBlockStore(SQLiteDatabase db){
    super(false);
    this.db=db;
    Block genesis=ProtocolVersion.genesisBlock();
    insertStatement=db.compileStatement("INSERT INTO blocks (hash,previous_hash,merkle_root,height,total_work,timestamp,nonce,bits) VALUES (?,?,?,?,?,?,?,?)");
    
    // this will find nothing but expose the SQLiteQuery to us, all this for a bindBlob() eh?
    // plus we can continually reuse the cursor
    
    // HACK: pass a null here so the blob doesn't rebind as a string
    
    hashCursor=(ExposedSQLiteCursor) db.rawQueryWithFactory(new ExposedSQLiteCursor.Factory(), "SELECT * from blocks WHERE hash = ?", null, "blocks");
    try {
      if(!has(genesis)){
        System.out.println("Storing genesis...");
        put(genesis);
      }

    } 
    catch(BlockExistsException e){
      // do nothing
    }
    

  }
  
  private Block createBlockFromCursor(Cursor cursor){
    Block b=new Block();
    b.setPreviousHash(cursor.getBlob(2));
    b.setMerkleRoot(cursor.getBlob(3));
    b.setHeight(cursor.getInt(4));
    b.setTotalWork(new BigInteger(cursor.getBlob(5)));
    b.setTimestamp(new java.util.Date(cursor.getLong(6)));
    b.setNonce(cursor.getLong(7));
    b.setBits(cursor.getLong(8));
    return b;
  }
  
  public synchronized boolean has(Block b){
    return getByHash(b.hash())!=null;
  }
  
  public synchronized Block getByHash(byte[] hash){
    
    // leetle bit of caching
    Block b;
    if(lastStored!=null &&  Arrays.areEqual(hash,lastStored.hash())){
      return lastStored;
    }
    b=searchGetByHashCache(hash);
    if(b!=null){
      return b;
    }
    SQLiteQuery s;
    s=hashCursor.getQuery();
    s.bindBlob(1, hash);
    hashCursor.requery();
    
    if(hashCursor.getCount() == 0){
      
      return null;
    }
    hashCursor.moveToFirst();
    b=createBlockFromCursor(hashCursor);
  
    return b;
  }
  
  public synchronized Block getByPreviousHash(byte[] hash){
    sql.setLength(0);
    sql.append("select * from blocks where previousHash=X'");
    sql.append(MyHex.encode(hash));
    sql.append("'");
    Cursor cursor = db.rawQuery(sql.toString(),null); ; 
    if(cursor.getCount() == 0){
      return null;
    }
    cursor.moveToFirst();
    Block b=createBlockFromCursor(cursor);
    cursor.close();
    return b;
  }
  

  public synchronized Block getPrevious(Block b){
    if(previousHashMap.containsKey(b)){
      return previousHashMap.get(b);
    }
    return getByHash(b.getPreviousHash());
  }
  
  
  
  public synchronized Block put(Block b) throws BlockExistsException{
    Block prev=getPrevious(b);
    if(topBlock==null || getTotalWork(b).compareTo(topBlock.getTotalWork())>0){
      topBlock=b;
    }
    if(prev!=null){
      b.setHeight(prev.getHeight()+1);
    }
    else{
      b.setHeight(0);
    }
    try{
      storeBlock(b);
    }
    catch(SQLiteConstraintException e){
      throw new BlockExistsException(e);
    }
    return b;
  }
  
  private Block searchGetByHashCache(byte[] hash){
    Block b;
    Iterator<Block> i=getByHashCache.iterator();
    while(i.hasNext()){
      b=i.next();
      if(Arrays.areEqual(hash, b.hash())){
        return b;
      }
    }
    return null;
    
  }

  private void storeBlock(Block b) {
    insertStatement.bindBlob(1, b.hash());
    insertStatement.bindBlob(2, b.getPreviousHash());
    insertStatement.bindBlob(3, b.getMerkleRoot());
    insertStatement.bindLong(4, b.getHeight());
    insertStatement.bindBlob(5, getTotalWork(b).toByteArray());
    insertStatement.bindLong(6, b.getTime());
    insertStatement.bindLong(7, b.getNonce());
    insertStatement.bindLong(8, b.getBits());
    insertStatement.execute();
    lastStored=b;
    getByHashCache.offer(b);
    previousHashMap.put(b, getPrevious(b));
    if(getByHashCache.size()>13){
      previousHashMap.remove(getByHashCache.poll());
    }
    
  }

}




Java Source Code List

net.dirtyfilthy.bitcoin.core.Address.java
net.dirtyfilthy.bitcoin.core.Base58Hash160.java
net.dirtyfilthy.bitcoin.core.BlockChain.java
net.dirtyfilthy.bitcoin.core.BlockExistsException.java
net.dirtyfilthy.bitcoin.core.BlockStore.java
net.dirtyfilthy.bitcoin.core.Block.java
net.dirtyfilthy.bitcoin.core.BtcValue.java
net.dirtyfilthy.bitcoin.core.ByteArrayable.java
net.dirtyfilthy.bitcoin.core.InvalidBlockException.java
net.dirtyfilthy.bitcoin.core.OpCode.java
net.dirtyfilthy.bitcoin.core.OpData.java
net.dirtyfilthy.bitcoin.core.OrphanBlockException.java
net.dirtyfilthy.bitcoin.core.Script.java
net.dirtyfilthy.bitcoin.core.TxIn.java
net.dirtyfilthy.bitcoin.core.TxOut.java
net.dirtyfilthy.bitcoin.core.Tx.java
net.dirtyfilthy.bitcoin.protocol.AddressBook.java
net.dirtyfilthy.bitcoin.protocol.AddressPacket.java
net.dirtyfilthy.bitcoin.protocol.BlockPacket.java
net.dirtyfilthy.bitcoin.protocol.ConnectionHandler.java
net.dirtyfilthy.bitcoin.protocol.Connection.java
net.dirtyfilthy.bitcoin.protocol.GetAddressPacket.java
net.dirtyfilthy.bitcoin.protocol.GetBlocksPacket.java
net.dirtyfilthy.bitcoin.protocol.GetDataPacket.java
net.dirtyfilthy.bitcoin.protocol.GetHeadersPacket.java
net.dirtyfilthy.bitcoin.protocol.HeadersPacket.java
net.dirtyfilthy.bitcoin.protocol.InventoryPacket.java
net.dirtyfilthy.bitcoin.protocol.InventoryVector.java
net.dirtyfilthy.bitcoin.protocol.IrcBootStrap.java
net.dirtyfilthy.bitcoin.protocol.MalformedPacketException.java
net.dirtyfilthy.bitcoin.protocol.PacketFactory.java
net.dirtyfilthy.bitcoin.protocol.PacketType.java
net.dirtyfilthy.bitcoin.protocol.Packet.java
net.dirtyfilthy.bitcoin.protocol.PingPacket.java
net.dirtyfilthy.bitcoin.protocol.ProtocolVersion.java
net.dirtyfilthy.bitcoin.protocol.ReplyPacket.java
net.dirtyfilthy.bitcoin.protocol.TxPacket.java
net.dirtyfilthy.bitcoin.protocol.VersionAckPacket.java
net.dirtyfilthy.bitcoin.protocol.VersionPacket.java
net.dirtyfilthy.bitcoin.util.Base58.java
net.dirtyfilthy.bitcoin.util.BigIntegerTools.java
net.dirtyfilthy.bitcoin.util.HashTools.java
net.dirtyfilthy.bitcoin.util.KeyTools.java
net.dirtyfilthy.bitcoin.util.MyHex.java
net.dirtyfilthy.bitcoin.wallet.ExposedSQLiteCursor.java
net.dirtyfilthy.bitcoin.wallet.InvalidPasswordException.java
net.dirtyfilthy.bitcoin.wallet.KeyRing.java
net.dirtyfilthy.bitcoin.wallet.SqlBlockStore.java
net.dirtyfilthy.bitcoin.wallet.Wallet.java