Skip to content

Commit

Permalink
Account made serializable, blocks binary files storage implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Apr 22, 2015
1 parent 3b2613c commit 5e81070
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/main/scala/scorex/account/Account.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scorex.account


class Account(val address: String) {
class Account(val address: String) extends Serializable {

override def toString = address

Expand Down
2 changes: 0 additions & 2 deletions src/main/scala/scorex/database/blockchain/BlockChain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ trait BlockChain {

def lastBlock: Block = blockAt(height()).get

def confirmations(tx: Transaction): Option[Int]

def confirmations(block: Block): Option[Int] = heightOf(block).map(height() - _)

def blockByHeader(signature: Array[Byte]): Option[Block]
Expand Down
82 changes: 54 additions & 28 deletions src/main/scala/scorex/database/blockchain/BlockchainImpl.scala
Original file line number Diff line number Diff line change
@@ -1,54 +1,80 @@
package scorex.database.blockchain

import java.io.File
import java.io.DataInputStream
import com.google.common.primitives.Ints
import org.mapdb.DBMaker
import scorex.account.Account
import scorex.block.Block
import scorex.transaction._
import settings.Settings
import scala.collection.concurrent.TrieMap

import scala.reflect.io.File
import scala.collection.JavaConversions._
import scala.util.Try

// todo: syncing issues
class BlockchainImpl extends BlockChain {
private val database = DBMaker.newFileDB(new java.io.File(s"/tmp/signatures"))
.closeOnJvmShutdown()
.checksumEnable()
.mmapFileEnableIfSupported()
.make()

private val signaturesIndex = database.createTreeMap("signatures").makeOrGet[Int, Array[Byte]]()

private val signaturesIndex = TrieMap[Int, Array[Byte]]()
private val blocksIndex = TrieMap[Int, Block]()
//if there are some uncommited changes from last run, discard'em
if(signaturesIndex.size() > 0) database.rollback()

private def blockFile(height: Int) = File(Settings.dataDir + s"/block-$height")

override def appendBlock(block: Block): BlockChain = {
val h = height() + 1
signaturesIndex += h -> block.signature
blocksIndex += h -> block
this
}.ensuring(_ => signaturesIndex.size == blocksIndex.size)
signaturesIndex.put(h, block.signature)

override def heightOf(block: Block): Option[Int] = signaturesIndex.find(_._2.sameElements(block.signature)).map(_._1)
val blockBytes = block.toBytes
val os = blockFile(h).outputStream(append = false)
try {
os.write(Ints.toByteArray(blockBytes.length))
os.write(blockBytes)
} finally os.close()

override def blockAt(height: Int): Option[Block] = blocksIndex.get(height)
database.commit()
this
}

override def discardBlock(): BlockChain = {
require(height() > 1, "Chain is empty or contains genesis block only, can't make rollback")
val h = height()
Try(blockFile(h).delete()) //todo: write msg to log if problems with deleting
signaturesIndex.remove(h)
database.commit()
this
}

override def heightOf(block: Block): Option[Int] =
signaturesIndex.descendingMap().find(_._2.sameElements(block.signature)).map(_._1)

override def blockAt(height: Int): Option[Block] = {
val is = new DataInputStream(blockFile(height).inputStream())
try {
val szBytes = new Array[Byte](4)
is.read(szBytes, 0, 4)
val sz = Ints.fromByteArray(szBytes)
val bytes = new Array[Byte](sz)
is.read(bytes)
Block.parse(bytes).toOption
}finally is.close()
}

override def contains(block: Block): Boolean = contains(block.signature)

override def contains(signature:Array[Byte]): Boolean = signaturesIndex.exists(_._2.sameElements(signature))

override def height(): Int = signaturesIndex.size

private def filename(height: Int) = Settings.dataDir + s"/block-${height + 1}"
override def height(): Int = Option(signaturesIndex.size).getOrElse(0)

override def heightOf(blockSignature: Array[Byte]): Option[Int] =
signaturesIndex.find(_._2.sameElements(blockSignature)).map(_._1)

override def blockByHeader(signature: Array[Byte]): Option[Block] =
signaturesIndex.find(_._2.sameElements(signature)).map(_._1).map(h => blocksIndex(h))

//todo: implement
override def confirmations(tx: Transaction): Option[Int] = ???

override def discardBlock(): BlockChain = {
require(height() > 1, "Chain is empty or contains genesis block only")
val key = height()
signaturesIndex -= key
blocksIndex -= key
new File(filename(key)).delete()
this
}.ensuring(_ => signaturesIndex.size == blocksIndex.size)
heightOf(signature).flatMap(blockAt)

//todo: implement
override def child(block: Block): Option[Block] = ???
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import scorex.transaction.Transaction
* Facade to both blockchain & internal state implementations
*/
object PrunableBlockchainStorage extends BlockChain with StateQuery {
private val chain = new BlockchainImpl
private val state = new InternalState
private val chain = new BlockchainImpl()
private val state = new InternalState()

override def height(): Int = chain.height()

Expand Down Expand Up @@ -40,8 +40,6 @@ object PrunableBlockchainStorage extends BlockChain with StateQuery {

override def child(block: Block): Option[Block] = chain.child(block)

override def confirmations(tx: Transaction): Option[Int] = chain.confirmations(tx)

override def blockByHeader(signature: Array[Byte]): Option[Block] = chain.blockByHeader(signature)

def generatedBy(account: Account): Seq[Block] = chain.generatedBy(account)
Expand Down

0 comments on commit 5e81070

Please sign in to comment.