mirror of
https://github.com/corda/corda.git
synced 2025-02-20 17:33:15 +00:00
Deprecate existing timestamp infrastructure
This commit is contained in:
parent
8c7de8a69c
commit
f0aa5a30d4
@ -403,7 +403,10 @@ class Obligation<P> : Contract {
|
||||
if (input is State<P>) {
|
||||
val actualOutput = outputs[stateIdx]
|
||||
val deadline = input.dueBefore
|
||||
val timestamp: TimestampCommand? = tx.timestamp
|
||||
val timestamp: TimestampCommand? = if (tx.inputNotary == null)
|
||||
null
|
||||
else
|
||||
tx.getTimestampBy(tx.inputNotary!!)
|
||||
val expectedOutput = input.copy(lifecycle = expectedOutputLifecycle)
|
||||
|
||||
requireThat {
|
||||
|
@ -85,6 +85,7 @@ fun <C : CommandData> Collection<AuthenticatedObject<CommandData>>.requireSingle
|
||||
mapNotNull { @Suppress("UNCHECKED_CAST") if (klass.isInstance(it.value)) it as AuthenticatedObject<C> else null }.single()
|
||||
|
||||
/** Returns a timestamp that was signed by the given authority, or returns null if missing. */
|
||||
@Deprecated("Get timestamp from the transaction")
|
||||
fun List<AuthenticatedObject<CommandData>>.getTimestampBy(timestampingAuthority: Party): TimestampCommand? {
|
||||
val timestampCmds = filter { it.signers.contains(timestampingAuthority.owningKey) && it.value is TimestampCommand }
|
||||
return timestampCmds.singleOrNull()?.value as? TimestampCommand
|
||||
|
@ -337,13 +337,30 @@ data class AuthenticatedObject<out T : Any>(
|
||||
val value: T
|
||||
)
|
||||
|
||||
/**
|
||||
* If present in a transaction, contains a time that was verified by the uniqueness service. The true time must be
|
||||
* between (after, before).
|
||||
*/
|
||||
data class Timestamp(val after: Instant?, val before: Instant?) {
|
||||
init {
|
||||
if (after == null && before == null)
|
||||
throw IllegalArgumentException("At least one of before/after must be specified")
|
||||
if (after != null && before != null)
|
||||
check(after <= before)
|
||||
}
|
||||
|
||||
constructor(time: Instant, tolerance: Duration) : this(time - tolerance, time + tolerance)
|
||||
|
||||
val midpoint: Instant get() = after!! + Duration.between(after, before!!).dividedBy(2)
|
||||
}
|
||||
|
||||
/**
|
||||
* If present in a transaction, contains a time that was verified by the timestamping authority/authorities whose
|
||||
* public keys are identified in the containing [Command] object. The true time must be between (after, before).
|
||||
*
|
||||
* @deprecated timestamps are now a field on a transaction, and this exists just for legacy reasons.
|
||||
*/
|
||||
// TODO: Timestamps are now always provided by the consensus service for the transaction, rather than potentially
|
||||
// having multiple timestamps on a transaction. As such, it likely makes more sense for time to be a field on the
|
||||
// transaction, rather than a command
|
||||
@Deprecated("timestamps are now a field on a transaction, and this exists just for legacy reasons.")
|
||||
data class TimestampCommand(val after: Instant?, val before: Instant?) : CommandData {
|
||||
init {
|
||||
if (after == null && before == null)
|
||||
|
@ -27,8 +27,10 @@ open class TransactionBuilder(
|
||||
protected val attachments: MutableList<SecureHash> = arrayListOf(),
|
||||
protected val outputs: MutableList<TransactionState<ContractState>> = arrayListOf(),
|
||||
protected val commands: MutableList<Command> = arrayListOf(),
|
||||
protected val signers: MutableSet<PublicKey> = mutableSetOf()) {
|
||||
protected val signers: MutableSet<PublicKey> = mutableSetOf(),
|
||||
protected var timestamp: Timestamp? = null) {
|
||||
|
||||
@Deprecated("use timestamp instead")
|
||||
val time: TimestampCommand? get() = commands.mapNotNull { it.value as? TimestampCommand }.singleOrNull()
|
||||
|
||||
/**
|
||||
@ -57,12 +59,30 @@ open class TransactionBuilder(
|
||||
* collaborating parties may therefore require a higher time tolerance than a transaction being built by a single
|
||||
* node.
|
||||
*/
|
||||
@Deprecated("use setTime(Instant, Duration) instead")
|
||||
fun setTime(time: Instant, authority: Party, timeTolerance: Duration) {
|
||||
check(currentSigs.isEmpty()) { "Cannot change timestamp after signing" }
|
||||
commands.removeAll { it.value is TimestampCommand }
|
||||
addCommand(TimestampCommand(time, timeTolerance), authority.owningKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Places a [TimestampCommand] in this transaction, removing any existing command if there is one.
|
||||
* The command requires a signature from the Notary service, which acts as a Timestamp Authority.
|
||||
* The signature can be obtained using [NotaryProtocol].
|
||||
*
|
||||
* The window of time in which the final timestamp may lie is defined as [time] +/- [timeTolerance].
|
||||
* If you want a non-symmetrical time window you must add the command via [addCommand] yourself. The tolerance
|
||||
* should be chosen such that your code can finish building the transaction and sending it to the TSA within that
|
||||
* window of time, taking into account factors such as network latency. Transactions being built by a group of
|
||||
* collaborating parties may therefore require a higher time tolerance than a transaction being built by a single
|
||||
* node.
|
||||
*/
|
||||
fun setTime(time: Instant, timeTolerance: Duration) {
|
||||
check(currentSigs.isEmpty()) { "Cannot change timestamp after signing" }
|
||||
timestamp = Timestamp(time, timeTolerance)
|
||||
}
|
||||
|
||||
/** A more convenient way to add items to this transaction that calls the add* methods for you based on type */
|
||||
fun withItems(vararg items: Any): TransactionBuilder {
|
||||
for (t in items) {
|
||||
@ -115,7 +135,7 @@ open class TransactionBuilder(
|
||||
}
|
||||
|
||||
fun toWireTransaction() = WireTransaction(ArrayList(inputs), ArrayList(attachments),
|
||||
ArrayList(outputs), ArrayList(commands), signers.toList(), type)
|
||||
ArrayList(outputs), ArrayList(commands), signers.toList(), type, timestamp)
|
||||
|
||||
fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction {
|
||||
if (checkSufficientSignatures) {
|
||||
|
@ -23,7 +23,7 @@ fun WireTransaction.toLedgerTransaction(services: ServiceHub): LedgerTransaction
|
||||
services.storageService.attachments.openAttachment(it) ?: throw FileNotFoundException(it.toString())
|
||||
}
|
||||
val resolvedInputs = inputs.map { StateAndRef(services.loadState(it), it) }
|
||||
return LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, signers, type)
|
||||
return LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, signers, type, timestamp)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,8 @@ data class TransactionForContract(val inputs: List<ContractState>,
|
||||
val attachments: List<Attachment>,
|
||||
val commands: List<AuthenticatedObject<CommandData>>,
|
||||
val origHash: SecureHash,
|
||||
val inputNotary: Party? = null) {
|
||||
val inputNotary: Party? = null,
|
||||
val timestamp: Timestamp? = null) {
|
||||
override fun hashCode() = origHash.hashCode()
|
||||
override fun equals(other: Any?) = other is TransactionForContract && other.origHash == origHash
|
||||
|
||||
@ -83,11 +84,8 @@ data class TransactionForContract(val inputs: List<ContractState>,
|
||||
*/
|
||||
data class InOutGroup<out T : ContractState, out K : Any>(val inputs: List<T>, val outputs: List<T>, val groupingKey: K)
|
||||
|
||||
/** Get the timestamp command for this transaction, using the notary from the input states. */
|
||||
val timestamp: TimestampCommand?
|
||||
get() = if (inputNotary == null) null else commands.getTimestampBy(inputNotary)
|
||||
|
||||
/** Simply calls [commands.getTimestampBy] as a shortcut to make code completion more intuitive. */
|
||||
@Deprecated("use timestamp property instead")
|
||||
fun getTimestampBy(timestampingAuthority: Party): TimestampCommand? = commands.getTimestampBy(timestampingAuthority)
|
||||
|
||||
/** Simply calls [commands.getTimestampByName] as a shortcut to make code completion more intuitive. */
|
||||
|
@ -49,7 +49,8 @@ data class WireTransaction(val inputs: List<StateRef>,
|
||||
val outputs: List<TransactionState<ContractState>>,
|
||||
val commands: List<Command>,
|
||||
val signers: List<PublicKey>,
|
||||
val type: TransactionType) : NamedByHash {
|
||||
val type: TransactionType,
|
||||
val timestamp: Timestamp? = null) : NamedByHash {
|
||||
|
||||
// Cache the serialised form of the transaction and its hash to give us fast access to it.
|
||||
@Volatile @Transient private var cachedBits: SerializedBytes<WireTransaction>? = null
|
||||
@ -165,7 +166,8 @@ data class LedgerTransaction(
|
||||
override val id: SecureHash,
|
||||
/** The notary key and the command keys together: a signed transaction must provide signatures for all of these. */
|
||||
val signers: List<PublicKey>,
|
||||
val type: TransactionType
|
||||
val type: TransactionType,
|
||||
val timestamp: Timestamp? = null
|
||||
) : NamedByHash {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : ContractState> outRef(index: Int) = StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
|
||||
|
Loading…
x
Reference in New Issue
Block a user