package qora;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import qora.account.Account;
import qora.assets.Asset;
import qora.block.Block;
import qora.block.GenesisBlock;
import qora.transaction.ArbitraryTransaction;
import qora.transaction.Transaction;
import utils.Pair;
import database.DBSet;
public class BlockChain
{
public static final int MAX_SIGNATURES = 500;
public BlockChain()
{
//CREATE GENESIS BLOCK
Block genesisBlock = new GenesisBlock();
if(!DBSet.getInstance().getBlockMap().contains(genesisBlock.getSignature()))
{
//PROCESS
genesisBlock.process();
//ADD QORA ASSET
Asset qoraAsset = new Asset(genesisBlock.getGenerator(), "Qora", "This is the simulated Qora asset.", 10000000000L, true, genesisBlock.getGeneratorSignature());
DBSet.getInstance().getIssueAssetMap().set(genesisBlock.getGeneratorSignature(), 0l);
DBSet.getInstance().getAssetMap().set(0l, qoraAsset);
}
}
public int getHeight() {
//GET LAST BLOCK
byte[] lastBlockSignature = DBSet.getInstance().getBlockMap().getLastBlockSignature();
//RETURN HEIGHT
return DBSet.getInstance().getHeightMap().get(lastBlockSignature);
}
public List<byte[]> getSignatures(byte[] parent) {
List<byte[]> headers = new ArrayList<byte[]>();
//CHECK IF BLOCK EXISTS
if(DBSet.getInstance().getBlockMap().contains(parent))
{
Block parentBlock = DBSet.getInstance().getBlockMap().get(parent).getChild();
int counter = 0;
while(parentBlock != null && counter < MAX_SIGNATURES)
{
headers.add(parentBlock.getSignature());
parentBlock = parentBlock.getChild();
counter ++;
}
}
return headers;
}
public Block getBlock(byte[] header) {
return DBSet.getInstance().getBlockMap().get(header);
}
public boolean isNewBlockValid(Block block) {
//CHECK IF NOT GENESIS
if(block instanceof GenesisBlock)
{
return false;
}
//CHECK IF SIGNATURE IS VALID
if(!block.isSignatureValid())
{
return false;
}
//CHECK IF WE KNOW REFERENCE
if(!DBSet.getInstance().getBlockMap().contains(block.getReference()))
{
return false;
}
//CHECK IF REFERENCE IS LASTBLOCK
if(!Arrays.equals(DBSet.getInstance().getBlockMap().getLastBlockSignature(), block.getReference()))
{
return false;
}
//CHECK IF BLOCK IS VALID
if(!block.isValid())
{
return false;
}
return true;
}
public Pair<Block, List<Transaction>> scanTransactions(Block block, int blockLimit, int transactionLimit, int type, int service, Account account)
{
//CREATE LIST
List<Transaction> transactions = new ArrayList<Transaction>();
//IF NO BLOCK START FROM GENESIS
if(block == null)
{
block = new GenesisBlock();
}
//START FROM BLOCK
int scannedBlocks = 0;
do
{
//FOR ALL TRANSACTIONS IN BLOCK
for(Transaction transaction: block.getTransactions())
{
//CHECK IF ACCOUNT INVOLVED
if(account != null && !transaction.isInvolved(account))
{
continue;
}
//CHECK IF TYPE OKE
if(type != -1 && transaction.getType() != type)
{
continue;
}
//CHECK IF SERVICE OKE
if(service != -1 && transaction.getType() == Transaction.ARBITRARY_TRANSACTION)
{
ArbitraryTransaction arbitraryTransaction = (ArbitraryTransaction) transaction;
if(arbitraryTransaction.getService() != service)
{
continue;
}
}
//ADD TO LIST
transactions.add(transaction);
}
//SET BLOCK TO CHILD
block = block.getChild();
scannedBlocks++;
}
//WHILE BLOCKS EXIST && NOT REACHED TRANSACTIONLIMIT && NOT REACHED BLOCK LIMIT
while(block != null && (transactions.size() < transactionLimit || transactionLimit == -1) && (scannedBlocks < blockLimit || blockLimit == -1));
//CHECK IF WE REACHED THE END
if(block == null)
{
block = this.getLastBlock();
}
else
{
block = block.getParent();
}
//RETURN PARENT BLOCK AS WE GET CHILD RIGHT BEFORE END OF WHILE
return new Pair<Block, List<Transaction>>(block, transactions);
}
public Block getLastBlock()
{
return DBSet.getInstance().getBlockMap().getLastBlock();
}
}