Refactor to utilize Kotlin features
This commit is contained in:
parent
b93f382ccd
commit
fab1c06135
@ -37,33 +37,33 @@ import java.util.*
|
|||||||
data class Message constructor(
|
data class Message constructor(
|
||||||
val subject: String,
|
val subject: String,
|
||||||
val body: String,
|
val body: String,
|
||||||
val parents: List<InventoryVector>,
|
val parents: List<InventoryVector> = emptyList(),
|
||||||
val files: List<Attachment>
|
val files: List<Attachment> = emptyList()
|
||||||
) : ExtendedEncoding.ExtendedType {
|
) : ExtendedEncoding.ExtendedType {
|
||||||
|
|
||||||
override val type: String = TYPE
|
override val type: String = TYPE
|
||||||
|
|
||||||
override fun pack(): MPMap<MPString, MPType<*>> {
|
override fun pack(): MPMap<MPString, MPType<*>> {
|
||||||
val result = MPMap<MPString, MPType<*>>()
|
val result = MPMap<MPString, MPType<*>>()
|
||||||
result.put("".mp, TYPE.mp)
|
result["".mp] = TYPE.mp
|
||||||
result.put("subject".mp, subject.mp)
|
result["subject".mp] = subject.mp
|
||||||
result.put("body".mp, body.mp)
|
result["body".mp] = body.mp
|
||||||
|
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
val items = MPArray<MPMap<MPString, MPType<*>>>()
|
val items = MPArray<MPMap<MPString, MPType<*>>>()
|
||||||
result.put("files".mp, items)
|
result["files".mp] = items
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
val item = MPMap<MPString, MPType<*>>()
|
val item = MPMap<MPString, MPType<*>>()
|
||||||
item.put("name".mp, file.name.mp)
|
item["name".mp] = file.name.mp
|
||||||
item.put("data".mp, file.data.mp)
|
item["data".mp] = file.data.mp
|
||||||
item.put("type".mp, file.type.mp)
|
item["type".mp] = file.type.mp
|
||||||
item.put("disposition".mp, file.disposition.name.mp)
|
item["disposition".mp] = file.disposition.name.mp
|
||||||
items.add(item)
|
items.add(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!parents.isEmpty()) {
|
if (!parents.isEmpty()) {
|
||||||
val items = MPArray<MPBinary>()
|
val items = MPArray<MPBinary>()
|
||||||
result.put("parents".mp, items)
|
result["parents".mp] = items
|
||||||
for ((hash) in parents) {
|
for ((hash) in parents) {
|
||||||
items.add(mp(*hash))
|
items.add(mp(*hash))
|
||||||
}
|
}
|
||||||
@ -179,6 +179,6 @@ data class Message constructor(
|
|||||||
companion object {
|
companion object {
|
||||||
private val LOG = LoggerFactory.getLogger(Message::class.java)
|
private val LOG = LoggerFactory.getLogger(Message::class.java)
|
||||||
|
|
||||||
val TYPE = "message"
|
const val TYPE = "message"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,16 @@ interface Cryptography {
|
|||||||
fun doProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long,
|
fun doProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long,
|
||||||
extraBytes: Long, callback: ProofOfWorkEngine.Callback)
|
extraBytes: Long, callback: ProofOfWorkEngine.Callback)
|
||||||
|
|
||||||
|
@JvmSynthetic
|
||||||
|
fun doProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long,
|
||||||
|
extraBytes: Long, callback: (ByteArray, ByteArray) -> Unit) {
|
||||||
|
doProofOfWork(objectMessage, nonceTrialsPerByte, extraBytes, object : ProofOfWorkEngine.Callback {
|
||||||
|
override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) {
|
||||||
|
callback.invoke(initialHash, nonce)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param objectMessage to be checked
|
* @param objectMessage to be checked
|
||||||
* *
|
* *
|
||||||
|
@ -23,16 +23,32 @@ interface ProofOfWorkEngine {
|
|||||||
/**
|
/**
|
||||||
* Returns a nonce, such that the first 8 bytes from sha512(sha512(nonce||initialHash)) represent a unsigned long
|
* Returns a nonce, such that the first 8 bytes from sha512(sha512(nonce||initialHash)) represent a unsigned long
|
||||||
* smaller than target.
|
* smaller than target.
|
||||||
|
*
|
||||||
* @param initialHash the SHA-512 hash of the object to send, sans nonce
|
* @param initialHash the SHA-512 hash of the object to send, sans nonce
|
||||||
* *
|
|
||||||
* @param target the target, representing an unsigned long
|
* @param target the target, representing an unsigned long
|
||||||
* *
|
* @param callback called with the initial hash and the calculated nonce as argument. The ProofOfWorkEngine
|
||||||
* @param callback called with the calculated nonce as argument. The ProofOfWorkEngine implementation must make
|
* implementation must make sure this is only called once.
|
||||||
* * sure this is only called once.
|
|
||||||
*/
|
*/
|
||||||
fun calculateNonce(initialHash: ByteArray, target: ByteArray, callback: Callback)
|
fun calculateNonce(initialHash: ByteArray, target: ByteArray, callback: Callback)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a nonce, such that the first 8 bytes from sha512(sha512(nonce||initialHash)) represent a unsigned long
|
||||||
|
* smaller than target.
|
||||||
|
*
|
||||||
|
* @param initialHash the SHA-512 hash of the object to send, sans nonce
|
||||||
|
* @param target the target, representing an unsigned long
|
||||||
|
* @param callback called with the initial hash and the calculated nonce as argument. The ProofOfWorkEngine
|
||||||
|
* implementation must make sure this is only called once.
|
||||||
|
*/
|
||||||
|
@JvmSynthetic
|
||||||
|
fun calculateNonce(initialHash: ByteArray, target: ByteArray, callback: (ByteArray, ByteArray) -> Unit) {
|
||||||
|
calculateNonce(initialHash, target, object : Callback {
|
||||||
|
override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) {
|
||||||
|
callback.invoke(initialHash, nonce)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
/**
|
/**
|
||||||
* @param nonce 8 bytes nonce
|
* @param nonce 8 bytes nonce
|
||||||
|
@ -126,7 +126,7 @@ class BitmessageContextTest {
|
|||||||
ctx.addContact(contact)
|
ctx.addContact(contact)
|
||||||
|
|
||||||
verify(ctx.addresses, timeout(1000).atLeastOnce()).save(eq(contact))
|
verify(ctx.addresses, timeout(1000).atLeastOnce()).save(eq(contact))
|
||||||
verify(testPowEngine, timeout(1000)).calculateNonce(any(), any(), any())
|
verify(testPowEngine, timeout(1000)).calculateNonce(any(), any(), any<ProofOfWorkEngine.Callback>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -139,7 +139,7 @@ class BitmessageContextTest {
|
|||||||
ctx.addContact(contact)
|
ctx.addContact(contact)
|
||||||
|
|
||||||
verify(ctx.addresses, times(1)).save(contact)
|
verify(ctx.addresses, times(1)).save(contact)
|
||||||
verify(testPowEngine, never()).calculateNonce(any(), any(), any())
|
verify(testPowEngine, never()).calculateNonce(any(), any(), any<ProofOfWorkEngine.Callback>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -162,7 +162,7 @@ class BitmessageContextTest {
|
|||||||
ctx.addContact(contact)
|
ctx.addContact(contact)
|
||||||
|
|
||||||
verify(ctx.addresses, atLeastOnce()).save(contact)
|
verify(ctx.addresses, atLeastOnce()).save(contact)
|
||||||
verify(testPowEngine, never()).calculateNonce(any(), any(), any())
|
verify(testPowEngine, never()).calculateNonce(any(), any(), any<ProofOfWorkEngine.Callback>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -186,7 +186,7 @@ class BitmessageContextTest {
|
|||||||
ctx.addContact(contact)
|
ctx.addContact(contact)
|
||||||
|
|
||||||
verify(ctx.addresses, atLeastOnce()).save(any())
|
verify(ctx.addresses, atLeastOnce()).save(any())
|
||||||
verify(testPowEngine, never()).calculateNonce(any(), any(), any())
|
verify(testPowEngine, never()).calculateNonce(any(), any(), any<ProofOfWorkEngine.Callback>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -245,7 +245,7 @@ class BitmessageContextTest {
|
|||||||
"Subject", "Message")
|
"Subject", "Message")
|
||||||
verify(ctx.internals.proofOfWorkRepository, timeout(1000).atLeastOnce())
|
verify(ctx.internals.proofOfWorkRepository, timeout(1000).atLeastOnce())
|
||||||
.putObject(argThat { payload.type == ObjectType.BROADCAST }, eq(1000L), eq(1000L))
|
.putObject(argThat { payload.type == ObjectType.BROADCAST }, eq(1000L), eq(1000L))
|
||||||
verify(testPowEngine).calculateNonce(any(), any(), any())
|
verify(testPowEngine).calculateNonce(any(), any(), any<ProofOfWorkEngine.Callback>())
|
||||||
verify(ctx.messages, timeout(10000).atLeastOnce()).save(argThat<Plaintext> { type == Type.BROADCAST })
|
verify(ctx.messages, timeout(10000).atLeastOnce()).save(argThat<Plaintext> { type == Type.BROADCAST })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import ch.dissem.bitmessage.entity.Plaintext.Type.MSG
|
|||||||
import ch.dissem.bitmessage.entity.payload.GenericPayload
|
import ch.dissem.bitmessage.entity.payload.GenericPayload
|
||||||
import ch.dissem.bitmessage.entity.payload.Msg
|
import ch.dissem.bitmessage.entity.payload.Msg
|
||||||
import ch.dissem.bitmessage.ports.Cryptography
|
import ch.dissem.bitmessage.ports.Cryptography
|
||||||
|
import ch.dissem.bitmessage.ports.ProofOfWorkEngine
|
||||||
import ch.dissem.bitmessage.ports.ProofOfWorkRepository
|
import ch.dissem.bitmessage.ports.ProofOfWorkRepository
|
||||||
import ch.dissem.bitmessage.utils.Singleton
|
import ch.dissem.bitmessage.utils.Singleton
|
||||||
import ch.dissem.bitmessage.utils.TestUtils
|
import ch.dissem.bitmessage.utils.TestUtils
|
||||||
@ -65,11 +66,11 @@ class ProofOfWorkServiceTest {
|
|||||||
fun `ensure missing proof of work is done`() {
|
fun `ensure missing proof of work is done`() {
|
||||||
whenever(ctx.proofOfWorkRepository.getItems()).thenReturn(Arrays.asList<ByteArray>(ByteArray(64)))
|
whenever(ctx.proofOfWorkRepository.getItems()).thenReturn(Arrays.asList<ByteArray>(ByteArray(64)))
|
||||||
whenever(ctx.proofOfWorkRepository.getItem(any())).thenReturn(ProofOfWorkRepository.Item(obj, 1001, 1002))
|
whenever(ctx.proofOfWorkRepository.getItem(any())).thenReturn(ProofOfWorkRepository.Item(obj, 1001, 1002))
|
||||||
doNothing().whenever(cryptography).doProofOfWork(any(), any(), any(), any())
|
doNothing().whenever(cryptography).doProofOfWork(any(), any(), any(), any<ProofOfWorkEngine.Callback>())
|
||||||
|
|
||||||
ctx.proofOfWorkService.doMissingProofOfWork(10)
|
ctx.proofOfWorkService.doMissingProofOfWork(10)
|
||||||
|
|
||||||
verify(cryptography, timeout(1000)).doProofOfWork(eq(obj), eq(1001L), eq(1002L), any())
|
verify(cryptography, timeout(1000)).doProofOfWork(eq(obj), eq(1001L), eq(1002L), any<ProofOfWorkEngine.Callback>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -89,12 +89,7 @@ class CryptographyTest {
|
|||||||
stream = 1
|
stream = 1
|
||||||
)
|
)
|
||||||
val waiter = CallbackWaiter<ByteArray>()
|
val waiter = CallbackWaiter<ByteArray>()
|
||||||
crypto.doProofOfWork(objectMessage, 1000, 1000,
|
crypto.doProofOfWork(objectMessage, 1000, 1000) { _, nonce -> waiter.setValue(nonce) }
|
||||||
object : ProofOfWorkEngine.Callback {
|
|
||||||
override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) {
|
|
||||||
waiter.setValue(nonce)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
objectMessage.nonce = waiter.waitForValue()
|
objectMessage.nonce = waiter.waitForValue()
|
||||||
try {
|
try {
|
||||||
crypto.checkProofOfWork(objectMessage, 1000, 1000)
|
crypto.checkProofOfWork(objectMessage, 1000, 1000)
|
||||||
|
@ -42,19 +42,21 @@ import java.io.OutputStream
|
|||||||
*/
|
*/
|
||||||
class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
||||||
|
|
||||||
private val dataReader: Reader<T>?
|
private val dataReader: (BitmessageAddress, InputStream) -> T
|
||||||
private var container: CryptoBox? = null
|
private var container: CryptoBox? = null
|
||||||
var sender: BitmessageAddress? = null
|
var sender: BitmessageAddress? = null
|
||||||
private set
|
private set
|
||||||
private var data: T? = null
|
private var data: T? = null
|
||||||
private set
|
|
||||||
|
|
||||||
constructor(data: T) : super(COMMAND, null) {
|
constructor(data: T) : super(COMMAND, null) {
|
||||||
this.data = data
|
this.data = data
|
||||||
this.dataReader = null
|
this.dataReader = { _, _ -> data }
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor(container: CryptoBox, dataReader: Reader<T>) : super(COMMAND, null) {
|
private constructor(container: CryptoBox, dataReader: (BitmessageAddress, InputStream) -> T) : super(
|
||||||
|
COMMAND,
|
||||||
|
null
|
||||||
|
) {
|
||||||
this.container = container
|
this.container = container
|
||||||
this.dataReader = dataReader
|
this.dataReader = dataReader
|
||||||
}
|
}
|
||||||
@ -81,8 +83,9 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
|
|
||||||
@Throws(DecryptionFailedException::class)
|
@Throws(DecryptionFailedException::class)
|
||||||
fun decrypt(privateKey: ByteArray): T {
|
fun decrypt(privateKey: ByteArray): T {
|
||||||
val input = SignatureCheckingInputStream(container?.decrypt(privateKey) ?: throw IllegalStateException("no encrypted data available"))
|
val input = SignatureCheckingInputStream(
|
||||||
if (dataReader == null) throw IllegalStateException("no data reader available")
|
container?.decrypt(privateKey) ?: throw IllegalStateException("no encrypted data available")
|
||||||
|
)
|
||||||
|
|
||||||
val addressVersion = varInt(input)
|
val addressVersion = varInt(input)
|
||||||
val stream = varInt(input)
|
val stream = varInt(input)
|
||||||
@ -92,7 +95,8 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
val nonceTrialsPerByte = if (addressVersion >= 3) varInt(input) else 0
|
val nonceTrialsPerByte = if (addressVersion >= 3) varInt(input) else 0
|
||||||
val extraBytes = if (addressVersion >= 3) varInt(input) else 0
|
val extraBytes = if (addressVersion >= 3) varInt(input) else 0
|
||||||
|
|
||||||
val sender = BitmessageAddress(Factory.createPubkey(
|
val sender = BitmessageAddress(
|
||||||
|
Factory.createPubkey(
|
||||||
addressVersion,
|
addressVersion,
|
||||||
stream,
|
stream,
|
||||||
publicSigningKey,
|
publicSigningKey,
|
||||||
@ -100,10 +104,11 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
nonceTrialsPerByte,
|
nonceTrialsPerByte,
|
||||||
extraBytes,
|
extraBytes,
|
||||||
behaviorBitfield
|
behaviorBitfield
|
||||||
))
|
)
|
||||||
|
)
|
||||||
this.sender = sender
|
this.sender = sender
|
||||||
|
|
||||||
data = dataReader.read(sender, input)
|
data = dataReader.invoke(sender, input)
|
||||||
|
|
||||||
input.checkSignature(sender.pubkey!!)
|
input.checkSignature(sender.pubkey!!)
|
||||||
|
|
||||||
@ -127,7 +132,8 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
fun read(sender: BitmessageAddress, input: InputStream): T
|
fun read(sender: BitmessageAddress, input: InputStream): T
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class SignatureCheckingInputStream internal constructor(private val wrapped: InputStream) : InputStream() {
|
private inner class SignatureCheckingInputStream internal constructor(private val wrapped: InputStream) :
|
||||||
|
InputStream() {
|
||||||
private val out = ByteArrayOutputStream()
|
private val out = ByteArrayOutputStream()
|
||||||
|
|
||||||
override fun read(): Int {
|
override fun read(): Int {
|
||||||
@ -145,13 +151,24 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
const val COMMAND = "ENCRYPTED"
|
||||||
val COMMAND = "ENCRYPTED"
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun <T : Streamable> read(data: CustomMessage, dataReader: Reader<T>): CryptoCustomMessage<T> {
|
fun <T : Streamable> read(data: CustomMessage, dataReader: Reader<T>): CryptoCustomMessage<T> =
|
||||||
val cryptoBox = CryptoBox.read(ByteArrayInputStream(data.getData()), data.getData().size)
|
CryptoCustomMessage(
|
||||||
return CryptoCustomMessage(cryptoBox, dataReader)
|
CryptoBox.read(ByteArrayInputStream(data.getData()), data.getData().size)
|
||||||
|
) { address, input ->
|
||||||
|
dataReader.read(address, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmSynthetic
|
||||||
|
fun <T : Streamable> read(
|
||||||
|
data: CustomMessage,
|
||||||
|
dataReader: (BitmessageAddress, InputStream) -> T
|
||||||
|
): CryptoCustomMessage<T> =
|
||||||
|
CryptoCustomMessage(
|
||||||
|
CryptoBox.read(ByteArrayInputStream(data.getData()), data.getData().size),
|
||||||
|
dataReader
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user