Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fork] Include block transaction hash in the generation signature #6

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/java/nxt/BlockImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ boolean verifyGenerationSignature() throws BlockchainProcessor.BlockNotAcceptedE
preVerify();
}

byte[] correctGenerationSignature = Nxt.getGenerator().calculateGenerationSignature(previousBlock.getGenerationSignature(), previousBlock.getGeneratorId());
byte[] correctGenerationSignature = Nxt.getGenerator().calculateGenerationSignature(previousBlock.getGenerationSignature(), previousBlock.getGeneratorId(), getPayloadHash(), getHeight());
if(!Arrays.equals(generationSignature, correctGenerationSignature)) {
return false;
}
Expand Down
2 changes: 2 additions & 0 deletions src/java/nxt/BlockchainProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public static enum Event {
Peer getLastBlockchainFeeder();

int getLastBlockchainFeederHeight();

byte[] getTransactionHash(Block lastBlock);

boolean isScanning();

Expand Down
69 changes: 50 additions & 19 deletions src/java/nxt/BlockchainProcessorImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import nxt.util.Listeners;
import nxt.util.Logger;
import nxt.util.ThreadPool;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONStreamAware;
Expand All @@ -39,6 +40,8 @@
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore;

Expand Down Expand Up @@ -75,6 +78,8 @@ static BlockchainProcessorImpl getInstance() {
private volatile boolean isScanning;
private volatile boolean forceScan = Nxt.getBooleanProperty("nxt.forceScan");
private volatile boolean validateAtScan = Nxt.getBooleanProperty("nxt.forceValidate");

private final ConcurrentMap<Long, SortedSet<TransactionImpl>> computedBlockTransactions = new ConcurrentHashMap<Long, SortedSet<TransactionImpl>>();

// Last downloaded block:
private Long lastDownloaded = 0L;
Expand Down Expand Up @@ -943,6 +948,7 @@ private void pushBlock(final BlockImpl block) throws BlockNotAcceptedException {
block.setPrevious(previousLastBlock);
blockListeners.notify(block, Event.BEFORE_BLOCK_ACCEPT);
transactionProcessor.requeueAllUnconfirmedTransactions();
computedBlockTransactions.clear();
Account.flushAccountTable();
addBlock(block);
accept(block, remainingAmount, remainingFee);
Expand Down Expand Up @@ -1069,9 +1075,13 @@ int getBlockVersion(int previousBlockHeight) {
: previousBlockHeight < Constants.NQT_BLOCK ? 2
: 3;
}

void generateBlock(String secretPhrase, byte[] publicKey, Long nonce) throws BlockNotAcceptedException {


public SortedSet<TransactionImpl> getBlockTransactions(Block previousBlock) {
SortedSet<TransactionImpl> previouslyComputedBlockedTransactions = computedBlockTransactions.get(previousBlock.getId());
if (previouslyComputedBlockedTransactions != null) {
return previouslyComputedBlockedTransactions;
}

TransactionProcessorImpl transactionProcessor = TransactionProcessorImpl.getInstance();
List<TransactionImpl> orderedUnconfirmedTransactions = new ArrayList<>();
try (FilteringIterator<TransactionImpl> transactions = new FilteringIterator<>(transactionProcessor.getAllUnconfirmedTransactions(),
Expand All @@ -1085,15 +1095,11 @@ public boolean ok(TransactionImpl transaction) {
orderedUnconfirmedTransactions.add(transaction);
}
}

BlockImpl previousBlock = blockchain.getLastBlock();


SortedSet<TransactionImpl> blockTransactions = new TreeSet<>();

Map<TransactionType, Set<String>> duplicates = new HashMap<>();

long totalAmountNQT = 0;
long totalFeeNQT = 0;
int payloadLength = 0;

int blockTimestamp = Nxt.getEpochTime();
Expand Down Expand Up @@ -1144,16 +1150,49 @@ public boolean ok(TransactionImpl transaction) {

blockTransactions.add(transaction);
payloadLength += transactionLength;
totalAmountNQT += transaction.getAmountNQT();
totalFeeNQT += transaction.getFeeNQT();

}

if (blockTransactions.size() == prevNumberOfNewTransactions) {
break;
}
}

computedBlockTransactions.putIfAbsent(previousBlock.getId(), blockTransactions);
return blockTransactions;
}

@Override
public byte[] getTransactionHash(Block previousBlock) {
SortedSet<TransactionImpl> transactions = BlockchainProcessorImpl.getInstance().getBlockTransactions(previousBlock);
MessageDigest digest = Crypto.sha256();

for (Transaction transaction : transactions) {
digest.update(transaction.getBytes());
}

return digest.digest();
}

void generateBlock(String secretPhrase, byte[] publicKey, Long nonce) throws BlockNotAcceptedException {
BlockImpl previousBlock = blockchain.getLastBlock();

SortedSet<TransactionImpl> blockTransactions = getBlockTransactions(previousBlock);
byte[] payloadHash = getTransactionHash(previousBlock);

long totalAmountNQT = 0;
long totalFeeNQT = 0;
int payloadLength = 0;

int blockTimestamp = Nxt.getEpochTime();

for (TransactionImpl transaction : blockTransactions) {
payloadLength += transaction.getSize();
totalAmountNQT += transaction.getAmountNQT();
totalFeeNQT += transaction.getFeeNQT();
}

TransactionProcessorImpl transactionProcessor = TransactionProcessorImpl.getInstance();
if(Subscription.isEnabled()) {
synchronized(blockchain) {
Subscription.clearRemovals();
Expand Down Expand Up @@ -1192,15 +1231,7 @@ public boolean ok(TransactionImpl transaction) {

//ATs for block

MessageDigest digest = Crypto.sha256();

for (Transaction transaction : blockTransactions) {
digest.update(transaction.getBytes());
}

byte[] payloadHash = digest.digest();

byte[] generationSignature = Nxt.getGenerator().calculateGenerationSignature(previousBlock.getGenerationSignature(), previousBlock.getGeneratorId());
byte[] generationSignature = Nxt.getGenerator().calculateGenerationSignature(previousBlock.getGenerationSignature(), previousBlock.getGeneratorId(), payloadHash, previousBlock.getHeight() + 1);

BlockImpl block;
byte[] previousBlockHash = Crypto.sha256().digest(previousBlock.getBytes());
Expand Down
2 changes: 2 additions & 0 deletions src/java/nxt/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public final class Constants {
public static final int AT_FIX_BLOCK_2 = 67000;
public static final int AT_FIX_BLOCK_3 = 92000;
public static final int AT_FIX_BLOCK_4 = 255000;

public static final int TRANSACTION_HASH_IN_GENERATION_SIG_BLOCK = 376600;

public static final int[] MIN_VERSION = new int[] {1, 2};

Expand Down
3 changes: 2 additions & 1 deletion src/java/nxt/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static enum Event {
GeneratorState addNonce(String secretPhrase, Long nonce, byte[] publicKey);
Collection<? extends GeneratorState> getAllGenerators();

byte[] calculateGenerationSignature(byte[] lastGenSig, long lastGenId);
byte[] calculateGenerationSignature(byte[] lastGenSig, long lastGenId, byte[] transactionHash, long blockHeight);
int calculateScoop(byte[] genSig, long height);
BigInteger calculateHit(long accountId, long nonce, byte[] genSig, int scoop);
BigInteger calculateHit(long accountId, long nonce, byte[] genSig, byte[] scoopData);
Expand All @@ -30,4 +30,5 @@ interface GeneratorState {
BigInteger getDeadline();
long getBlock();
}

}
25 changes: 18 additions & 7 deletions src/java/nxt/GeneratorImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -129,11 +131,19 @@ public Collection<? extends GeneratorState> getAllGenerators() {
}

@Override
public byte[] calculateGenerationSignature(byte[] lastGenSig, long lastGenId) {
ByteBuffer gensigbuf = ByteBuffer.allocate(32 + 8);
gensigbuf.put(lastGenSig);
gensigbuf.putLong(lastGenId);

public byte[] calculateGenerationSignature(byte[] lastGenSig, long lastGenId, byte[] transactionHash, long blockHeight) {
ByteBuffer gensigbuf;
if (blockHeight >= Constants.TRANSACTION_HASH_IN_GENERATION_SIG_BLOCK) {
gensigbuf = ByteBuffer.allocate(32 + 8 + 32);
gensigbuf.put(lastGenSig);
gensigbuf.putLong(lastGenId);
gensigbuf.put(transactionHash);
} else {
gensigbuf = ByteBuffer.allocate(32 + 8);
gensigbuf.put(lastGenSig);
gensigbuf.putLong(lastGenId);
}

Shabal256 md = new Shabal256();
md.update(gensigbuf.array());
return md.digest();
Expand Down Expand Up @@ -197,8 +207,9 @@ private GeneratorStateImpl(String secretPhrase, Long nonce, byte[] publicKey, Lo
Block lastBlock = Nxt.getBlockchain().getLastBlock();
byte[] lastGenSig = lastBlock.getGenerationSignature();
Long lastGenerator = lastBlock.getGeneratorId();
byte[] transactionHash = Nxt.getBlockchainProcessor().getTransactionHash(lastBlock);

byte[] newGenSig = calculateGenerationSignature(lastGenSig, lastGenerator);
byte[] newGenSig = calculateGenerationSignature(lastGenSig, lastGenerator, transactionHash, block);

int scoopNum = calculateScoop(newGenSig, lastBlock.getHeight() + 1);

Expand Down Expand Up @@ -278,7 +289,7 @@ public Collection<? extends GeneratorState> getAllGenerators() {
}

@Override
public byte[] calculateGenerationSignature(byte[] lastGenSig, long lastGenId) {
public byte[] calculateGenerationSignature(byte[] lastGenSig, long lastGenId, byte[] transactionHash, long blockHeight) {
return new byte[32];
}

Expand Down
16 changes: 13 additions & 3 deletions src/java/nxt/http/GetMiningInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import javax.servlet.http.HttpServletRequest;

import nxt.Block;
import nxt.Constants;
import nxt.Nxt;
import nxt.util.Convert;
import fr.cryptohash.Shabal256;
Expand All @@ -28,10 +29,19 @@ JSONStreamAware processRequest(HttpServletRequest req) {
Block lastBlock = Nxt.getBlockchain().getLastBlock();
byte[] lastGenSig = lastBlock.getGenerationSignature();
Long lastGenerator = lastBlock.getGeneratorId();
byte[] transactionHash = Nxt.getBlockchainProcessor().getTransactionHash(lastBlock);

ByteBuffer buf = ByteBuffer.allocate(32 + 8);
buf.put(lastGenSig);
buf.putLong(lastGenerator);
ByteBuffer buf;
if (lastBlock.getHeight() >= Constants.TRANSACTION_HASH_IN_GENERATION_SIG_BLOCK) {
buf = ByteBuffer.allocate(32 + 8 + 32);
buf.put(lastGenSig);
buf.putLong(lastGenerator);
buf.put(transactionHash);
} else {
buf = ByteBuffer.allocate(32 + 8);
buf.put(lastGenSig);
buf.putLong(lastGenerator);
}

Shabal256 md = new Shabal256();
md.update(buf.array());
Expand Down