Minor: more code motion ... TimestampingProtocol now split to top level class and moved to same location as the other protocols. Few other timestamping related classes reorganised.

This commit is contained in:
Mike Hearn 2016-03-08 12:17:07 +01:00
parent 2c4475b0d9
commit dc6ef73b6b
5 changed files with 81 additions and 60 deletions

View File

@ -21,7 +21,7 @@ import core.messaging.SingleMessageRecipient
import core.node.services.ArtemisMessagingService
import core.node.services.NodeAttachmentStorage
import core.node.services.NodeWalletService
import core.node.services.TimestampingProtocol
import protocols.TimestampingProtocol
import core.protocols.ProtocolLogic
import core.serialization.deserialize
import core.utilities.ANSIProgressRenderer

View File

@ -9,29 +9,22 @@
package core.node.services
import co.paralleluniverse.common.util.VisibleForTesting
import co.paralleluniverse.fibers.Suspendable
import core.*
import core.Party
import core.TimestampCommand
import core.crypto.DigitalSignature
import core.crypto.signWithECDSA
import core.messaging.LegallyIdentifiableNode
import core.messaging.MessageRecipients
import core.messaging.MessagingService
import core.messaging.StateMachineManager
import core.protocols.ProtocolLogic
import core.serialization.SerializedBytes
import core.seconds
import core.serialization.deserialize
import core.serialization.serialize
import core.until
import org.slf4j.LoggerFactory
import protocols.TimestampingProtocol
import java.security.KeyPair
import java.time.Clock
import java.time.Duration
import javax.annotation.concurrent.ThreadSafe
class TimestampingMessages {
// TODO: Improve the messaging api to have a notion of sender+replyTo topic (optional?)
data class Request(val tx: SerializedBytes<WireTransaction>, val replyTo: MessageRecipients, val replyToTopic: String)
}
/**
* This class implements the server side of the timestamping protocol, using the local clock. A future version might
* add features like checking against other NTP servers to make sure the clock hasn't drifted by too much.
@ -54,7 +47,7 @@ class NodeTimestamperService(private val net: MessagingService,
require(identity.owningKey == signingKey.public)
net.addMessageHandler(TIMESTAMPING_PROTOCOL_TOPIC + ".0", null) { message, r ->
try {
val req = message.data.deserialize<TimestampingMessages.Request>()
val req = message.data.deserialize<TimestampingProtocol.Request>()
val signature = processRequest(req)
val msg = net.createMessage(req.replyToTopic, signature.serialize().bits)
net.send(msg, req.replyTo)
@ -67,7 +60,7 @@ class NodeTimestamperService(private val net: MessagingService,
}
@VisibleForTesting
fun processRequest(req: TimestampingMessages.Request): DigitalSignature.LegallyIdentifiable {
fun processRequest(req: TimestampingProtocol.Request): DigitalSignature.LegallyIdentifiable {
// We don't bother verifying signatures anything about the transaction here: we simply don't need to see anything
// except the relevant command, and a future privacy upgrade should ensure we only get a torn-off command
// rather than the full transaction.
@ -96,41 +89,3 @@ class NodeTimestamperService(private val net: MessagingService,
}
}
/**
* The TimestampingProtocol class is the client code that talks to a [NodeTimestamperService] on some remote node. It is a
* [ProtocolLogic], meaning it can either be a sub-protocol of some other protocol, or be driven independently.
*
* If you are not yourself authoring a protocol and want to timestamp something, the [TimestampingProtocol.Client] class
* implements the [TimestamperService] interface, meaning it can be passed to [TransactionBuilder.timestamp] to timestamp
* the built transaction. Please be aware that this will block, meaning it should not be used on a thread that is handling
* a network message: use it only from spare application threads that don't have to respond to anything.
*/
class TimestampingProtocol(private val node: LegallyIdentifiableNode,
private val wtxBytes: SerializedBytes<WireTransaction>) : ProtocolLogic<DigitalSignature.LegallyIdentifiable>() {
class Client(private val stateMachineManager: StateMachineManager, private val node: LegallyIdentifiableNode) : TimestamperService {
override val identity: Party = node.identity
override fun timestamp(wtxBytes: SerializedBytes<WireTransaction>): DigitalSignature.LegallyIdentifiable {
return stateMachineManager.add("platform.timestamping", TimestampingProtocol(node, wtxBytes)).get()
}
}
@Suspendable
override fun call(): DigitalSignature.LegallyIdentifiable {
val sessionID = random63BitValue()
val replyTopic = "${NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC}.$sessionID"
val req = TimestampingMessages.Request(wtxBytes, serviceHub.networkService.myAddress, replyTopic)
val maybeSignature = sendAndReceive<DigitalSignature.LegallyIdentifiable>(
NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC, node.address, 0, sessionID, req)
// Check that the timestamping authority gave us back a valid signature and didn't break somehow
maybeSignature.validate { sig ->
sig.verifyWithECDSA(wtxBytes)
return sig
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2015 Distributed Ledger Group LLC. Distributed as Licensed Company IP to DLG Group Members
* pursuant to the August 7, 2015 Advisory Services Agreement and subject to the Company IP License terms
* set forth therein.
*
* All other rights reserved.
*/
package protocols
import co.paralleluniverse.fibers.Suspendable
import core.Party
import core.WireTransaction
import core.crypto.DigitalSignature
import core.messaging.LegallyIdentifiableNode
import core.messaging.MessageRecipients
import core.messaging.StateMachineManager
import core.node.services.NodeTimestamperService
import core.node.services.TimestamperService
import core.protocols.ProtocolLogic
import core.random63BitValue
import core.serialization.SerializedBytes
/**
* The TimestampingProtocol class is the client code that talks to a [NodeTimestamperService] on some remote node. It is a
* [ProtocolLogic], meaning it can either be a sub-protocol of some other protocol, or be driven independently.
*
* If you are not yourself authoring a protocol and want to timestamp something, the [TimestampingProtocol.Client] class
* implements the [TimestamperService] interface, meaning it can be passed to [TransactionBuilder.timestamp] to timestamp
* the built transaction. Please be aware that this will block, meaning it should not be used on a thread that is handling
* a network message: use it only from spare application threads that don't have to respond to anything.
*/
class TimestampingProtocol(private val node: LegallyIdentifiableNode,
private val wtxBytes: SerializedBytes<WireTransaction>) : ProtocolLogic<DigitalSignature.LegallyIdentifiable>() {
class Client(private val stateMachineManager: StateMachineManager, private val node: LegallyIdentifiableNode) : TimestamperService {
override val identity: Party = node.identity
override fun timestamp(wtxBytes: SerializedBytes<WireTransaction>): DigitalSignature.LegallyIdentifiable {
return stateMachineManager.add("platform.timestamping", TimestampingProtocol(node, wtxBytes)).get()
}
}
@Suspendable
override fun call(): DigitalSignature.LegallyIdentifiable {
val sessionID = random63BitValue()
val replyTopic = "${NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC}.$sessionID"
val req = Request(wtxBytes, serviceHub.networkService.myAddress, replyTopic)
val maybeSignature = sendAndReceive<DigitalSignature.LegallyIdentifiable>(
NodeTimestamperService.TIMESTAMPING_PROTOCOL_TOPIC, node.address, 0, sessionID, req)
// Check that the timestamping authority gave us back a valid signature and didn't break somehow
maybeSignature.validate { sig ->
sig.verifyWithECDSA(wtxBytes)
return sig
}
}
// TODO: Improve the messaging api to have a notion of sender+replyTo topic (optional?)
data class Request(val tx: SerializedBytes<WireTransaction>, val replyTo: MessageRecipients, val replyToTopic: String)
}

View File

@ -18,7 +18,7 @@ import core.crypto.signWithECDSA
import core.messaging.LegallyIdentifiableNode
import core.messaging.SingleMessageRecipient
import core.messaging.StateMachineManager
import core.node.services.TimestampingProtocol
import protocols.TimestampingProtocol
import core.protocols.ProtocolLogic
import core.utilities.ProgressTracker
import core.utilities.trace

View File

@ -12,7 +12,9 @@ import co.paralleluniverse.fibers.Suspendable
import core.*
import core.crypto.SecureHash
import core.messaging.*
import core.node.services.*
import core.node.services.NodeTimestamperService
import core.node.services.ServiceHub
import core.node.services.TimestampingError
import core.protocols.ProtocolLogic
import core.serialization.serialize
import core.testutils.ALICE
@ -21,6 +23,7 @@ import core.testutils.CASH
import core.utilities.BriefLogFormatter
import org.junit.Before
import org.junit.Test
import protocols.TimestampingProtocol
import java.security.PublicKey
import java.time.Clock
import java.time.Instant
@ -94,14 +97,14 @@ class TimestamperNodeServiceTest : TestWithInMemoryNetwork() {
// Zero commands is not OK.
assertFailsWith(TimestampingError.RequiresExactlyOneCommand::class) {
val wtx = ptx.toWireTransaction()
service.processRequest(TimestampingMessages.Request(wtx.serialize(), myMessaging.first, "ignored"))
service.processRequest(TimestampingProtocol.Request(wtx.serialize(), myMessaging.first, "ignored"))
}
// More than one command is not OK.
assertFailsWith(TimestampingError.RequiresExactlyOneCommand::class) {
ptx.addCommand(TimestampCommand(clock.instant(), 30.seconds), ALICE)
ptx.addCommand(TimestampCommand(clock.instant(), 40.seconds), ALICE)
val wtx = ptx.toWireTransaction()
service.processRequest(TimestampingMessages.Request(wtx.serialize(), myMessaging.first, "ignored"))
service.processRequest(TimestampingProtocol.Request(wtx.serialize(), myMessaging.first, "ignored"))
}
}
@ -111,7 +114,7 @@ class TimestamperNodeServiceTest : TestWithInMemoryNetwork() {
val now = clock.instant()
ptx.addCommand(TimestampCommand(now - 60.seconds, now - 40.seconds), ALICE)
val wtx = ptx.toWireTransaction()
service.processRequest(TimestampingMessages.Request(wtx.serialize(), myMessaging.first, "ignored"))
service.processRequest(TimestampingProtocol.Request(wtx.serialize(), myMessaging.first, "ignored"))
}
}
@ -121,7 +124,7 @@ class TimestamperNodeServiceTest : TestWithInMemoryNetwork() {
val now = clock.instant()
ptx.addCommand(TimestampCommand(now - 60.seconds, now - 40.seconds), ALICE)
val wtx = ptx.toWireTransaction()
service.processRequest(TimestampingMessages.Request(wtx.serialize(), myMessaging.first, "ignored"))
service.processRequest(TimestampingProtocol.Request(wtx.serialize(), myMessaging.first, "ignored"))
}
}
@ -130,7 +133,7 @@ class TimestamperNodeServiceTest : TestWithInMemoryNetwork() {
val now = clock.instant()
ptx.addCommand(TimestampCommand(now - 20.seconds, now + 20.seconds), ALICE)
val wtx = ptx.toWireTransaction()
val sig = service.processRequest(TimestampingMessages.Request(wtx.serialize(), myMessaging.first, "ignored"))
val sig = service.processRequest(TimestampingProtocol.Request(wtx.serialize(), myMessaging.first, "ignored"))
ptx.checkAndAddSignature(sig)
ptx.toSignedTransaction(false).verifySignatures()
}