Server POW should now work
This commit is contained in:
parent
891294f267
commit
aafa4a4a11
@ -19,12 +19,11 @@ package ch.dissem.bitmessage.server;
|
|||||||
import ch.dissem.bitmessage.BitmessageContext;
|
import ch.dissem.bitmessage.BitmessageContext;
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
|
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
|
||||||
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
|
import ch.dissem.bitmessage.ports.*;
|
||||||
import ch.dissem.bitmessage.repository.JdbcAddressRepository;
|
import ch.dissem.bitmessage.repository.*;
|
||||||
import ch.dissem.bitmessage.repository.JdbcConfig;
|
|
||||||
import ch.dissem.bitmessage.repository.JdbcInventory;
|
|
||||||
import ch.dissem.bitmessage.repository.JdbcMessageRepository;
|
|
||||||
import ch.dissem.bitmessage.security.bc.BouncySecurity;
|
import ch.dissem.bitmessage.security.bc.BouncySecurity;
|
||||||
|
import ch.dissem.bitmessage.server.repository.ServerProofOfWorkRepository;
|
||||||
|
import ch.dissem.bitmessage.utils.Singleton;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -47,17 +46,74 @@ public class JabitServerConfig {
|
|||||||
@Value("${bitmessage.connection.limit}")
|
@Value("${bitmessage.connection.limit}")
|
||||||
private int connectionLimit;
|
private int connectionLimit;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JdbcConfig jdbcConfig() {
|
||||||
|
return new JdbcConfig("jdbc:h2:file:./jabit;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=10", "sa", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AddressRepository addressRepo() {
|
||||||
|
return new JdbcAddressRepository(jdbcConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Inventory inventory() {
|
||||||
|
return new JdbcInventory(jdbcConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MessageRepository messageRepo() {
|
||||||
|
return new JdbcMessageRepository(jdbcConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ProofOfWorkRepository proofOfWorkRepo() {
|
||||||
|
return new JdbcProofOfWorkRepository(jdbcConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public NodeRegistry nodeRegistry() {
|
||||||
|
return new MemoryNodeRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public NetworkHandler networkHandler() {
|
||||||
|
return new DefaultNetworkHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Security security() {
|
||||||
|
BouncySecurity security = new BouncySecurity();
|
||||||
|
Singleton.initialize(security); // needed for admins and clients
|
||||||
|
return security;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BitmessageContext.Listener serverListener() {
|
||||||
|
return new ServerListener(admins(), clients(), whitelist(), shortlist(), blacklist());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServerProofOfWorkRepository serverProofOfWorkRepository() {
|
||||||
|
return new ServerProofOfWorkRepository(jdbcConfig());
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
public CustomCommandHandler commandHandler() {
|
||||||
|
return new ProofOfWorkRequestHandler(serverProofOfWorkRepository(), clients());
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public BitmessageContext bitmessageContext() {
|
public BitmessageContext bitmessageContext() {
|
||||||
JdbcConfig config = new JdbcConfig("jdbc:h2:file:./jabit;AUTO_SERVER=TRUE", "sa", null);
|
|
||||||
return new BitmessageContext.Builder()
|
return new BitmessageContext.Builder()
|
||||||
.addressRepo(new JdbcAddressRepository(config))
|
.addressRepo(addressRepo())
|
||||||
.inventory(new JdbcInventory(config))
|
.inventory(inventory())
|
||||||
.messageRepo(new JdbcMessageRepository(config))
|
.messageRepo(messageRepo())
|
||||||
.nodeRegistry(new MemoryNodeRegistry())
|
.nodeRegistry(nodeRegistry())
|
||||||
.networkHandler(new DefaultNetworkHandler())
|
.powRepo(proofOfWorkRepo())
|
||||||
.listener(new ServerListener(admins(), clients(), whitelist(), shortlist(), blacklist()))
|
.networkHandler(networkHandler())
|
||||||
.security(new BouncySecurity())
|
.listener(serverListener())
|
||||||
|
.customCommandHandler(commandHandler())
|
||||||
|
.security(security())
|
||||||
.port(port)
|
.port(port)
|
||||||
.connectionLimit(connectionLimit)
|
.connectionLimit(connectionLimit)
|
||||||
.connectionTTL(connectionTTL)
|
.connectionTTL(connectionTTL)
|
||||||
@ -74,6 +130,7 @@ public class JabitServerConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Set<BitmessageAddress> clients() {
|
public Set<BitmessageAddress> clients() {
|
||||||
|
security();
|
||||||
return Utils.readOrCreateList(
|
return Utils.readOrCreateList(
|
||||||
CLIENT_LIST,
|
CLIENT_LIST,
|
||||||
"# Clients may send incomplete objects for proof of work.\n"
|
"# Clients may send incomplete objects for proof of work.\n"
|
||||||
|
@ -16,57 +16,122 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.server;
|
package ch.dissem.bitmessage.server;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.InternalContext;
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.CustomMessage;
|
import ch.dissem.bitmessage.entity.CustomMessage;
|
||||||
import ch.dissem.bitmessage.entity.MessagePayload;
|
import ch.dissem.bitmessage.entity.MessagePayload;
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||||
import ch.dissem.bitmessage.extensions.CryptoCustomMessage;
|
import ch.dissem.bitmessage.extensions.CryptoCustomMessage;
|
||||||
import ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest;
|
import ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest;
|
||||||
import ch.dissem.bitmessage.ports.CustomCommandHandler;
|
import ch.dissem.bitmessage.ports.CustomCommandHandler;
|
||||||
import ch.dissem.bitmessage.ports.ProofOfWorkEngine;
|
import ch.dissem.bitmessage.ports.ProofOfWorkEngine;
|
||||||
import ch.dissem.bitmessage.server.repository.ProofOfWorkRepository;
|
import ch.dissem.bitmessage.server.repository.ServerProofOfWorkRepository;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest.Request.CALCULATING;
|
||||||
|
import static ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest.Request.COMPLETE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christian Basler
|
* @author Christian Basler
|
||||||
*/
|
*/
|
||||||
public class ProofOfWorkRequestHandler implements CustomCommandHandler {
|
public class ProofOfWorkRequestHandler implements CustomCommandHandler, InternalContext.ContextHolder {
|
||||||
private final List<byte[]> decryptionKeys = new ArrayList<>();
|
private final static Logger LOG = LoggerFactory.getLogger(ProofOfWorkRequestHandler.class);
|
||||||
private ProofOfWorkRepository repo;
|
|
||||||
|
private final List<byte[]> decryptionKeys;
|
||||||
|
private final ServerProofOfWorkRepository repo;
|
||||||
|
private BitmessageAddress serverIdentity;
|
||||||
private ProofOfWorkEngine engine;
|
private ProofOfWorkEngine engine;
|
||||||
|
private InternalContext context;
|
||||||
|
|
||||||
|
public ProofOfWorkRequestHandler(ServerProofOfWorkRepository repo, Collection<BitmessageAddress> clients) {
|
||||||
|
this.repo = repo;
|
||||||
|
decryptionKeys = clients.stream().map(BitmessageAddress::getPublicDecryptionKey).collect(Collectors.toList());
|
||||||
|
new Timer().schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
doMissingProofOfWork();
|
||||||
|
}
|
||||||
|
}, 15_000); // After 15 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doMissingProofOfWork() {
|
||||||
|
List<ServerProofOfWorkRepository.Task> incompleteTasks = repo.getIncompleteTasks();
|
||||||
|
LOG.info("Doing POW for " + incompleteTasks.size() + " tasks.");
|
||||||
|
for (ServerProofOfWorkRepository.Task task : incompleteTasks) {
|
||||||
|
engine.calculateNonce(task.initialHash, task.target, repo::updateTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MessagePayload handle(CustomMessage message) {
|
public MessagePayload handle(CustomMessage message) {
|
||||||
try {
|
try {
|
||||||
CryptoCustomMessage<ProofOfWorkRequest> cryptoMessage = CryptoCustomMessage.read(message.getData(),
|
CryptoCustomMessage<ProofOfWorkRequest> cryptoMessage = CryptoCustomMessage.read(message,
|
||||||
(sender, in) -> ProofOfWorkRequest.read(sender, in));
|
ProofOfWorkRequest::read);
|
||||||
ProofOfWorkRequest request = decrypt(cryptoMessage);
|
ProofOfWorkRequest request = decrypt(cryptoMessage);
|
||||||
if (request == null) return error("Unknown encryption key.");
|
if (request == null)
|
||||||
|
return CustomMessage.error(
|
||||||
|
"Unknown sender. Please ask the server's administrator to add you as a client. " +
|
||||||
|
"For this he'll need your identity."
|
||||||
|
);
|
||||||
switch (request.getRequest()) {
|
switch (request.getRequest()) {
|
||||||
case CALCULATE:
|
case CALCULATE:
|
||||||
repo.storeTask(request); // FIXME
|
if (!repo.hasTask(request.getInitialHash())) {
|
||||||
engine.calculateNonce(request.getInitialHash(), request.getData(), nonce -> {
|
repo.storeTask(request);
|
||||||
|
// TODO: This is probably the place to do some book-keeping
|
||||||
});
|
// if we want to bill our customers.
|
||||||
|
engine.calculateNonce(request.getInitialHash(), request.getData(), repo::updateTask);
|
||||||
|
return new CryptoCustomMessage<>(
|
||||||
|
new ProofOfWorkRequest(getIdentity(), request.getInitialHash(), CALCULATING, new byte[0])
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
byte[] nonce = repo.getNonce(request);
|
||||||
|
CryptoCustomMessage<ProofOfWorkRequest> response;
|
||||||
|
if (nonce != null) {
|
||||||
|
response = new CryptoCustomMessage<>(
|
||||||
|
new ProofOfWorkRequest(getIdentity(), request.getInitialHash(), COMPLETE, nonce)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
response = new CryptoCustomMessage<>(
|
||||||
|
new ProofOfWorkRequest(getIdentity(), request.getInitialHash(), CALCULATING, new byte[0])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
response.signAndEncrypt(serverIdentity, request.getSender().getPubkey().getEncryptionKey());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return error(e.getMessage());
|
return CustomMessage.error(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MessagePayload error(String message) {
|
private BitmessageAddress getIdentity() {
|
||||||
try {
|
if (serverIdentity == null) {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
synchronized (this) {
|
||||||
out.write("ERROR\n".getBytes("UTF-8"));
|
if (serverIdentity == null) {
|
||||||
out.write(message.getBytes("UTF-8"));
|
serverIdentity = context.getAddressRepository().getIdentities().stream().findFirst().orElseGet(() -> {
|
||||||
return new CustomMessage(out.toByteArray());
|
final BitmessageAddress identity = new BitmessageAddress(new PrivateKey(
|
||||||
} catch (Exception e) {
|
false,
|
||||||
throw new RuntimeException(e);
|
context.getStreams()[0],
|
||||||
|
context.getNetworkNonceTrialsPerByte(),
|
||||||
|
context.getNetworkExtraBytes()
|
||||||
|
));
|
||||||
|
context.getAddressRepository().save(identity);
|
||||||
|
return identity;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return serverIdentity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProofOfWorkRequest decrypt(CryptoCustomMessage<ProofOfWorkRequest> cryptoMessage) {
|
private ProofOfWorkRequest decrypt(CryptoCustomMessage<ProofOfWorkRequest> cryptoMessage) {
|
||||||
@ -81,4 +146,9 @@ public class ProofOfWorkRequestHandler implements CustomCommandHandler {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContext(InternalContext context) {
|
||||||
|
this.context = context;
|
||||||
|
this.engine = context.getProofOfWorkEngine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,44 +16,26 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.server.repository;
|
package ch.dissem.bitmessage.server.repository;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.InternalContext;
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
|
||||||
import ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest;
|
import ch.dissem.bitmessage.extensions.pow.ProofOfWorkRequest;
|
||||||
import ch.dissem.bitmessage.repository.JdbcConfig;
|
import ch.dissem.bitmessage.repository.JdbcConfig;
|
||||||
import ch.dissem.bitmessage.repository.JdbcHelper;
|
import ch.dissem.bitmessage.repository.JdbcHelper;
|
||||||
import ch.dissem.bitmessage.server.entities.Update;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static ch.dissem.bitmessage.server.repository.ProofOfWorkRepository.Status.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christian Basler
|
* @author Christian Basler
|
||||||
*/
|
*/
|
||||||
public class ProofOfWorkRepository extends JdbcHelper implements InternalContext.ContextHolder {
|
public class ServerProofOfWorkRepository extends JdbcHelper {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ProofOfWorkRepository.class);
|
|
||||||
|
|
||||||
private InternalContext context;
|
public ServerProofOfWorkRepository(JdbcConfig config) {
|
||||||
|
|
||||||
protected ProofOfWorkRepository(JdbcConfig config) {
|
|
||||||
super(config);
|
super(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContext(InternalContext context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* client (can be removed once the new IV is returned)
|
* client (can be removed once the new IV is returned)
|
||||||
* IV (without nonce)
|
* IV (without nonce)
|
||||||
@ -64,61 +46,79 @@ public class ProofOfWorkRepository extends JdbcHelper implements InternalContext
|
|||||||
public void storeTask(ProofOfWorkRequest request) {
|
public void storeTask(ProofOfWorkRequest request) {
|
||||||
try (Connection connection = config.getConnection()) {
|
try (Connection connection = config.getConnection()) {
|
||||||
PreparedStatement ps = connection.prepareStatement(
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
"INSERT INTO ProofOfWorkTask (initial_hash, client, target, status) VALUES (?, ?, ?, ?)");
|
"INSERT INTO ProofOfWorkTask (initial_hash, client, target) VALUES (?, ?, ?)");
|
||||||
ps.setBytes(1, request.getInitialHash());
|
ps.setBytes(1, request.getInitialHash());
|
||||||
ps.setString(2, request.getClient().getAddress());
|
ps.setString(2, request.getSender().getAddress());
|
||||||
ps.setBytes(3, request.getData());
|
ps.setBytes(3, request.getData());
|
||||||
ps.setString(4, CALCULATING.name());
|
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateTask(InventoryVector temporaryIV, InventoryVector newIV) {
|
public void updateTask(byte[] initalHash, byte[] nonce) {
|
||||||
try (Connection connection = config.getConnection()) {
|
try (Connection connection = config.getConnection()) {
|
||||||
PreparedStatement ps = connection.prepareStatement(
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
"UPDATE ProofOfWorkTask SET IV = ?, status = ?, data = NULL WHERE temporaryIV = ?");
|
"UPDATE ProofOfWorkTask SET nonce = ? WHERE initial_hash = ?");
|
||||||
ps.setBytes(1, newIV.getHash());
|
ps.setBytes(1, nonce);
|
||||||
ps.setString(2, FINISHED.name());
|
ps.setBytes(2, initalHash);
|
||||||
ps.setBytes(3, temporaryIV.getHash());
|
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Update<InventoryVector>> getUnconfirmed(BitmessageAddress client) {
|
public byte[] getNonce(ProofOfWorkRequest request) {
|
||||||
List<Update<InventoryVector>> result = new LinkedList<>();
|
|
||||||
try (Connection connection = config.getConnection()) {
|
try (Connection connection = config.getConnection()) {
|
||||||
PreparedStatement ps = connection.prepareStatement("SELECT temporaryIV, IV FROM ProofOfWorkTask WHERE client = ? AND status = ?");
|
PreparedStatement ps = connection.prepareStatement("SELECT nonce FROM ProofOfWorkTask WHERE initial_hash = ?");
|
||||||
ps.setString(1, client.getAddress());
|
ps.setBytes(1, request.getInitialHash());
|
||||||
ps.setString(2, FINISHED.name());
|
|
||||||
ResultSet rs = ps.executeQuery();
|
ResultSet rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
if (rs.next()) {
|
||||||
InventoryVector temporaryIV = new InventoryVector(rs.getBytes(1));
|
return rs.getBytes(1);
|
||||||
InventoryVector iv = new InventoryVector(rs.getBytes(2));
|
} else {
|
||||||
result.add(new Update<>(temporaryIV, iv));
|
return null;
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void confirm(Stream<InventoryVector> unconfirmed) {
|
public boolean hasTask(byte[] initialHash) {
|
||||||
try (Connection connection = config.getConnection()) {
|
try (Connection connection = config.getConnection()) {
|
||||||
PreparedStatement ps = connection.prepareStatement(
|
PreparedStatement ps = connection.prepareStatement("SELECT count(1) FROM ProofOfWorkTask WHERE initial_hash = ?");
|
||||||
"UPDATE ProofOfWorkTask SET status = ?, IV = NULL, client = NULL WHERE IV = ANY(?)");
|
ps.setBytes(1, initialHash);
|
||||||
ps.setString(1, CONFIRMED.name());
|
ResultSet rs = ps.executeQuery();
|
||||||
ps.setArray(2, connection.createArrayOf("BINARY", unconfirmed.map(InventoryVector::getHash).toArray()));
|
rs.next();
|
||||||
ps.executeUpdate();
|
return rs.getInt(1) > 0;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Status {
|
public List<Task> getIncompleteTasks() {
|
||||||
CALCULATING, FINISHED, CONFIRMED
|
try (Connection connection = config.getConnection()) {
|
||||||
|
List<Task> result = new LinkedList<>();
|
||||||
|
ResultSet rs = connection.createStatement().executeQuery(
|
||||||
|
"SELECT initial_hash, target FROM ProofOfWorkTask WHERE nonce IS NULL");
|
||||||
|
while (rs.next()) {
|
||||||
|
result.add(new Task(
|
||||||
|
rs.getBytes(1),
|
||||||
|
rs.getBytes(2)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Task {
|
||||||
|
public final byte[] initialHash;
|
||||||
|
public final byte[] target;
|
||||||
|
|
||||||
|
private Task(byte[] initialHash, byte[] target) {
|
||||||
|
this.initialHash = initialHash;
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user