The POW callback is now a service and its state stored.

The proof of work engine therefore just has to remember its initial hash making server based POW easier.
This commit is contained in:
2015-12-08 20:27:32 +01:00
parent 991a0e5f86
commit ab6a3c56dd
25 changed files with 289 additions and 103 deletions

View File

@ -22,6 +22,7 @@ import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.ports.MessageRepository;
import ch.dissem.bitmessage.utils.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -108,6 +109,20 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
return 0;
}
@Override
public Plaintext getMessage(byte[] initialHash) {
List<Plaintext> plaintexts = find("initial_hash=X'" + Strings.hex(initialHash) + "'");
switch (plaintexts.size()) {
case 0:
return null;
case 1:
return plaintexts.get(0);
default:
throw new RuntimeException("This shouldn't happen, found " + plaintexts.size() +
" messages, one or none was expected");
}
}
@Override
public List<Plaintext> findMessages(Label label) {
return find("id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ")");
@ -141,8 +156,8 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
long id = rs.getLong("id");
builder.id(id);
builder.IV(new InventoryVector(iv));
builder.from(ctx.getAddressRepo().getAddress(rs.getString("sender")));
builder.to(ctx.getAddressRepo().getAddress(rs.getString("recipient")));
builder.from(ctx.getAddressRepository().getAddress(rs.getString("sender")));
builder.to(ctx.getAddressRepository().getAddress(rs.getString("recipient")));
builder.sent(rs.getLong("sent"));
builder.received(rs.getLong("received"));
builder.status(Plaintext.Status.valueOf(rs.getString("status")));
@ -173,12 +188,12 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
public void save(Plaintext message) {
// save from address if necessary
if (message.getId() == null) {
BitmessageAddress savedAddress = ctx.getAddressRepo().getAddress(message.getFrom().getAddress());
BitmessageAddress savedAddress = ctx.getAddressRepository().getAddress(message.getFrom().getAddress());
if (savedAddress == null || savedAddress.getPrivateKey() == null) {
if (savedAddress != null && savedAddress.getAlias() != null) {
message.getFrom().setAlias(savedAddress.getAlias());
}
ctx.getAddressRepo().save(message.getFrom());
ctx.getAddressRepository().save(message.getFrom());
}
}
@ -219,7 +234,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
private void insert(Connection connection, Plaintext message) throws SQLException, IOException {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
"INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status, initial_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS);
ps.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null);
ps.setString(2, message.getType().name());
@ -229,6 +244,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
ps.setLong(6, message.getSent());
ps.setLong(7, message.getReceived());
ps.setString(8, message.getStatus() != null ? message.getStatus().name() : null);
ps.setBytes(9, message.getInitialHash());
ps.executeUpdate();

View File

@ -0,0 +1,69 @@
package ch.dissem.bitmessage.repository;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.ProofOfWorkRepository;
import ch.dissem.bitmessage.utils.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import static ch.dissem.bitmessage.utils.Singleton.security;
/**
* @author Christian Basler
*/
public class JdbcProofOfWorkRepository extends JdbcHelper implements ProofOfWorkRepository {
private static final Logger LOG = LoggerFactory.getLogger(JdbcProofOfWorkRepository.class);
public JdbcProofOfWorkRepository(JdbcConfig config) {
super(config);
}
@Override
public ObjectMessage getObject(byte[] initialHash) {
try (Connection connection = config.getConnection()) {
PreparedStatement ps = connection.prepareStatement("SELECT data, version FROM POW WHERE initial_hash=?");
ps.setBytes(1, initialHash);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Blob data = rs.getBlob("data");
return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length());
} else {
throw new RuntimeException("Object requested that we don't have. Initial hash: " + Strings.hex(initialHash));
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
@Override
public void putObject(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) {
try (Connection connection = config.getConnection()) {
PreparedStatement ps = connection.prepareStatement("INSERT INTO POW (initial_hash, data, version) VALUES (?, ?, ?)");
ps.setBytes(1, security().getInitialHash(object));
writeBlob(ps, 2, object);
ps.setLong(3, object.getVersion());
ps.executeUpdate();
} catch (SQLException e) {
LOG.debug("Error storing object of type " + object.getPayload().getClass().getSimpleName(), e);
throw new RuntimeException(e);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
@Override
public void removeObject(ObjectMessage object) {
try (Connection connection = config.getConnection()) {
PreparedStatement ps = connection.prepareStatement("DELETE FROM POW WHERE initial_hash=?");
ps.setBytes(1, security().getInitialHash(object));
ps.executeUpdate();
} catch (SQLException e) {
LOG.debug(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,2 @@
ALTER TABLE Message ADD COLUMN initial_hash BINARY(64);
ALTER TABLE Message ADD CONSTRAINT initial_hash_unique UNIQUE(initial_hash);

View File

@ -0,0 +1,5 @@
CREATE TABLE POW (
initial_hash BINARY(64) PRIMARY KEY,
data BLOB NOT NULL,
version BIGINT NOT NULL
);