mirror of
https://github.com/corda/corda.git
synced 2025-02-22 02:06:45 +00:00
Merged in mike-tx-types-refactoring-september (pull request #330)
Small cleanups to the transaction types
This commit is contained in:
commit
85c112f80d
@ -11,6 +11,7 @@ package com.r3corda.contracts.isolated
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
|
||||
// The dummy contract doesn't do anything useful. It exists for testing purposes.
|
||||
|
@ -2,7 +2,7 @@ package com.r3corda.core.node
|
||||
|
||||
import com.r3corda.core.contracts.ContractState
|
||||
import com.r3corda.core.contracts.PartyAndReference
|
||||
import com.r3corda.core.contracts.TransactionBuilder
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.crypto.Party
|
||||
|
||||
interface DummyContractBackdoor {
|
||||
|
@ -7,6 +7,7 @@ import com.r3corda.core.contracts.Timestamp;
|
||||
import com.r3corda.core.contracts.TransactionForContract.*;
|
||||
import com.r3corda.core.contracts.clauses.*;
|
||||
import com.r3corda.core.crypto.*;
|
||||
import com.r3corda.core.transactions.*;
|
||||
import kotlin.*;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
|
@ -11,6 +11,7 @@ import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.toStringShort
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
|
@ -9,6 +9,7 @@ import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.toStringShort
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
|
@ -5,6 +5,7 @@ import com.r3corda.core.contracts.clauses.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.protocols.ProtocolLogicRefFactory
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.suggestInterestRateAnnouncementTimeWindow
|
||||
import com.r3corda.protocols.TwoPartyDealProtocol
|
||||
import org.apache.commons.jexl3.JexlBuilder
|
||||
|
@ -7,6 +7,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.contracts.clauses.*
|
||||
import com.r3corda.core.crypto.*
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import java.math.BigInteger
|
||||
import java.security.PublicKey
|
||||
|
@ -11,6 +11,7 @@ import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.newSecureRandom
|
||||
import com.r3corda.core.crypto.toStringShort
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.util.*
|
||||
|
||||
|
@ -6,6 +6,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.contracts.clauses.*
|
||||
import com.r3corda.core.crypto.*
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.*
|
||||
import java.math.BigInteger
|
||||
import java.security.PublicKey
|
||||
|
@ -3,6 +3,7 @@ package com.r3corda.contracts.asset
|
||||
import com.r3corda.contracts.clause.AbstractConserveAmount
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -7,6 +7,7 @@ import com.r3corda.contracts.asset.sumFungibleOrZero
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.contracts.clauses.Clause
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.util.*
|
||||
|
||||
|
@ -6,7 +6,7 @@ import com.r3corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||
import com.r3corda.contracts.asset.DUMMY_CASH_ISSUER_KEY
|
||||
import com.r3corda.core.contracts.Amount
|
||||
import com.r3corda.core.contracts.Issued
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.contracts.TransactionType
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
|
@ -12,6 +12,9 @@ import com.r3corda.core.node.NodeInfo
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.seconds
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.ProgressTracker
|
||||
import com.r3corda.core.utilities.trace
|
||||
import java.security.KeyPair
|
||||
|
@ -7,6 +7,8 @@ import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.days
|
||||
import com.r3corda.core.seconds
|
||||
import com.r3corda.core.transactions.LedgerTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.core.utilities.DUMMY_PUBKEY_1
|
||||
|
@ -2,6 +2,7 @@ package com.r3corda.contracts
|
||||
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.seconds
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.core.utilities.TEST_TX_TIME
|
||||
|
@ -4,6 +4,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.serialization.OpaqueBytes
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_PUBKEY_1
|
||||
import com.r3corda.core.utilities.DUMMY_PUBKEY_2
|
||||
|
@ -2,6 +2,7 @@ package com.r3corda.core.contracts
|
||||
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
|
||||
// The dummy contract doesn't do anything useful. It exists for testing purposes.
|
||||
|
@ -3,7 +3,7 @@ package com.r3corda.core.contracts
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* Dummy state for use in testing. Not part of any real contract.
|
||||
* Dummy state for use in testing. Not part of any contract, not even the [DummyContract].
|
||||
*/
|
||||
data class DummyState(val magicNumber: Int = 0) : ContractState {
|
||||
override val contract = DUMMY_PROGRAM_ID
|
||||
|
@ -8,6 +8,7 @@ import com.r3corda.core.protocols.ProtocolLogicRef
|
||||
import com.r3corda.core.protocols.ProtocolLogicRefFactory
|
||||
import com.r3corda.core.serialization.OpaqueBytes
|
||||
import com.r3corda.core.serialization.serialize
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
@ -2,6 +2,8 @@ package com.r3corda.core.contracts
|
||||
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.node.services.ReadOnlyTransactionStorage
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import java.util.*
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
package com.r3corda.core.contracts
|
||||
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
// TODO: Move these into the actual classes (i.e. where people would expect to find them) and split Transactions.kt into multiple files
|
||||
|
||||
/**
|
||||
* Looks up identities and attachments from storage to generate a [LedgerTransaction]. A transaction is expected to
|
||||
* have been fully resolved using the resolution protocol by this point.
|
||||
*
|
||||
* @throws FileNotFoundException if a required attachment was not found in storage.
|
||||
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
|
||||
*/
|
||||
fun WireTransaction.toLedgerTransaction(services: ServiceHub): LedgerTransaction {
|
||||
// Look up random keys to authenticated identities. This is just a stub placeholder and will all change in future.
|
||||
val authenticatedArgs = commands.map {
|
||||
val parties = it.signers.mapNotNull { pk -> services.identityService.partyFromKey(pk) }
|
||||
AuthenticatedObject(it.signers, parties, it.value)
|
||||
}
|
||||
// Open attachments specified in this transaction. If we haven't downloaded them, we fail.
|
||||
val attachments = attachments.map {
|
||||
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, notary, signers, timestamp, type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls [verify] to check all required signatures are present, and then calls [WireTransaction.toLedgerTransaction]
|
||||
* with the passed in [ServiceHub] to resolve the dependencies, returning an unverified LedgerTransaction.
|
||||
*
|
||||
* @throws FileNotFoundException if a required attachment was not found in storage.
|
||||
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
|
||||
*/
|
||||
fun SignedTransaction.toLedgerTransaction(services: ServiceHub): LedgerTransaction {
|
||||
verifySignatures()
|
||||
return tx.toLedgerTransaction(services)
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
package com.r3corda.core.contracts
|
||||
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.noneOrSingle
|
||||
import com.r3corda.core.transactions.LedgerTransaction
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
|
||||
/** Defines transaction build & validation logic for a specific transaction type */
|
||||
|
@ -3,6 +3,7 @@ package com.r3corda.core.contracts
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.toStringShort
|
||||
import com.r3corda.core.transactions.LedgerTransaction
|
||||
import java.security.PublicKey
|
||||
import java.util.*
|
||||
|
||||
|
@ -1,217 +0,0 @@
|
||||
package com.r3corda.core.contracts
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
import com.r3corda.core.crypto.DigitalSignature
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.toStringsShort
|
||||
import com.r3corda.core.indexOfOrThrow
|
||||
import com.r3corda.core.serialization.SerializedBytes
|
||||
import com.r3corda.core.serialization.THREAD_LOCAL_KRYO
|
||||
import com.r3corda.core.serialization.deserialize
|
||||
import com.r3corda.core.serialization.serialize
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import java.security.PublicKey
|
||||
import java.security.SignatureException
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Views of a transaction as it progresses through the pipeline, from bytes loaded from disk/network to the object
|
||||
* tree passed into a contract.
|
||||
*
|
||||
* SignedTransaction wraps a serialized WireTransaction. It contains one or more signatures, each one for
|
||||
* a public key that is mentioned inside a transaction command. SignedTransaction is the top level transaction type
|
||||
* and the type most frequently passed around the network and stored. The identity of a transaction is the hash
|
||||
* of a WireTransaction, therefore if you are storing data keyed by WT hash be aware that multiple different STs may
|
||||
* map to the same key (and they could be different in important ways, like validity!). The signatures on a
|
||||
* SignedTransaction might be invalid or missing: the type does not imply validity.
|
||||
*
|
||||
* WireTransaction is a transaction in a form ready to be serialised/unserialised. A WireTransaction can be hashed
|
||||
* in various ways to calculate a *signature hash* (or sighash), this is the hash that is signed by the various involved
|
||||
* keypairs.
|
||||
*
|
||||
* LedgerTransaction is derived from WireTransaction. It is the result of doing the following operations:
|
||||
*
|
||||
* - Downloading and locally storing all the dependencies of the transaction.
|
||||
* - Resolving the input states and loading them into memory.
|
||||
* - Doing some basic key lookups on WireCommand to see if any keys are from a recognised party, thus converting the
|
||||
* WireCommand objects into AuthenticatedObject<Command>. Currently we just assume a hard coded pubkey->party map.
|
||||
* In future it'd make more sense to use a certificate scheme and so that logic would get more complex.
|
||||
* - Deserialising the output states.
|
||||
*
|
||||
* All the above refer to inputs using a (txhash, output index) pair.
|
||||
*
|
||||
* There is also TransactionForContract, which is a lightly red-acted form of LedgerTransaction that's fed into the
|
||||
* contract's verify function. It may be removed in future.
|
||||
*/
|
||||
|
||||
/** Transaction ready for serialisation, without any signatures attached. */
|
||||
data class WireTransaction(val inputs: List<StateRef>,
|
||||
val attachments: List<SecureHash>,
|
||||
val outputs: List<TransactionState<ContractState>>,
|
||||
val commands: List<Command>,
|
||||
val notary: Party?,
|
||||
val signers: List<PublicKey>,
|
||||
val type: TransactionType,
|
||||
val timestamp: Timestamp?) : 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
|
||||
val serialized: SerializedBytes<WireTransaction> get() = cachedBits ?: serialize().apply { cachedBits = this }
|
||||
override val id: SecureHash get() = serialized.hash
|
||||
|
||||
companion object {
|
||||
fun deserialize(bits: SerializedBytes<WireTransaction>, kryo: Kryo = THREAD_LOCAL_KRYO.get()): WireTransaction {
|
||||
val wtx = bits.bits.deserialize<WireTransaction>(kryo)
|
||||
wtx.cachedBits = bits
|
||||
return wtx
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a [StateAndRef] for the given output index. */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : ContractState> outRef(index: Int): StateAndRef<T> {
|
||||
require(index >= 0 && index < outputs.size)
|
||||
return StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
|
||||
}
|
||||
|
||||
/** Returns a [StateAndRef] for the requested output state, or throws [IllegalArgumentException] if not found. */
|
||||
fun <T : ContractState> outRef(state: ContractState): StateAndRef<T> = outRef(outputs.map { it.data }.indexOfOrThrow(state))
|
||||
|
||||
override fun toString(): String {
|
||||
val buf = StringBuilder()
|
||||
buf.appendln("Transaction $id:")
|
||||
for (input in inputs) buf.appendln("${Emoji.rightArrow}INPUT: $input")
|
||||
for (output in outputs) buf.appendln("${Emoji.leftArrow}OUTPUT: $output")
|
||||
for (command in commands) buf.appendln("${Emoji.diamond}COMMAND: $command")
|
||||
for (attachment in attachments) buf.appendln("${Emoji.paperclip}ATTACHMENT: $attachment")
|
||||
return buf.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/** Container for a [WireTransaction] and attached signatures. */
|
||||
data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
val sigs: List<DigitalSignature.WithKey>) : NamedByHash {
|
||||
init {
|
||||
check(sigs.isNotEmpty())
|
||||
}
|
||||
|
||||
// TODO: This needs to be reworked to ensure that the inner WireTransaction is only ever deserialised sandboxed.
|
||||
|
||||
/** Lazily calculated access to the deserialised/hashed transaction data. */
|
||||
val tx: WireTransaction by lazy { WireTransaction.deserialize(txBits) }
|
||||
|
||||
/** A transaction ID is the hash of the [WireTransaction]. Thus adding or removing a signature does not change it. */
|
||||
override val id: SecureHash get() = txBits.hash
|
||||
|
||||
/**
|
||||
* Verify the signatures, deserialise the wire transaction and then check that the set of signatures found contains
|
||||
* the set of pubkeys in the signers list. If any signatures are missing, either throws an exception (by default) or
|
||||
* returns the list of keys that have missing signatures, depending on the parameter.
|
||||
*
|
||||
* @throws SignatureException if a signature is invalid, does not match or if any signature is missing.
|
||||
*/
|
||||
fun verifySignatures(throwIfSignaturesAreMissing: Boolean = true): Set<PublicKey> {
|
||||
// Embedded WireTransaction is not deserialised until after we check the signatures.
|
||||
for (sig in sigs)
|
||||
sig.verifyWithECDSA(txBits.bits)
|
||||
|
||||
// Now examine the contents and ensure the sigs we have line up with the advertised list of signers.
|
||||
val missing = getMissingSignatures()
|
||||
if (missing.isNotEmpty() && throwIfSignaturesAreMissing) {
|
||||
val missingElements = getMissingKeyDescriptions(missing)
|
||||
throw SignatureException("Missing signatures for ${missingElements} on transaction ${id.prefixChars()} for ${missing.toStringsShort()}")
|
||||
}
|
||||
|
||||
return missing
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a human readable description of where signatures are required from, and are missing, to assist in debugging
|
||||
* the underlying cause.
|
||||
*/
|
||||
private fun getMissingKeyDescriptions(missing: Set<PublicKey>): ArrayList<String> {
|
||||
// TODO: We need a much better way of structuring this data
|
||||
val missingElements = ArrayList<String>()
|
||||
this.tx.commands.forEach { command ->
|
||||
if (command.signers.any { signer -> missing.contains(signer) })
|
||||
missingElements.add(command.toString())
|
||||
}
|
||||
this.tx.notary?.owningKey.apply {
|
||||
if (missing.contains(this))
|
||||
missingElements.add("notary")
|
||||
}
|
||||
return missingElements
|
||||
}
|
||||
|
||||
/** Returns the same transaction but with an additional (unchecked) signature */
|
||||
fun withAdditionalSignature(sig: DigitalSignature.WithKey): SignedTransaction {
|
||||
// TODO: need to make sure the Notary signs last
|
||||
return copy(sigs = sigs + sig)
|
||||
}
|
||||
|
||||
fun withAdditionalSignatures(sigList: Iterable<DigitalSignature.WithKey>): SignedTransaction {
|
||||
return copy(sigs = sigs + sigList)
|
||||
}
|
||||
|
||||
/** Alias for [withAdditionalSignature] to let you use Kotlin operator overloading. */
|
||||
operator fun plus(sig: DigitalSignature.WithKey) = withAdditionalSignature(sig)
|
||||
|
||||
operator fun plus(sigList: Collection<DigitalSignature.WithKey>) = withAdditionalSignatures(sigList)
|
||||
|
||||
/**
|
||||
* Returns the set of missing signatures - a signature must be present for each signer public key.
|
||||
*/
|
||||
private fun getMissingSignatures(): Set<PublicKey> {
|
||||
val requiredKeys = tx.signers.toSet()
|
||||
val sigKeys = sigs.map { it.by }.toSet()
|
||||
|
||||
if (sigKeys.containsAll(requiredKeys)) return emptySet()
|
||||
return requiredKeys - sigKeys
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A LedgerTransaction wraps the data needed to calculate one or more successor states from a set of input states.
|
||||
* It is the first step after extraction from a WireTransaction. The signatures at this point have been lined up
|
||||
* with the commands from the wire, and verified/looked up.
|
||||
*/
|
||||
data class LedgerTransaction(
|
||||
/** The input states which will be consumed/invalidated by the execution of this transaction. */
|
||||
val inputs: List<StateAndRef<*>>,
|
||||
/** The states that will be generated by the execution of this transaction. */
|
||||
val outputs: List<TransactionState<*>>,
|
||||
/** Arbitrary data passed to the program of each input state. */
|
||||
val commands: List<AuthenticatedObject<CommandData>>,
|
||||
/** A list of [Attachment] objects identified by the transaction that are needed for this transaction to verify. */
|
||||
val attachments: List<Attachment>,
|
||||
/** The hash of the original serialised WireTransaction. */
|
||||
override val id: SecureHash,
|
||||
/** The notary for this party, may be null for transactions with no notary. */
|
||||
val notary: Party?,
|
||||
/** The notary key and the command keys together: a signed transaction must provide signatures for all of these. */
|
||||
val signers: List<PublicKey>,
|
||||
val timestamp: Timestamp?,
|
||||
val type: TransactionType
|
||||
) : NamedByHash {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : ContractState> outRef(index: Int) = StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
|
||||
|
||||
// TODO: Remove this concept.
|
||||
// There isn't really a good justification for hiding this data from the contract, it's just a backwards compat hack.
|
||||
/** Strips the transaction down to a form that is usable by the contract verify functions */
|
||||
fun toTransactionForContract(): TransactionForContract {
|
||||
return TransactionForContract(inputs.map { it.state.data }, outputs.map { it.data }, attachments, commands, id,
|
||||
inputs.map { it.state.notary }.singleOrNull(), timestamp)
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies this transaction and throws an exception if not valid, depending on the type. For general transactions:
|
||||
*
|
||||
* - The contracts are run with the transaction as the input.
|
||||
* - The list of keys mentioned in commands is compared against the signers list.
|
||||
*
|
||||
* @throws TransactionVerificationException if anything goes wrong.
|
||||
*/
|
||||
fun verify() = type.verify(this)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package com.r3corda.core.node
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.contracts.StateRef
|
||||
import com.r3corda.core.contracts.TransactionResolutionException
|
||||
import com.r3corda.core.contracts.TransactionState
|
||||
|
@ -5,6 +5,7 @@ import com.google.common.util.concurrent.SettableFuture
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.r3corda.core.node.services
|
||||
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,8 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.*
|
||||
import com.r3corda.core.node.AttachmentsClassLoader
|
||||
import com.r3corda.core.node.services.AttachmentStorage
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.NonEmptySet
|
||||
import com.r3corda.core.utilities.NonEmptySetSerializer
|
||||
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
||||
|
@ -7,6 +7,7 @@ import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.loggerFor
|
||||
import com.r3corda.core.utilities.trace
|
||||
import rx.Observable
|
||||
|
@ -0,0 +1,57 @@
|
||||
package com.r3corda.core.transactions
|
||||
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* A LedgerTransaction is derived from a [WireTransaction]. It is the result of doing the following operations:
|
||||
*
|
||||
* - Downloading and locally storing all the dependencies of the transaction.
|
||||
* - Resolving the input states and loading them into memory.
|
||||
* - Doing some basic key lookups on the [Command]s to see if any keys are from a recognised party, thus converting the
|
||||
* [Command] objects into [AuthenticatedObject].
|
||||
* - Deserialising the output states.
|
||||
*
|
||||
* All the above refer to inputs using a (txhash, output index) pair.
|
||||
*/
|
||||
data class LedgerTransaction(
|
||||
/** The input states which will be consumed/invalidated by the execution of this transaction. */
|
||||
val inputs: List<StateAndRef<*>>,
|
||||
/** The states that will be generated by the execution of this transaction. */
|
||||
val outputs: List<TransactionState<*>>,
|
||||
/** Arbitrary data passed to the program of each input state. */
|
||||
val commands: List<AuthenticatedObject<CommandData>>,
|
||||
/** A list of [Attachment] objects identified by the transaction that are needed for this transaction to verify. */
|
||||
val attachments: List<Attachment>,
|
||||
/** The hash of the original serialised WireTransaction. */
|
||||
override val id: SecureHash,
|
||||
/** The notary for this party, may be null for transactions with no notary. */
|
||||
val notary: Party?,
|
||||
/** The notary key and the command keys together: a signed transaction must provide signatures for all of these. */
|
||||
val signers: List<PublicKey>,
|
||||
val timestamp: Timestamp?,
|
||||
val type: TransactionType
|
||||
) : NamedByHash {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : ContractState> outRef(index: Int) = StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
|
||||
|
||||
// TODO: Remove this concept.
|
||||
// There isn't really a good justification for hiding this data from the contract, it's just a backwards compat hack.
|
||||
/** Strips the transaction down to a form that is usable by the contract verify functions */
|
||||
fun toTransactionForContract(): TransactionForContract {
|
||||
return TransactionForContract(inputs.map { it.state.data }, outputs.map { it.data }, attachments, commands, id,
|
||||
inputs.map { it.state.notary }.singleOrNull(), timestamp)
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies this transaction and throws an exception if not valid, depending on the type. For general transactions:
|
||||
*
|
||||
* - The contracts are run with the transaction as the input.
|
||||
* - The list of keys mentioned in commands is compared against the signers list.
|
||||
*
|
||||
* @throws TransactionVerificationException if anything goes wrong.
|
||||
*/
|
||||
fun verify() = type.verify(this)
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package com.r3corda.core.transactions
|
||||
|
||||
import com.r3corda.core.contracts.NamedByHash
|
||||
import com.r3corda.core.contracts.TransactionResolutionException
|
||||
import com.r3corda.core.crypto.DigitalSignature
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.toStringsShort
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.serialization.SerializedBytes
|
||||
import java.io.FileNotFoundException
|
||||
import java.security.PublicKey
|
||||
import java.security.SignatureException
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* SignedTransaction wraps a serialized WireTransaction. It contains one or more signatures, each one for
|
||||
* a public key that is mentioned inside a transaction command. SignedTransaction is the top level transaction type
|
||||
* and the type most frequently passed around the network and stored. The identity of a transaction is the hash
|
||||
* of a WireTransaction, therefore if you are storing data keyed by WT hash be aware that multiple different STs may
|
||||
* map to the same key (and they could be different in important ways, like validity!). The signatures on a
|
||||
* SignedTransaction might be invalid or missing: the type does not imply validity.
|
||||
*/
|
||||
data class SignedTransaction(val txBits: SerializedBytes<WireTransaction>,
|
||||
val sigs: List<DigitalSignature.WithKey>) : NamedByHash {
|
||||
init {
|
||||
check(sigs.isNotEmpty())
|
||||
}
|
||||
|
||||
// TODO: This needs to be reworked to ensure that the inner WireTransaction is only ever deserialised sandboxed.
|
||||
|
||||
/** Lazily calculated access to the deserialised/hashed transaction data. */
|
||||
val tx: WireTransaction by lazy { WireTransaction.deserialize(txBits) }
|
||||
|
||||
/** A transaction ID is the hash of the [WireTransaction]. Thus adding or removing a signature does not change it. */
|
||||
override val id: SecureHash get() = txBits.hash
|
||||
|
||||
/**
|
||||
* Verify the signatures, deserialise the wire transaction and then check that the set of signatures found contains
|
||||
* the set of pubkeys in the signers list. If any signatures are missing, either throws an exception (by default) or
|
||||
* returns the list of keys that have missing signatures, depending on the parameter.
|
||||
*
|
||||
* @throws SignatureException if a signature is invalid, does not match or if any signature is missing.
|
||||
*/
|
||||
@Throws(SignatureException::class)
|
||||
fun verifySignatures(throwIfSignaturesAreMissing: Boolean = true): Set<PublicKey> {
|
||||
// Embedded WireTransaction is not deserialised until after we check the signatures.
|
||||
for (sig in sigs)
|
||||
sig.verifyWithECDSA(txBits.bits)
|
||||
|
||||
// Now examine the contents and ensure the sigs we have line up with the advertised list of signers.
|
||||
val missing = getMissingSignatures()
|
||||
if (missing.isNotEmpty() && throwIfSignaturesAreMissing) {
|
||||
val missingElements = getMissingKeyDescriptions(missing)
|
||||
throw SignatureException("Missing signatures for ${missingElements} on transaction ${id.prefixChars()} for ${missing.toStringsShort()}")
|
||||
}
|
||||
|
||||
return missing
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a human readable description of where signatures are required from, and are missing, to assist in debugging
|
||||
* the underlying cause.
|
||||
*/
|
||||
private fun getMissingKeyDescriptions(missing: Set<PublicKey>): ArrayList<String> {
|
||||
// TODO: We need a much better way of structuring this data
|
||||
val missingElements = ArrayList<String>()
|
||||
this.tx.commands.forEach { command ->
|
||||
if (command.signers.any { signer -> missing.contains(signer) })
|
||||
missingElements.add(command.toString())
|
||||
}
|
||||
this.tx.notary?.owningKey.apply {
|
||||
if (missing.contains(this))
|
||||
missingElements.add("notary")
|
||||
}
|
||||
return missingElements
|
||||
}
|
||||
|
||||
/** Returns the same transaction but with an additional (unchecked) signature. */
|
||||
fun withAdditionalSignature(sig: DigitalSignature.WithKey) = copy(sigs = sigs + sig)
|
||||
/** Returns the same transaction but with an additional (unchecked) signatures. */
|
||||
fun withAdditionalSignatures(sigList: Iterable<DigitalSignature.WithKey>) = copy(sigs = sigs + sigList)
|
||||
|
||||
/** Alias for [withAdditionalSignature] to let you use Kotlin operator overloading. */
|
||||
operator fun plus(sig: DigitalSignature.WithKey) = withAdditionalSignature(sig)
|
||||
/** Alias for [withAdditionalSignatures] to let you use Kotlin operator overloading. */
|
||||
operator fun plus(sigList: Collection<DigitalSignature.WithKey>) = withAdditionalSignatures(sigList)
|
||||
|
||||
/**
|
||||
* Returns the set of missing signatures - a signature must be present for each signer public key.
|
||||
*/
|
||||
private fun getMissingSignatures(): Set<PublicKey> {
|
||||
val requiredKeys = tx.signers.toSet()
|
||||
val sigKeys = sigs.map { it.by }.toSet()
|
||||
|
||||
if (sigKeys.containsAll(requiredKeys)) return emptySet()
|
||||
return requiredKeys - sigKeys
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls [verifySignatures] to check all required signatures are present, and then calls
|
||||
* [WireTransaction.toLedgerTransaction] with the passed in [ServiceHub] to resolve the dependencies,
|
||||
* returning an unverified LedgerTransaction.
|
||||
*
|
||||
* @throws FileNotFoundException if a required attachment was not found in storage.
|
||||
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
|
||||
*/
|
||||
@Throws(FileNotFoundException::class, TransactionResolutionException::class)
|
||||
fun toLedgerTransaction(services: ServiceHub): LedgerTransaction {
|
||||
verifySignatures()
|
||||
return tx.toLedgerTransaction(services)
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
package com.r3corda.core.contracts
|
||||
package com.r3corda.core.transactions
|
||||
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.*
|
||||
import com.r3corda.core.serialization.serialize
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import java.time.Duration
|
||||
@ -94,10 +97,11 @@ open class TransactionBuilder(
|
||||
/** The signatures that have been collected so far - might be incomplete! */
|
||||
protected val currentSigs = arrayListOf<DigitalSignature.WithKey>()
|
||||
|
||||
fun signWith(key: KeyPair) {
|
||||
fun signWith(key: KeyPair): TransactionBuilder {
|
||||
check(currentSigs.none { it.by == key.public }) { "This partial transaction was already signed by ${key.public}" }
|
||||
val data = toWireTransaction().serialize()
|
||||
addSignatureUnchecked(key.signWithECDSA(data.bits))
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
@ -0,0 +1,114 @@
|
||||
package com.r3corda.core.transactions
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.indexOfOrThrow
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.serialization.SerializedBytes
|
||||
import com.r3corda.core.serialization.THREAD_LOCAL_KRYO
|
||||
import com.r3corda.core.serialization.deserialize
|
||||
import com.r3corda.core.serialization.serialize
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import java.io.FileNotFoundException
|
||||
import java.security.PublicKey
|
||||
|
||||
/**
|
||||
* A transaction ready for serialisation, without any signatures attached. A WireTransaction is usually wrapped
|
||||
* by a [SignedTransaction] that carries the signatures over this payload. The hash of the wire transaction is
|
||||
* the identity of the transaction, that is, it's possible for two [SignedTransaction]s with different sets of
|
||||
* signatures to have the same identity hash.
|
||||
*/
|
||||
data class WireTransaction(
|
||||
/** Pointers to the input states on the ledger, identified by (tx identity hash, output index). */
|
||||
val inputs: List<StateRef>,
|
||||
/** Hashes of the ZIP/JAR files that are needed to interpret the contents of this wire transaction. */
|
||||
val attachments: List<SecureHash>,
|
||||
/** Ordered list of states defined by this transaction, along with the associated notaries. */
|
||||
val outputs: List<TransactionState<ContractState>>,
|
||||
/** Ordered list of ([CommandData], [PublicKey]) pairs that instruct the contracts what to do. */
|
||||
val commands: List<Command>,
|
||||
/**
|
||||
* If present, the notary for this transaction. If absent then the transaction is not notarised at all.
|
||||
* This is intended for issuance/genesis transactions that don't consume any other states and thus can't
|
||||
* double spend anything.
|
||||
*
|
||||
* TODO: Ensure the invariant 'notary == null -> inputs.isEmpty' is enforced!
|
||||
*/
|
||||
val notary: Party?,
|
||||
/**
|
||||
* Keys that are required to have signed the wrapping [SignedTransaction], ordered to match the list of
|
||||
* signatures. There is nothing that forces the list to be the _correct_ list of signers for this
|
||||
* transaction until the transaction is verified by using [LedgerTransaction.verify]. It includes the
|
||||
* notary key, if the notary field is set.
|
||||
*/
|
||||
val signers: List<PublicKey>,
|
||||
/**
|
||||
* Pointer to a class that defines the behaviour of this transaction: either normal, or "notary changing".
|
||||
*/
|
||||
val type: TransactionType,
|
||||
/**
|
||||
* If specified, a time window in which this transaction may have been notarised. Contracts can check this
|
||||
* time window to find out when a transaction is deemed to have occurred, from the ledger's perspective.
|
||||
*
|
||||
* TODO: Ensure the invariant 'timestamp != null -> notary != null' is enforced!
|
||||
*/
|
||||
val timestamp: Timestamp?
|
||||
) : 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
|
||||
val serialized: SerializedBytes<WireTransaction> get() = cachedBits ?: serialize().apply { cachedBits = this }
|
||||
override val id: SecureHash get() = serialized.hash
|
||||
|
||||
companion object {
|
||||
fun deserialize(bits: SerializedBytes<WireTransaction>, kryo: Kryo = THREAD_LOCAL_KRYO.get()): WireTransaction {
|
||||
val wtx = bits.bits.deserialize<WireTransaction>(kryo)
|
||||
wtx.cachedBits = bits
|
||||
return wtx
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a [StateAndRef] for the given output index. */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : ContractState> outRef(index: Int): StateAndRef<T> {
|
||||
require(index >= 0 && index < outputs.size)
|
||||
return StateAndRef(outputs[index] as TransactionState<T>, StateRef(id, index))
|
||||
}
|
||||
|
||||
/** Returns a [StateAndRef] for the requested output state, or throws [IllegalArgumentException] if not found. */
|
||||
fun <T : ContractState> outRef(state: ContractState): StateAndRef<T> = outRef(outputs.map { it.data }.indexOfOrThrow(state))
|
||||
|
||||
override fun toString(): String {
|
||||
val buf = StringBuilder()
|
||||
buf.appendln("Transaction $id:")
|
||||
for (input in inputs) buf.appendln("${Emoji.rightArrow}INPUT: $input")
|
||||
for (output in outputs) buf.appendln("${Emoji.leftArrow}OUTPUT: $output")
|
||||
for (command in commands) buf.appendln("${Emoji.diamond}COMMAND: $command")
|
||||
for (attachment in attachments) buf.appendln("${Emoji.paperclip}ATTACHMENT: $attachment")
|
||||
return buf.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up identities and attachments from storage to generate a [LedgerTransaction]. A transaction is expected to
|
||||
* have been fully resolved using the resolution protocol by this point.
|
||||
*
|
||||
* @throws FileNotFoundException if a required attachment was not found in storage.
|
||||
* @throws TransactionResolutionException if an input points to a transaction not found in storage.
|
||||
*/
|
||||
@Throws(FileNotFoundException::class, TransactionResolutionException::class)
|
||||
fun toLedgerTransaction(services: ServiceHub): LedgerTransaction {
|
||||
// Look up public keys to authenticated identities. This is just a stub placeholder and will all change in future.
|
||||
val authenticatedArgs = commands.map {
|
||||
val parties = it.signers.mapNotNull { pk -> services.identityService.partyFromKey(pk) }
|
||||
AuthenticatedObject(it.signers, parties, it.value)
|
||||
}
|
||||
// Open attachments specified in this transaction. If we haven't downloaded them, we fail.
|
||||
val attachments = attachments.map {
|
||||
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, notary, signers, timestamp, type)
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ import com.r3corda.core.messaging.Ack
|
||||
import com.r3corda.core.node.NodeInfo
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.ProgressTracker
|
||||
import com.r3corda.protocols.AbstractStateReplacementProtocol.Acceptor
|
||||
import com.r3corda.protocols.AbstractStateReplacementProtocol.Instigator
|
||||
|
@ -2,7 +2,7 @@ package com.r3corda.protocols
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.r3corda.core.contracts.ClientToServiceCommand
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.random63BitValue
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.r3corda.protocols
|
||||
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
|
||||
|
@ -3,9 +3,9 @@ package com.r3corda.protocols
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.r3corda.core.contracts.ClientToServiceCommand
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.contracts.TransactionBuilder
|
||||
import com.r3corda.core.contracts.WireTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
|
@ -3,6 +3,7 @@ package com.r3corda.protocols
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.utilities.ProgressTracker
|
||||
import java.security.PublicKey
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.r3corda.protocols
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.contracts.StateRef
|
||||
import com.r3corda.core.contracts.Timestamp
|
||||
import com.r3corda.core.contracts.WireTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.crypto.DigitalSignature
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SignedData
|
||||
|
@ -3,8 +3,8 @@ package com.r3corda.protocols
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.r3corda.core.contracts.Fix
|
||||
import com.r3corda.core.contracts.FixOf
|
||||
import com.r3corda.core.contracts.TransactionBuilder
|
||||
import com.r3corda.core.contracts.WireTransaction
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.crypto.DigitalSignature
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
|
@ -2,10 +2,9 @@ package com.r3corda.protocols
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.r3corda.core.checkedAdd
|
||||
import com.r3corda.core.contracts.LedgerTransaction
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.contracts.WireTransaction
|
||||
import com.r3corda.core.contracts.toLedgerTransaction
|
||||
import com.r3corda.core.transactions.LedgerTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
|
@ -11,6 +11,9 @@ import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.seconds
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.ProgressTracker
|
||||
import com.r3corda.core.utilities.UntrustworthyData
|
||||
import com.r3corda.core.utilities.trace
|
||||
|
@ -1,10 +1,9 @@
|
||||
package com.r3corda.protocols
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.contracts.TransactionVerificationException
|
||||
import com.r3corda.core.contracts.WireTransaction
|
||||
import com.r3corda.core.contracts.toLedgerTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.node.services.TimestampChecker
|
||||
import com.r3corda.core.node.services.UniquenessProvider
|
||||
|
Binary file not shown.
@ -1,6 +1,8 @@
|
||||
package com.r3corda.core.contracts
|
||||
|
||||
import com.r3corda.core.crypto.newSecureRandom
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.testing.node.MockTransactionStorage
|
||||
|
@ -5,6 +5,7 @@ import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.node.services.AttachmentStorage
|
||||
import com.r3corda.core.serialization.*
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.testing.node.MockAttachmentStorage
|
||||
import com.r3corda.testing.MEGA_CORP
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.r3corda.core.protocols
|
||||
|
||||
import com.r3corda.core.contracts.DummyContract
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.NullSignature
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
|
@ -3,6 +3,7 @@ package com.r3corda.core.serialization
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.seconds
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.*
|
||||
import com.r3corda.testing.*
|
||||
import org.junit.Before
|
||||
|
@ -4,6 +4,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.toStringShort
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneOffset
|
||||
|
@ -4,6 +4,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.days
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneOffset
|
||||
|
@ -4,6 +4,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.NullPublicKey
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.time.LocalDate
|
||||
import java.time.Period
|
||||
|
@ -5,6 +5,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.days
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
|
@ -3,6 +3,7 @@ package com.r3corda.contracts.universal
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import java.math.BigDecimal
|
||||
import java.security.PublicKey
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
package com.r3corda.contracts
|
||||
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.contracts.LedgerTransaction
|
||||
import com.r3corda.core.transactions.LedgerTransaction
|
||||
import com.r3corda.core.contracts.`issued by`
|
||||
import com.r3corda.core.contracts.toLedgerTransaction
|
||||
import com.r3corda.core.seconds
|
||||
import com.r3corda.core.serialization.OpaqueBytes
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
|
@ -2,6 +2,7 @@ package com.r3corda.contracts
|
||||
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.testing.node.MockServices
|
||||
@ -81,7 +82,7 @@ class BillOfLadingAgreementTests {
|
||||
// @Test // TODO: Fix Test
|
||||
fun transferAndEndorseGenerationMethod() {
|
||||
|
||||
val ptx:TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val ptx: TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val sr = StateAndRef(
|
||||
TransactionState(Bill, DUMMY_NOTARY),
|
||||
StateRef(SecureHash.randomSHA256(), Random().nextInt(32))
|
||||
@ -95,7 +96,7 @@ class BillOfLadingAgreementTests {
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun transferAndEndorseGenerationMethod_MissingBeneficiarySignature() {
|
||||
val ptx:TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val ptx: TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val sr = StateAndRef(
|
||||
TransactionState(Bill, DUMMY_NOTARY),
|
||||
StateRef(SecureHash.randomSHA256(), Random().nextInt(32))
|
||||
@ -107,7 +108,7 @@ class BillOfLadingAgreementTests {
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun transferAndEndorseGenerationMethod_MissingOwnerSignature() {
|
||||
val ptx:TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val ptx: TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val sr = StateAndRef(
|
||||
TransactionState(Bill, DUMMY_NOTARY),
|
||||
StateRef(SecureHash.randomSHA256(), Random().nextInt(32))
|
||||
@ -119,7 +120,7 @@ class BillOfLadingAgreementTests {
|
||||
|
||||
// @Test // TODO Fix Test
|
||||
fun transferPossessionGenerationMethod() {
|
||||
val ptx:TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val ptx: TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val sr = StateAndRef(
|
||||
TransactionState(Bill, DUMMY_NOTARY),
|
||||
StateRef(SecureHash.randomSHA256(), Random().nextInt(32))
|
||||
@ -131,7 +132,7 @@ class BillOfLadingAgreementTests {
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun transferPossessionGenerationMethod_Unsigned() {
|
||||
val ptx:TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val ptx: TransactionBuilder = TransactionType.General.Builder(notary = DUMMY_NOTARY)
|
||||
val sr = StateAndRef(
|
||||
TransactionState(Bill, DUMMY_NOTARY),
|
||||
StateRef(SecureHash.randomSHA256(), Random().nextInt(32))
|
||||
|
@ -5,6 +5,8 @@ import com.r3corda.node.api.StatesQuery
|
||||
import com.r3corda.core.crypto.DigitalSignature
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.serialization.SerializedBytes
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import javax.ws.rs.GET
|
||||
|
@ -6,6 +6,8 @@ import com.r3corda.core.crypto.DigitalSignature
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.node.services.linearHeadsOfType
|
||||
import com.r3corda.core.serialization.SerializedBytes
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.node.api.*
|
||||
import java.time.LocalDateTime
|
||||
import javax.ws.rs.core.Response
|
||||
|
@ -5,7 +5,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.google.common.util.concurrent.MoreExecutors
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import com.r3corda.core.RunOnCallerThread
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.messaging.runOnNextMessage
|
||||
import com.r3corda.core.node.CityDatabase
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.r3corda.node.services.api
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.messaging.MessagingService
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.TxWritableStorageService
|
||||
|
@ -12,6 +12,7 @@ import com.r3corda.core.math.InterpolatorFactory
|
||||
import com.r3corda.core.node.CordaPluginRegistry
|
||||
import com.r3corda.core.node.services.ServiceType
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.ProgressTracker
|
||||
import com.r3corda.node.services.api.AbstractNodeService
|
||||
import com.r3corda.node.services.api.AcceptsFileUpload
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.r3corda.node.services.monitor
|
||||
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.node.utilities.AddOrRemove
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
|
@ -14,6 +14,8 @@ import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.serialization.serialize
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.loggerFor
|
||||
import com.r3corda.node.services.api.AbstractNodeService
|
||||
import com.r3corda.node.services.statemachine.StateMachineManager
|
||||
|
@ -2,7 +2,7 @@ package com.r3corda.node.services.persistence
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.failure
|
||||
import com.r3corda.core.messaging.MessagingService
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.r3corda.node.services.persistence
|
||||
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.node.services.TransactionStorage
|
||||
import com.r3corda.core.serialization.deserialize
|
||||
|
@ -14,6 +14,8 @@ import com.r3corda.core.node.services.ServiceType
|
||||
import com.r3corda.core.node.services.TransactionStorage
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.core.utilities.LogHelper
|
||||
|
@ -2,7 +2,7 @@ package com.r3corda.node.services
|
||||
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.node.services.*
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.protocols.ProtocolLogicRefFactory
|
||||
|
@ -2,7 +2,7 @@ package com.r3corda.node.services
|
||||
|
||||
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.node.services.TxWritableStorageService
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.testing.node.MockServices
|
||||
|
@ -6,6 +6,7 @@ import com.r3corda.contracts.asset.cashBalances
|
||||
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import com.r3corda.core.utilities.LogHelper
|
||||
|
@ -4,7 +4,7 @@ import co.paralleluniverse.strands.SettableFuture
|
||||
import com.google.common.jimfs.Configuration.unix
|
||||
import com.google.common.jimfs.Jimfs
|
||||
import com.google.common.primitives.Ints
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.DigitalSignature
|
||||
import com.r3corda.core.crypto.NullPublicKey
|
||||
import com.r3corda.core.serialization.SerializedBytes
|
||||
|
@ -17,6 +17,7 @@ import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
||||
import com.r3corda.core.node.services.ServiceType
|
||||
import com.r3corda.core.protocols.ProtocolLogic
|
||||
import com.r3corda.core.serialization.deserialize
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.utilities.Emoji
|
||||
import com.r3corda.core.utilities.LogHelper
|
||||
import com.r3corda.core.utilities.ProgressTracker
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.r3corda.demos.api
|
||||
|
||||
import com.r3corda.contracts.InterestRateSwap
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.failure
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.node.services.linearHeadsOfType
|
||||
|
@ -4,7 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import com.google.common.util.concurrent.FutureCallback
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.r3corda.core.contracts.DealState
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.node.CordaPluginRegistry
|
||||
import com.r3corda.core.node.services.DEFAULT_SESSION_ID
|
||||
|
@ -7,7 +7,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import com.r3corda.contracts.InterestRateSwap
|
||||
import com.r3corda.core.RunOnCallerThread
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.contracts.StateAndRef
|
||||
import com.r3corda.core.contracts.UniqueIdentifier
|
||||
import com.r3corda.core.failure
|
||||
|
@ -7,7 +7,7 @@ import com.r3corda.contracts.asset.DUMMY_CASH_ISSUER
|
||||
import com.r3corda.contracts.testing.fillWithSomeTestCash
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.contracts.OwnableState
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.contracts.`issued by`
|
||||
import com.r3corda.core.days
|
||||
import com.r3corda.core.random63BitValue
|
||||
|
@ -6,7 +6,7 @@ import com.google.common.base.Throwables
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.r3corda.testing.*
|
||||
import com.r3corda.core.contracts.StateRef
|
||||
import com.r3corda.core.contracts.TransactionBuilder
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.crypto.*
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.testing.node.MockIdentityService
|
||||
|
@ -2,6 +2,8 @@ package com.r3corda.testing
|
||||
|
||||
import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import java.io.InputStream
|
||||
|
||||
|
@ -4,6 +4,9 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.*
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
import com.r3corda.core.serialization.serialize
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.transactions.WireTransaction
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import java.io.InputStream
|
||||
import java.security.KeyPair
|
||||
|
@ -4,6 +4,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.seconds
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import java.security.PublicKey
|
||||
import java.time.Duration
|
||||
|
@ -2,7 +2,7 @@ package com.r3corda.testing.node
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.r3corda.core.contracts.Attachment
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.transactions.SignedTransaction
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.crypto.generateKeyPair
|
||||
|
Loading…
x
Reference in New Issue
Block a user