Skip to content

Commit

Permalink
zerocoin.
Browse files Browse the repository at this point in the history
  • Loading branch information
furszy committed Oct 26, 2017
1 parent c22f2da commit e7449f7
Show file tree
Hide file tree
Showing 19 changed files with 350 additions and 93 deletions.
20 changes: 19 additions & 1 deletion core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java
Original file line number Diff line number Diff line change
Expand Up @@ -459,10 +459,18 @@ private boolean add(Block block, boolean tryConnecting,
// article here for more details: https://bitcoinj.github.io/security-model
try {
block.verifyHeader();
//System.out.println("New block previous hash: "+block.getPrevBlockHash());
storedPrev = getStoredBlockInCurrentScope(block.getPrevBlockHash());
if (storedPrev!=null) {
//System.out.println("New block, previous stored block from db: " + storedPrev.getHeader().getHashAsString());
checkArgument(block.getPrevBlockHash().equals(storedPrev.getHeader().getHash()), "Database saving shit.. prev hash block: " + block.getPrevBlockHash() + ", db prev hash: " + storedPrev.getHeader().getHashAsString());
}

if (storedPrev != null) {
height = storedPrev.getHeight() + 1;
//System.out.println("Adding Block: "+height+" hash "+block.getHashAsString()+", Prev block "+storedPrev.getHeight()+" hash: "+block.getPrevBlockHash().toString());
} else {
//System.out.println("block height unknown");
height = Block.BLOCK_HEIGHT_UNKNOWN;
}
flags = params.getBlockVerificationFlags(block, versionTally, height);
Expand Down Expand Up @@ -491,6 +499,7 @@ private boolean add(Block block, boolean tryConnecting,
//todo furszy: i'm not checking the difficulty yet
//todo: this should be checked on a MN wallet service.
//checkDifficultyTransitions(storedPrev, block);
//System.out.println("going to connect block with accumulator: "+block.getAccumulator().toString());
connectBlock(block, storedPrev, shouldVerifyTransactions(), filteredTxHashList, filteredTxn);
}

Expand Down Expand Up @@ -538,6 +547,9 @@ private void connectBlock(final Block block, StoredBlock storedPrev, boolean exp
}

StoredBlock head = getChainHead();
// System.out.println("New block: "+block.toString());
//System.out.println("Head height: "+head.getHeight() + " hash: "+head.getHeader().getHashAsString()
// + " Previous block stored height: "+storedPrev.getHeight());
if (storedPrev.equals(head)) {
if (filtered && filteredTxn.size() > 0) {
log.debug("Block {} connects to top of best chain with {} transaction(s) of which we were sent {}",
Expand Down Expand Up @@ -571,6 +583,12 @@ private void connectBlock(final Block block, StoredBlock storedPrev, boolean exp
log.debug("Chain is now {} blocks high, running listeners", newStoredBlock.getHeight());
informListenersForNewBlock(block, NewBlockType.BEST_CHAIN, filteredTxHashList, filteredTxn, newStoredBlock);
} else {
//System.out.println("#####################");
//System.out.println("block not connect to the blockchain heads..");
//System.out.println("head chain: "+head.getHeader().getHashAsString());
//System.out.println("Stored block: "+storedPrev.getHeader().getHashAsString());
//System.out.println("New block work: "+block.getHashAsString());
//System.out.println("#####################");
// This block connects to somewhere other than the top of the best known chain. We treat these differently.
//
// Note that we send the transactions to the wallet FIRST, even if we're about to re-organize this block
Expand Down Expand Up @@ -759,7 +777,7 @@ private void handleNewBestChain(StoredBlock storedPrev, StoredBlock newChainHead
log.info("New chain head: {}", newChainHead.getHeader().getHashAsString());
log.info("Split at block: {}", splitPoint.getHeader().getHashAsString());
// Then build a list of all blocks in the old part of the chain and the new part.
System.out.println("head work: "+head.getChainWork()+ ", splitPoint: "+splitPoint.getChainWork());
//System.out.println("head work: "+head.getChainWork()+ ", splitPoint: "+splitPoint.getChainWork());
final LinkedList<StoredBlock> oldBlocks = getPartialChain(head, splitPoint, blockStore);
final LinkedList<StoredBlock> newBlocks = getPartialChain(newChainHead, splitPoint, blockStore);
// Disconnect each transaction in the previous main chain that is no longer in the new main chain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;

import java.io.IOException;
import java.io.OutputStream;
Expand Down
108 changes: 74 additions & 34 deletions core/src/main/java/org/bitcoinj/core/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,16 @@ public enum VerifyFlag {
public static final int HEADER_SIZE = 80;
/*** Zerocoin blocks header size */
public static final int ZEROCOIN_HEADER_SIZE = 112;
/** Zerocoin starting block height */
public static final long ZEROCOIN_STARTING_BLOCK_HEIGHT = 201564;

static final long ALLOWED_TIME_DRIFT = 2 * 60 * 60; // Same value as Bitcoin Core.

/**
* Zerocoin block version
* Includes an accumulator on the block.
*/
public static final int ZEROCOIN_BLOCK_VERSION = 4;
public static final long ZEROCOIN_BLOCK_VERSION = 4;

public static final boolean ACTIVATE_ZEROCOIN = false;
public static final boolean ACTIVATE_ZEROCOIN = true;

/**
* A constant shared by the entire network: how large in bytes a block is allowed to be. One day we may have to
Expand Down Expand Up @@ -122,7 +120,6 @@ public enum VerifyFlag {

/**
* Zerocoin accumulator
*
*/
private Sha256Hash zeroCoinAccumulator;

Expand Down Expand Up @@ -284,28 +281,50 @@ protected void parseTransactions(final int transactionsOffset) throws ProtocolEx

@Override
protected void parse() throws ProtocolException {
// header
cursor = offset;
version = readUint32();
prevBlockHash = readHash();
merkleRoot = readHash();
time = readUint32();
difficultyTarget = readUint32();
nonce = readUint32();
int headerSize = getHeaderSize();
if (isZerocoin()){
// accumulator
zeroCoinAccumulator = readHash();
hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(payload, offset, cursor - offset));
}else {
hash = Sha256Hash.wrapReversed(Hash9.digest(payload, offset, cursor - offset));
}
try {
// header
cursor = offset;
version = readUint32();
//System.out.println("parse version: "+version);
prevBlockHash = readHash();
//System.out.println("parse prevBlockHash: "+prevBlockHash);
merkleRoot = readHash();
//System.out.println("parse merkleRoot: "+merkleRoot);
time = readUint32();
//System.out.println("parse time: "+time);
difficultyTarget = readUint32();
//System.out.println("parse difficultyTarget: "+difficultyTarget);
nonce = readUint32();
//System.out.println("parse nonce: "+nonce);
int headerSize = getHeaderSize();
if (isZerocoin()) {
// accumulator
zeroCoinAccumulator = readHash(true);
//System.out.println("parse zeroCoinAccumulator: "+zeroCoinAccumulator);
//System.out.println("offset: "+offset);
//System.out.println("cursor: "+cursor);
//System.out.println("payload size: "+payload.length);
//System.out.println("Hash payload "+Arrays.toString(copy));
// hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(copy));
// System.out.println("zerocoin hash parsed: "+hash.toString());
hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(payload, offset, cursor - offset));
//System.out.println("zerocoin test hash parsed 2: "+hash.toString());

//hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(payload, offset, cursor - offset));
} else {
hash = Sha256Hash.wrapReversed(Hash9.digest(payload, offset, cursor - offset));
//System.out.println("hash parsed: "+hash.toString());
}

headerBytesValid = serializer.isParseRetainMode();
headerBytesValid = serializer.isParseRetainMode();

// transactions
parseTransactions(offset + headerSize);
length = cursor - offset;
// transactions
parseTransactions(offset + headerSize);
length = cursor - offset;
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}

public int getOptimalEncodingMessageSize() {
Expand All @@ -318,24 +337,29 @@ public int getOptimalEncodingMessageSize() {
// default for testing
void writeHeader(OutputStream stream) throws IOException {
int headerSize = getHeaderSize();
//System.out.println("writeHeader header size: "+headerSize);
// try for cached write first
if (headerBytesValid && payload != null && payload.length >= offset + headerSize) {
stream.write(payload, offset, headerSize);
return;
}
// fall back to manual write
Utils.uint32ToByteStreamLE(version, stream);
//System.out.println("writeHeader version: "+version);
stream.write(prevBlockHash.getReversedBytes());
//System.out.println("writeHeader prevBlockHash: "+prevBlockHash);
stream.write(getMerkleRoot().getReversedBytes());
//System.out.println("writeHeader merkle root: "+getMerkleRoot());
Utils.uint32ToByteStreamLE(time, stream);
//System.out.println("writeHeader time: "+time);
Utils.uint32ToByteStreamLE(difficultyTarget, stream);
//System.out.println("writeHeader difficultyTarget: "+difficultyTarget);
Utils.uint32ToByteStreamLE(nonce, stream);
//System.out.println("writeHeader nonce: "+nonce);
if (isZerocoin()){
if (zeroCoinAccumulator!=null) {
stream.write(zeroCoinAccumulator.getReversedBytes());
}else {
stream.write(new byte[32]);
}
byte[] accumulator = (zeroCoinAccumulator!=null)?zeroCoinAccumulator.getReversedBytes():new byte[32];
stream.write(accumulator);
//System.out.println("writeHeader zeroCoinAccumulator: "+nonce);
}
}

Expand Down Expand Up @@ -482,6 +506,10 @@ public String getHashAsString() {
}


public Sha256Hash getAccumulator() {
return zeroCoinAccumulator;
}

/**
* Returns the hash of the block (which for a valid, solved block should be
* below the target). Big endian.
Expand All @@ -502,18 +530,26 @@ public boolean isZerocoin() {
}
}

public static boolean isZerocoinHeight(long height) {
public static boolean isZerocoinHeight(NetworkParameters networkParameters,long height) {
if (!ACTIVATE_ZEROCOIN) {
return false;
}else
return height>=ZEROCOIN_STARTING_BLOCK_HEIGHT;
return height>=networkParameters.getZerocoinStartedHeight();
}

public static int getHeaderSizeByVersion(long version){
if (!ACTIVATE_ZEROCOIN) {
return Block.HEADER_SIZE;
}else {
return Block.ZEROCOIN_BLOCK_VERSION == version ? ZEROCOIN_HEADER_SIZE : HEADER_SIZE;
}
}

public static int getHeaderSize(long height){
public static int getHeaderSize(NetworkParameters params,long height){
if (!ACTIVATE_ZEROCOIN) {
return Block.HEADER_SIZE;
}else
return Block.isZerocoinHeight(height)?Block.ZEROCOIN_HEADER_SIZE:Block.HEADER_SIZE;
return Block.isZerocoinHeight(params,height)?Block.ZEROCOIN_HEADER_SIZE:Block.HEADER_SIZE;
}

/**
Expand Down Expand Up @@ -550,6 +586,7 @@ protected final void copyBitcoinHeaderTo(final Block block) {
block.version = version;
block.time = time;
block.difficultyTarget = difficultyTarget;
block.zeroCoinAccumulator = zeroCoinAccumulator;
block.transactions = null;
block.hash = getHash();
}
Expand All @@ -574,6 +611,9 @@ public String toString() {
s.append(" time: ").append(time).append(" (").append(Utils.dateTimeFormat(time * 1000)).append(")\n");
s.append(" difficulty target (nBits): ").append(difficultyTarget).append("\n");
s.append(" nonce: ").append(nonce).append("\n");
if (isZerocoin()){
s.append(" accumulator: ").append((zeroCoinAccumulator!=null)?zeroCoinAccumulator.toString():0).append("\n");;
}
if (transactions != null && transactions.size() > 0) {
s.append(" with ").append(transactions.size()).append(" transaction(s):\n");
for (Transaction tx : transactions) {
Expand Down
8 changes: 6 additions & 2 deletions core/src/main/java/org/bitcoinj/core/CoinDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ public static final int getTargetTimespan(int height, boolean testNet) {
public static final boolean feeCanBeRaised = false;

//
// Dash 0.12
// PIVX 0.12
//
public static final int PROTOCOL_VERSION = 70910; //version.h PROTOCOL_VERSION
public static final int MIN_PROTOCOL_VERSION = 70810; //version.h MIN_PROTO_VERSION
public static final int MIN_PROTOCOL_VERSION = 70910; //version.h MIN_PROTO_VERSION

public static final int BLOCK_CURRENTVERSION = 2; //CBlock::CURRENT_VERSION
public static final int MAX_BLOCK_SIZE = 1 * 1000 * 1000;
Expand All @@ -91,6 +91,10 @@ public static final int getTargetTimespan(int height, boolean testNet) {
public static final int Port = 51472; //protocol.h GetDefaultPort(testnet=false)
public static final int TestPort = 51474; //protocol.h GetDefaultPort(testnet=true)

/** Zerocoin starting block height */
public static final long TESTNET_ZEROCOIN_STARTING_BLOCK_HEIGHT = 201564;
public static final long MAINNET_ZEROCOIN_STARTING_BLOCK_HEIGHT = 863787;

//
// Production
//
Expand Down
12 changes: 8 additions & 4 deletions core/src/main/java/org/bitcoinj/core/FilteredBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package org.bitcoinj.core;

import com.google.common.base.Objects;
import org.spongycastle.util.encoders.Hex;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
Expand Down Expand Up @@ -59,13 +61,15 @@ public void bitcoinSerializeToStream(OutputStream stream) throws IOException {

@Override
protected void parse() throws ProtocolException {
byte[] headerBytes = new byte[Block.HEADER_SIZE];
System.arraycopy(payload, 0, headerBytes, 0, Block.HEADER_SIZE);
long version = Utils.readUint32(payload, 0);
int headerSize = Block.getHeaderSizeByVersion(version);
byte[] headerBytes = new byte[headerSize];
System.arraycopy(payload, 0, headerBytes, 0, headerSize);
header = params.getDefaultSerializer().makeBlock(headerBytes);

merkleTree = new PartialMerkleTree(params, payload, Block.HEADER_SIZE);
merkleTree = new PartialMerkleTree(params, payload, headerSize);

length = Block.HEADER_SIZE + merkleTree.getMessageSize();
length = headerSize + merkleTree.getMessageSize();
}

/**
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/org/bitcoinj/core/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ protected Message(NetworkParameters params, byte[] payload, int offset, int prot
this.cursor = this.offset = offset;
this.length = length;

assert payload!=null:"Block payload null";

parse();

if (this.length == UNKNOWN_LENGTH)
Expand Down Expand Up @@ -356,6 +358,13 @@ protected Sha256Hash readHash() throws ProtocolException {
return Sha256Hash.wrapReversed(readBytes(32));
}

protected Sha256Hash readHash(boolean zerocoin) throws ProtocolException {
// We have to flip it around, as it's been read off the wire in little endian.
// Not the most efficient way to do this but the clearest.
byte[] accumulator = readBytes(32);
return Sha256Hash.wrapReversed(accumulator);
}

protected boolean hasMoreBytes() {
return cursor < payload.length;
}
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/org/bitcoinj/core/NetworkParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ public abstract class NetworkParameters {
protected int bip32HeaderPub;
protected int bip32HeaderPriv;

protected long zerocoinStartedHeight;

/** Used to check majorities for block version upgrade */
protected int majorityEnforceBlockUpgrade;
protected int majorityRejectBlockOutdated;
Expand Down Expand Up @@ -471,6 +473,14 @@ public final MessageSerializer getDefaultSerializer() {
return defaultSerializer;
}

/**
* Zerocoin started height in blockchain
* @return
*/
public long getZerocoinStartedHeight() {
return zerocoinStartedHeight;
}

/**
* Construct and return a custom serializer.
*/
Expand Down
Loading

0 comments on commit e7449f7

Please sign in to comment.