diff --git a/src/main/java/org/qora/api/resource/TransactionsResource.java b/src/main/java/org/qora/api/resource/TransactionsResource.java index 278c255d..2fc00393 100644 --- a/src/main/java/org/qora/api/resource/TransactionsResource.java +++ b/src/main/java/org/qora/api/resource/TransactionsResource.java @@ -28,6 +28,7 @@ import org.qora.api.ApiErrors; import org.qora.api.ApiException; import org.qora.api.ApiExceptionFactory; import org.qora.api.model.SimpleTransactionSignRequest; +import org.qora.controller.Controller; import org.qora.data.transaction.TransactionData; import org.qora.globalization.Translator; import org.qora.repository.DataException; @@ -388,6 +389,9 @@ public class TransactionsResource { repository.getTransactionRepository().unconfirmTransaction(transactionData); repository.saveChanges(); + // Notify controller of new transaction + Controller.getInstance().onNewTransaction(transactionData); + return "true"; } catch (NumberFormatException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA, e); diff --git a/src/main/java/org/qora/controller/Controller.java b/src/main/java/org/qora/controller/Controller.java index 7e4aa7b8..7fa60b25 100644 --- a/src/main/java/org/qora/controller/Controller.java +++ b/src/main/java/org/qora/controller/Controller.java @@ -23,6 +23,7 @@ import org.qora.block.BlockChain; import org.qora.block.BlockGenerator; import org.qora.data.block.BlockData; import org.qora.data.network.PeerData; +import org.qora.data.transaction.TransactionData; import org.qora.network.Network; import org.qora.network.Peer; import org.qora.network.message.BlockMessage; @@ -31,12 +32,15 @@ import org.qora.network.message.GetSignaturesMessage; import org.qora.network.message.HeightMessage; import org.qora.network.message.Message; import org.qora.network.message.SignaturesMessage; +import org.qora.network.message.TransactionMessage; import org.qora.repository.DataException; import org.qora.repository.Repository; import org.qora.repository.RepositoryFactory; import org.qora.repository.RepositoryManager; import org.qora.repository.hsqldb.HSQLDBRepositoryFactory; import org.qora.settings.Settings; +import org.qora.transaction.Transaction; +import org.qora.transaction.Transaction.ValidationResult; import org.qora.utils.Base58; import org.qora.utils.NTP; @@ -216,26 +220,39 @@ public class Controller extends Thread { // If we have enough peers, potentially synchronize List peers = Network.getInstance().getHandshakeCompletedPeers(); - if (peers.size() >= Settings.getInstance().getMinPeers()) { - peers.removeIf(peer -> peer.getPeerData().getLastHeight() <= ourHeight); + if (peers.size() < Settings.getInstance().getMinPeers()) + return; - if (!peers.isEmpty()) { - // Pick random peer to sync with - int index = new SecureRandom().nextInt(peers.size()); - Peer peer = peers.get(index); + for(Peer peer : peers) + LOGGER.trace(String.format("Peer %s is at height %d", peer, peer.getPeerData().getLastHeight())); - if (!Synchronizer.getInstance().synchronize(peer)) { - // Failure so don't use this peer again for a while - try (final Repository repository = RepositoryManager.getRepository()) { - PeerData peerData = peer.getPeerData(); - peerData.setLastMisbehaved(NTP.getTime()); - repository.getNetworkRepository().save(peerData); - repository.saveChanges(); - } catch (DataException e) { - LOGGER.warn("Repository issue while updating peer synchronization info", e); - } + peers.removeIf(peer -> peer.getPeerData().getLastHeight() <= ourHeight); + + if (!peers.isEmpty()) { + // Pick random peer to sync with + int index = new SecureRandom().nextInt(peers.size()); + Peer peer = peers.get(index); + + if (!Synchronizer.getInstance().synchronize(peer)) { + LOGGER.debug(String.format("Failed to synchronize with peer %s", peer)); + + // Failure so don't use this peer again for a while + try (final Repository repository = RepositoryManager.getRepository()) { + PeerData peerData = peer.getPeerData(); + peerData.setLastMisbehaved(NTP.getTime()); + repository.getNetworkRepository().save(peerData); + repository.saveChanges(); + } catch (DataException e) { + LOGGER.warn("Repository issue while updating peer synchronization info", e); } + + return; } + + LOGGER.debug(String.format("Synchronized with peer %s", peer)); + + // Broadcast our new height + Network.getInstance().broadcast(recipientPeer -> new HeightMessage(getChainHeight())); } } @@ -366,9 +383,42 @@ public class Controller extends Thread { } break; + case TRANSACTION: + try (final Repository repository = RepositoryManager.getRepository()) { + TransactionMessage transactionMessage = (TransactionMessage) message; + + TransactionData transactionData = transactionMessage.getTransactionData(); + Transaction transaction = Transaction.fromData(repository, transactionData); + + // Check signature + if (!transaction.isSignatureValid()) + break; + + // Do we have it already? + if (repository.getTransactionRepository().exists(transactionData.getSignature())) + break; + + // Is it valid? + if (transaction.isValidUnconfirmed() != ValidationResult.OK) + break; + + // Seems ok - add to unconfirmed pile + repository.getTransactionRepository().save(transactionData); + repository.getTransactionRepository().unconfirmTransaction(transactionData); + repository.saveChanges(); + } catch (DataException e) { + LOGGER.error(String.format("Repository issue while responding to %s from peer %s", message.getType().name(), peer), e); + } + break; + default: break; } } + public void onNewTransaction(TransactionData transactionData) { + // Send round to all peers + Network.getInstance().broadcast(peer -> new TransactionMessage(transactionData)); + } + } diff --git a/src/main/java/org/qora/controller/Synchronizer.java b/src/main/java/org/qora/controller/Synchronizer.java index b82c48df..7504d8c9 100644 --- a/src/main/java/org/qora/controller/Synchronizer.java +++ b/src/main/java/org/qora/controller/Synchronizer.java @@ -109,15 +109,13 @@ public class Synchronizer { signatures.remove(0); ++this.ourHeight; - BlockData newBlockData = this.fetchBlockData(peer, signature); + Block newBlock = this.fetchBlock(repository, peer, signature); - if (newBlockData == null) { + if (newBlock == null) { LOGGER.info(String.format("Peer %s failed to respond with block for height %d", peer, this.ourHeight)); return false; } - Block newBlock = new Block(repository, newBlockData); - if (!newBlock.isSignatureValid()) { LOGGER.info(String.format("Peer %s sent block with invalid signature for height %d", peer, this.ourHeight)); return false; @@ -227,8 +225,8 @@ public class Synchronizer { return blockSignatures; } - private List getBlockSignatures(Peer peer, byte[] parentSignature, int countRequested) { - // TODO countRequested is v2+ feature + private List getBlockSignatures(Peer peer, byte[] parentSignature, int numberRequested) { + // TODO numberRequested is v2+ feature Message getSignaturesMessage = new GetSignaturesMessage(parentSignature); Message message = peer.getResponse(getSignaturesMessage); @@ -240,7 +238,7 @@ public class Synchronizer { return signaturesMessage.getSignatures(); } - private BlockData fetchBlockData(Peer peer, byte[] signature) { + private Block fetchBlock(Repository repository, Peer peer, byte[] signature) { Message getBlockMessage = new GetBlockMessage(signature); Message message = peer.getResponse(getBlockMessage); @@ -249,7 +247,12 @@ public class Synchronizer { BlockMessage blockMessage = (BlockMessage) message; - return blockMessage.getBlockData(); + try { + return new Block(repository, blockMessage.getBlockData(), blockMessage.getTransactions(), blockMessage.getAtStates()); + } catch (DataException e) { + LOGGER.debug("Failed to create block", e); + return null; + } } } diff --git a/src/main/java/org/qora/network/Handshake.java b/src/main/java/org/qora/network/Handshake.java index 1b1368f4..ea247d73 100644 --- a/src/main/java/org/qora/network/Handshake.java +++ b/src/main/java/org/qora/network/Handshake.java @@ -105,7 +105,7 @@ public enum Handshake { } }; - private static final long MAX_TIMESTAMP_DELTA = 1000; // ms + private static final long MAX_TIMESTAMP_DELTA = 2000; // ms public final MessageType expectedMessageType; diff --git a/src/main/java/org/qora/network/Network.java b/src/main/java/org/qora/network/Network.java index 2372cd8c..27043fac 100644 --- a/src/main/java/org/qora/network/Network.java +++ b/src/main/java/org/qora/network/Network.java @@ -13,6 +13,8 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -21,11 +23,13 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qora.controller.Controller; import org.qora.data.network.PeerData; +import org.qora.data.transaction.TransactionData; import org.qora.network.message.HeightMessage; import org.qora.network.message.Message; import org.qora.network.message.PeersMessage; import org.qora.network.message.PeersV2Message; import org.qora.network.message.PingMessage; +import org.qora.network.message.TransactionMessage; import org.qora.repository.DataException; import org.qora.repository.Repository; import org.qora.repository.RepositoryManager; @@ -56,6 +60,7 @@ public class Network extends Thread { private int maxPeers; private ExecutorService peerExecutor; private long nextBroadcast; + private Lock mergePeersLock; // Constructors @@ -92,6 +97,8 @@ public class Network extends Thread { peerExecutor = Executors.newCachedThreadPool(); nextBroadcast = System.currentTimeMillis(); + + mergePeersLock = new ReentrantLock(); } // Getters / setters @@ -377,18 +384,35 @@ public class Network extends Thread { // Make a note that we've successfully completed handshake (and when) peer.getPeerData().setLastConnected(NTP.getTime()); + // Start regular pings peer.startPings(); + // Send our height Message heightMessage = new HeightMessage(Controller.getInstance().getChainHeight()); - if (!peer.sendMessage(heightMessage)) { peer.disconnect(); return; } + // Send our peers list Message peersMessage = this.buildPeersMessage(peer); if (!peer.sendMessage(peersMessage)) peer.disconnect(); + + // Send our unconfirmed transactions + try (final Repository repository = RepositoryManager.getRepository()) { + List transactions = repository.getTransactionRepository().getUnconfirmedTransactions(); + + for (TransactionData transactionData : transactions) { + Message transactionMessage = new TransactionMessage(transactionData); + if (!peer.sendMessage(transactionMessage)) { + peer.disconnect(); + return; + } + } + } catch (DataException e) { + LOGGER.error("Repository issue while sending unconfirmed transactions", e); + } } /** Returns PEERS message made from peers we've connected to recently, and this node's details */ @@ -441,27 +465,42 @@ public class Network extends Thread { } private void mergePeers(List peerAddresses) { - try (final Repository repository = RepositoryManager.getRepository()) { - List knownPeers = repository.getNetworkRepository().getAllPeers(); + mergePeersLock.lock(); - // Resolve known peer hostnames - Function peerDataToSocketAddress = peerData -> new InetSocketAddress(peerData.getSocketAddress().getHostString(), - peerData.getSocketAddress().getPort()); - List knownPeerAddresses = knownPeers.stream().map(peerDataToSocketAddress).collect(Collectors.toList()); + try { + try (final Repository repository = RepositoryManager.getRepository()) { + List knownPeers = repository.getNetworkRepository().getAllPeers(); - // Filter out duplicates - Predicate addressKnown = peerAddress -> knownPeerAddresses.stream().anyMatch(knownAddress -> knownAddress.equals(peerAddress)); - peerAddresses.removeIf(addressKnown); + for (PeerData peerData : knownPeers) + LOGGER.trace(String.format("Known peer %s", peerData.getSocketAddress())); - // Save the rest into database - for (InetSocketAddress peerAddress : peerAddresses) { - PeerData peerData = new PeerData(peerAddress); - repository.getNetworkRepository().save(peerData); + // Resolve known peer hostnames + Function peerDataToSocketAddress = peerData -> new InetSocketAddress(peerData.getSocketAddress().getHostString(), + peerData.getSocketAddress().getPort()); + List knownPeerAddresses = knownPeers.stream().map(peerDataToSocketAddress).collect(Collectors.toList()); + + for (InetSocketAddress address : knownPeerAddresses) + LOGGER.trace(String.format("Resolved known peer %s", address)); + + // Filter out duplicates + // We have to use our own Peer.addressEquals as InetSocketAddress.equals isn't quite right for us + Predicate addressKnown = peerAddress -> knownPeerAddresses.stream() + .anyMatch(knownAddress -> Peer.addressEquals(knownAddress, peerAddress)); + peerAddresses.removeIf(addressKnown); + + // Save the rest into database + for (InetSocketAddress peerAddress : peerAddresses) { + PeerData peerData = new PeerData(peerAddress); + LOGGER.trace(String.format("Adding new peer %s to repository", peerAddress)); + repository.getNetworkRepository().save(peerData); + } + + repository.saveChanges(); + } catch (DataException e) { + LOGGER.error("Repository issue while merging peers list from remote node", e); } - - repository.saveChanges(); - } catch (DataException e) { - LOGGER.error("Repository issue while merging peers list from remote node", e); + } finally { + mergePeersLock.unlock(); } } diff --git a/src/main/java/org/qora/network/Peer.java b/src/main/java/org/qora/network/Peer.java index 32acd76c..ed62f219 100644 --- a/src/main/java/org/qora/network/Peer.java +++ b/src/main/java/org/qora/network/Peer.java @@ -180,6 +180,8 @@ public class Peer implements Runnable { if (message == null) return; + LOGGER.trace(String.format("Received %s message with ID %d from peer %s", message.getType().name(), message.getId(), this)); + // Find potential blocking queue for this id (expect null if id is -1) BlockingQueue queue = this.messages.get(message.getId()); if (queue != null) { @@ -209,7 +211,7 @@ public class Peer implements Runnable { try { // Send message - LOGGER.trace(String.format("Sending %s message to peer %s", message.getType().name(), this)); + LOGGER.trace(String.format("Sending %s message with ID %d to peer %s", message.getType().name(), message.getId(), this)); synchronized (this.out) { this.out.write(message.toBytes()); @@ -309,4 +311,12 @@ public class Peer implements Runnable { Network.getInstance().onDisconnect(this); } + /** Returns true if ports and addresses (or hostnames) match */ + public static boolean addressEquals(InetSocketAddress knownAddress, InetSocketAddress peerAddress) { + if (knownAddress.getPort() != peerAddress.getPort()) + return false; + + return knownAddress.getHostString().equalsIgnoreCase(peerAddress.getHostString()); + } + } diff --git a/src/main/java/org/qora/network/Proof.java b/src/main/java/org/qora/network/Proof.java index d32e7f05..12e05801 100644 --- a/src/main/java/org/qora/network/Proof.java +++ b/src/main/java/org/qora/network/Proof.java @@ -12,16 +12,6 @@ import com.google.common.primitives.Longs; public class Proof extends Thread { private static final int MIN_PROOF_ZEROS = 2; - private static final MessageDigest sha256; - static { - try { - sha256 = MessageDigest.getInstance("SHA256"); - } catch (NoSuchAlgorithmException e) { - // Can't progress - throw new RuntimeException("Message digest SHA256 not available"); - } - } - private static final HashSet seenSalts = new HashSet<>(); private Peer peer; @@ -63,6 +53,14 @@ public class Proof extends Thread { byte[] timestampBytes = Longs.toByteArray(timestamp); System.arraycopy(timestampBytes, 0, message, 8 + 8, timestampBytes.length); + MessageDigest sha256; + try { + sha256 = MessageDigest.getInstance("SHA256"); + } catch (NoSuchAlgorithmException e) { + // Can't progress + throw new RuntimeException("Message digest SHA256 not available"); + } + long nonce; for (nonce = 0; nonce < Long.MAX_VALUE; ++nonce) { // Check whether we're shutting down every so often @@ -77,6 +75,8 @@ public class Proof extends Thread { if (check(digest)) break; + + sha256.reset(); } ProofMessage proofMessage = new ProofMessage(timestamp, salt, nonce); @@ -104,6 +104,14 @@ public class Proof extends Thread { byte[] nonceBytes = Longs.toByteArray(nonce); System.arraycopy(nonceBytes, 0, message, 0, nonceBytes.length); + MessageDigest sha256; + try { + sha256 = MessageDigest.getInstance("SHA256"); + } catch (NoSuchAlgorithmException e) { + // Can't progress + throw new RuntimeException("Message digest SHA256 not available"); + } + byte[] digest = sha256.digest(message); return check(digest); diff --git a/src/main/java/org/qora/network/message/TransactionMessage.java b/src/main/java/org/qora/network/message/TransactionMessage.java new file mode 100644 index 00000000..a492f6d2 --- /dev/null +++ b/src/main/java/org/qora/network/message/TransactionMessage.java @@ -0,0 +1,50 @@ +package org.qora.network.message; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; + +import org.qora.data.transaction.TransactionData; +import org.qora.transform.TransformationException; +import org.qora.transform.transaction.TransactionTransformer; + +public class TransactionMessage extends Message { + + private TransactionData transactionData; + + public TransactionMessage(TransactionData transactionData) { + this(-1, transactionData); + } + + private TransactionMessage(int id, TransactionData transactionData) { + super(id, MessageType.TRANSACTION); + + this.transactionData = transactionData; + } + + public TransactionData getTransactionData() { + return this.transactionData; + } + + public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws UnsupportedEncodingException { + try { + TransactionData transactionData = TransactionTransformer.fromByteBuffer(byteBuffer); + + return new TransactionMessage(id, transactionData); + } catch (TransformationException e) { + return null; + } + } + + @Override + protected byte[] toData() { + if (this.transactionData == null) + return null; + + try { + return TransactionTransformer.toBytes(this.transactionData); + } catch (TransformationException e) { + return null; + } + } + +} diff --git a/src/main/java/org/qora/repository/TransactionRepository.java b/src/main/java/org/qora/repository/TransactionRepository.java index 97a6aa34..026340ac 100644 --- a/src/main/java/org/qora/repository/TransactionRepository.java +++ b/src/main/java/org/qora/repository/TransactionRepository.java @@ -19,6 +19,8 @@ public interface TransactionRepository { /** Returns block height containing transaction or 0 if not in a block or transaction doesn't exist */ public int getHeightFromSignature(byte[] signature) throws DataException; + public boolean exists(byte[] signature) throws DataException; + // Transaction participants public List getSignaturesInvolvingAddress(String address) throws DataException; diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java index e41e2c31..33857895 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java @@ -77,6 +77,7 @@ public class HSQLDBDatabaseUpdates { stmt.execute("SET DATABASE SQL NAMES TRUE"); // SQL keywords cannot be used as DB object names, e.g. table names stmt.execute("SET DATABASE SQL SYNTAX MYS TRUE"); // Required for our use of INSERT ... ON DUPLICATE KEY UPDATE ... syntax stmt.execute("SET DATABASE SQL RESTRICT EXEC TRUE"); // No multiple-statement execute() or DDL/DML executeQuery() + stmt.execute("SET DATABASE TRANSACTION CONTROL MVCC"); // Use MVCC over default two-phase locking, a-k-a "LOCKS" stmt.execute("SET DATABASE DEFAULT TABLE TYPE CACHED"); stmt.execute("SET DATABASE COLLATION SQL_TEXT NO PAD"); // Do not pad strings to same length before comparison stmt.execute("CREATE COLLATION SQL_TEXT_UCC_NO_PAD FOR SQL_TEXT FROM SQL_TEXT_UCC NO PAD"); diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java index 09481e09..efc6e1e1 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java @@ -357,4 +357,33 @@ public class HSQLDBRepository implements Repository { return sql; } -} + /** Logs other HSQLDB sessions then re-throws passed exception */ + public SQLException examineException(SQLException e) throws SQLException { + LOGGER.error("SQL error: " + e.getMessage()); + + // Serialization failure / potential deadlock - so list other sessions + try (ResultSet resultSet = this.checkedExecute( + "SELECT session_id, transaction, transaction_size, waiting_for_this, this_waiting_for, current_statement FROM Information_schema.system_sessions")) { + if (resultSet == null) + return e; + + do { + long sessionId = resultSet.getLong(1); + boolean inTransaction = resultSet.getBoolean(2); + long transactionSize = resultSet.getLong(3); + String waitingForThis = resultSet.getString(4); + String thisWaitingFor = resultSet.getString(5); + String currentStatement = resultSet.getString(6); + + LOGGER.error(String.format("Session %d, %s transaction (size %d), waiting for this '%s', this waiting for '%s', current statement: %s", + sessionId, (inTransaction ? "in" : "not in"), transactionSize, waitingForThis, thisWaitingFor, currentStatement)); + } while (resultSet.next()); + } catch (SQLException de) { + // Throw original exception instead + return e; + } + + return e; + } + +} \ No newline at end of file diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBSaver.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBSaver.java index f34d5dc4..b004b647 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBSaver.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBSaver.java @@ -62,6 +62,8 @@ public class HSQLDBSaver { this.bindValues(preparedStatement); return preparedStatement.execute(); + } catch (SQLException e) { + throw repository.examineException(e); } } diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java index fb5054cf..e61ea4e2 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java @@ -251,6 +251,15 @@ public class HSQLDBTransactionRepository implements TransactionRepository { } } + @Override + public boolean exists(byte[] signature) throws DataException { + try { + return this.repository.exists("Transactions", "signature = ?", signature); + } catch (SQLException e) { + throw new DataException("Unable to check for transaction in repository", e); + } + } + @Override public List getSignaturesInvolvingAddress(String address) throws DataException { List signatures = new ArrayList(); diff --git a/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java index 7f07f48d..69460da3 100644 --- a/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java @@ -40,7 +40,7 @@ public class AddGroupAdminTransactionTransformer extends TransactionTransformer layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/ArbitraryTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/ArbitraryTransactionTransformer.java index fb592c8f..e592cb6d 100644 --- a/src/main/java/org/qora/transform/transaction/ArbitraryTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/ArbitraryTransactionTransformer.java @@ -59,7 +59,7 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); int version = ArbitraryTransaction.getVersionByTimestamp(timestamp); diff --git a/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java index bd399c1c..3500f670 100644 --- a/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java @@ -26,7 +26,7 @@ public class AtTransactionTransformer extends TransactionTransformer { private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + SENDER_LENGTH + RECIPIENT_LENGTH + AMOUNT_LENGTH + ASSET_ID_LENGTH + DATA_SIZE_LENGTH; - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { throw new TransformationException("Serialized AT Transactions should not exist!"); } diff --git a/src/main/java/org/qora/transform/transaction/BuyNameTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/BuyNameTransactionTransformer.java index dbbe144a..c27b6c50 100644 --- a/src/main/java/org/qora/transform/transaction/BuyNameTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/BuyNameTransactionTransformer.java @@ -45,7 +45,7 @@ public class BuyNameTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/CancelAssetOrderTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CancelAssetOrderTransactionTransformer.java index 7845c095..0bdab13d 100644 --- a/src/main/java/org/qora/transform/transaction/CancelAssetOrderTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CancelAssetOrderTransactionTransformer.java @@ -39,7 +39,7 @@ public class CancelAssetOrderTransactionTransformer extends TransactionTransform layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/CancelGroupBanTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CancelGroupBanTransactionTransformer.java index 2a2f3fe2..07ec79f1 100644 --- a/src/main/java/org/qora/transform/transaction/CancelGroupBanTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CancelGroupBanTransactionTransformer.java @@ -40,7 +40,7 @@ public class CancelGroupBanTransactionTransformer extends TransactionTransformer layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java index c79a2e26..1a0f6a77 100644 --- a/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java @@ -40,7 +40,7 @@ public class CancelGroupInviteTransactionTransformer extends TransactionTransfor layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/CancelSellNameTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CancelSellNameTransactionTransformer.java index ba27b53c..5e4f1d83 100644 --- a/src/main/java/org/qora/transform/transaction/CancelSellNameTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CancelSellNameTransactionTransformer.java @@ -41,7 +41,7 @@ public class CancelSellNameTransactionTransformer extends TransactionTransformer layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/CreateAssetOrderTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CreateAssetOrderTransactionTransformer.java index ce989202..bfbb2d28 100644 --- a/src/main/java/org/qora/transform/transaction/CreateAssetOrderTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CreateAssetOrderTransactionTransformer.java @@ -43,7 +43,7 @@ public class CreateAssetOrderTransactionTransformer extends TransactionTransform layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java index 069260ab..122e8c74 100644 --- a/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java @@ -48,7 +48,7 @@ public class CreateGroupTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/CreatePollTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CreatePollTransactionTransformer.java index 9079188c..ee7b6aa0 100644 --- a/src/main/java/org/qora/transform/transaction/CreatePollTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CreatePollTransactionTransformer.java @@ -55,7 +55,7 @@ public class CreatePollTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/DeployAtTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/DeployAtTransactionTransformer.java index f354735c..9317d8e2 100644 --- a/src/main/java/org/qora/transform/transaction/DeployAtTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/DeployAtTransactionTransformer.java @@ -59,7 +59,7 @@ public class DeployAtTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); int version = DeployAtTransaction.getVersionByTimestamp(timestamp); diff --git a/src/main/java/org/qora/transform/transaction/GenesisTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/GenesisTransactionTransformer.java index c317341c..0448046b 100644 --- a/src/main/java/org/qora/transform/transaction/GenesisTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/GenesisTransactionTransformer.java @@ -41,7 +41,7 @@ public class GenesisTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); String recipient = Serialization.deserializeAddress(byteBuffer); diff --git a/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java index 448ee4bb..2e0a0c7e 100644 --- a/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java @@ -47,7 +47,7 @@ public class GroupBanTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java index b46d2231..98c2df43 100644 --- a/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java @@ -42,7 +42,7 @@ public class GroupInviteTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java index a98807f6..a2dd9bfe 100644 --- a/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java @@ -45,7 +45,7 @@ public class GroupKickTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/IssueAssetTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/IssueAssetTransactionTransformer.java index 65fce444..6da7819f 100644 --- a/src/main/java/org/qora/transform/transaction/IssueAssetTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/IssueAssetTransactionTransformer.java @@ -54,7 +54,7 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java index 317d4c2a..26bab418 100644 --- a/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java @@ -38,7 +38,7 @@ public class JoinGroupTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java index a46bfb02..77c4634b 100644 --- a/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java @@ -38,7 +38,7 @@ public class LeaveGroupTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/MessageTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/MessageTransactionTransformer.java index 57ce16dc..7f6d06ca 100644 --- a/src/main/java/org/qora/transform/transaction/MessageTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/MessageTransactionTransformer.java @@ -55,7 +55,7 @@ public class MessageTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); int version = MessageTransaction.getVersionByTimestamp(timestamp); diff --git a/src/main/java/org/qora/transform/transaction/MultiPaymentTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/MultiPaymentTransactionTransformer.java index c5c14747..3b6c29bb 100644 --- a/src/main/java/org/qora/transform/transaction/MultiPaymentTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/MultiPaymentTransactionTransformer.java @@ -48,7 +48,7 @@ public class MultiPaymentTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/PaymentTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/PaymentTransactionTransformer.java index bf7e45fc..636ad910 100644 --- a/src/main/java/org/qora/transform/transaction/PaymentTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/PaymentTransactionTransformer.java @@ -40,7 +40,7 @@ public class PaymentTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/RegisterNameTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/RegisterNameTransactionTransformer.java index 6a5bb1b3..9cdf4c91 100644 --- a/src/main/java/org/qora/transform/transaction/RegisterNameTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/RegisterNameTransactionTransformer.java @@ -46,7 +46,7 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java index 6adbca0e..2d265b89 100644 --- a/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java @@ -40,7 +40,7 @@ public class RemoveGroupAdminTransactionTransformer extends TransactionTransform layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/SellNameTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/SellNameTransactionTransformer.java index 2b402df3..66af7b53 100644 --- a/src/main/java/org/qora/transform/transaction/SellNameTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/SellNameTransactionTransformer.java @@ -43,7 +43,7 @@ public class SellNameTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/TransactionTransformer.java b/src/main/java/org/qora/transform/transaction/TransactionTransformer.java index edbbdca4..8d079762 100644 --- a/src/main/java/org/qora/transform/transaction/TransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/TransactionTransformer.java @@ -190,13 +190,17 @@ public abstract class TransactionTransformer extends Transformer { if (bytes == null) return null; - if (bytes.length < TYPE_LENGTH) - throw new TransformationException("Byte data too short to determine transaction type"); - LOGGER.trace("tx hex: " + HashCode.fromBytes(bytes).toString()); ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + return fromByteBuffer(byteBuffer); + } + + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + if (byteBuffer.remaining() < TYPE_LENGTH) + throw new TransformationException("Byte data too short to determine transaction type"); + TransactionType type = TransactionType.valueOf(byteBuffer.getInt()); if (type == null) return null; diff --git a/src/main/java/org/qora/transform/transaction/TransferAssetTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/TransferAssetTransactionTransformer.java index 5d89d8eb..d6b0d650 100644 --- a/src/main/java/org/qora/transform/transaction/TransferAssetTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/TransferAssetTransactionTransformer.java @@ -41,7 +41,7 @@ public class TransferAssetTransactionTransformer extends TransactionTransformer layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java index abda115e..5d63f331 100644 --- a/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java @@ -48,7 +48,7 @@ public class UpdateGroupTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/UpdateNameTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/UpdateNameTransactionTransformer.java index 0bc47b8d..58beec5e 100644 --- a/src/main/java/org/qora/transform/transaction/UpdateNameTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/UpdateNameTransactionTransformer.java @@ -46,7 +46,7 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH]; diff --git a/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java index 82e72151..171f46a7 100644 --- a/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java @@ -42,7 +42,7 @@ public class VoteOnPollTransactionTransformer extends TransactionTransformer { layout.add("signature", TransformationType.SIGNATURE); } - static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); byte[] reference = new byte[REFERENCE_LENGTH];