mirror of
https://github.com/corda/corda.git
synced 2025-06-11 20:01:46 +00:00
Deprecate existing timestamp infrastructure
This commit is contained in:
@ -403,7 +403,10 @@ class Obligation<P> : Contract {
|
|||||||
if (input is State<P>) {
|
if (input is State<P>) {
|
||||||
val actualOutput = outputs[stateIdx]
|
val actualOutput = outputs[stateIdx]
|
||||||
val deadline = input.dueBefore
|
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)
|
val expectedOutput = input.copy(lifecycle = expectedOutputLifecycle)
|
||||||
|
|
||||||
requireThat {
|
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()
|
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. */
|
/** 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? {
|
fun List<AuthenticatedObject<CommandData>>.getTimestampBy(timestampingAuthority: Party): TimestampCommand? {
|
||||||
val timestampCmds = filter { it.signers.contains(timestampingAuthority.owningKey) && it.value is TimestampCommand }
|
val timestampCmds = filter { it.signers.contains(timestampingAuthority.owningKey) && it.value is TimestampCommand }
|
||||||
return timestampCmds.singleOrNull()?.value as? TimestampCommand
|
return timestampCmds.singleOrNull()?.value as? TimestampCommand
|
||||||
|
@ -337,13 +337,30 @@ data class AuthenticatedObject<out T : Any>(
|
|||||||
val value: T
|
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
|
* 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).
|
* 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
|
@Deprecated("timestamps are now a field on a transaction, and this exists just for legacy reasons.")
|
||||||
// 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
|
|
||||||
data class TimestampCommand(val after: Instant?, val before: Instant?) : CommandData {
|
data class TimestampCommand(val after: Instant?, val before: Instant?) : CommandData {
|
||||||
init {
|
init {
|
||||||
if (after == null && before == null)
|
if (after == null && before == null)
|
||||||
|
@ -27,8 +27,10 @@ open class TransactionBuilder(
|
|||||||
protected val attachments: MutableList<SecureHash> = arrayListOf(),
|
protected val attachments: MutableList<SecureHash> = arrayListOf(),
|
||||||
protected val outputs: MutableList<TransactionState<ContractState>> = arrayListOf(),
|
protected val outputs: MutableList<TransactionState<ContractState>> = arrayListOf(),
|
||||||
protected val commands: MutableList<Command> = 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()
|
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
|
* collaborating parties may therefore require a higher time tolerance than a transaction being built by a single
|
||||||
* node.
|
* node.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("use setTime(Instant, Duration) instead")
|
||||||
fun setTime(time: Instant, authority: Party, timeTolerance: Duration) {
|
fun setTime(time: Instant, authority: Party, timeTolerance: Duration) {
|
||||||
check(currentSigs.isEmpty()) { "Cannot change timestamp after signing" }
|
check(currentSigs.isEmpty()) { "Cannot change timestamp after signing" }
|
||||||
commands.removeAll { it.value is TimestampCommand }
|
commands.removeAll { it.value is TimestampCommand }
|
||||||
addCommand(TimestampCommand(time, timeTolerance), authority.owningKey)
|
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 */
|
/** 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 {
|
fun withItems(vararg items: Any): TransactionBuilder {
|
||||||
for (t in items) {
|
for (t in items) {
|
||||||
@ -115,7 +135,7 @@ open class TransactionBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun toWireTransaction() = WireTransaction(ArrayList(inputs), ArrayList(attachments),
|
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 {
|
fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction {
|
||||||
if (checkSufficientSignatures) {
|
if (checkSufficientSignatures) {
|
||||||
|
@ -23,7 +23,7 @@ fun WireTransaction.toLedgerTransaction(services: ServiceHub): LedgerTransaction
|
|||||||
services.storageService.attachments.openAttachment(it) ?: throw FileNotFoundException(it.toString())
|
services.storageService.attachments.openAttachment(it) ?: throw FileNotFoundException(it.toString())
|
||||||
}
|
}
|
||||||
val resolvedInputs = inputs.map { StateAndRef(services.loadState(it), it) }
|
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 attachments: List<Attachment>,
|
||||||
val commands: List<AuthenticatedObject<CommandData>>,
|
val commands: List<AuthenticatedObject<CommandData>>,
|
||||||
val origHash: SecureHash,
|
val origHash: SecureHash,
|
||||||
val inputNotary: Party? = null) {
|
val inputNotary: Party? = null,
|
||||||
|
val timestamp: Timestamp? = null) {
|
||||||
override fun hashCode() = origHash.hashCode()
|
override fun hashCode() = origHash.hashCode()
|
||||||
override fun equals(other: Any?) = other is TransactionForContract && other.origHash == origHash
|
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)
|
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. */
|
/** 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)
|
fun getTimestampBy(timestampingAuthority: Party): TimestampCommand? = commands.getTimestampBy(timestampingAuthority)
|
||||||
|
|
||||||
/** Simply calls [commands.getTimestampByName] as a shortcut to make code completion more intuitive. */
|
/** 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 outputs: List<TransactionState<ContractState>>,
|
||||||
val commands: List<Command>,
|
val commands: List<Command>,
|
||||||
val signers: List<PublicKey>,
|
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.
|
// 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
|
@Volatile @Transient private var cachedBits: SerializedBytes<WireTransaction>? = null
|
||||||
@ -165,7 +166,8 @@ data class LedgerTransaction(
|
|||||||
override val id: SecureHash,
|
override val id: SecureHash,
|
||||||
/** The notary key and the command keys together: a signed transaction must provide signatures for all of these. */
|
/** The notary key and the command keys together: a signed transaction must provide signatures for all of these. */
|
||||||
val signers: List<PublicKey>,
|
val signers: List<PublicKey>,
|
||||||
val type: TransactionType
|
val type: TransactionType,
|
||||||
|
val timestamp: Timestamp? = null
|
||||||
) : NamedByHash {
|
) : NamedByHash {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T : ContractState> outRef(index: Int) = StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
|
fun <T : ContractState> outRef(index: Int) = StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
|
||||||
|
Reference in New Issue
Block a user