Add Any constraint to Amount token

Signed-off-by: Ross Nicoll <ross.nicoll@r3.com>
This commit is contained in:
Matthew Nesbit 2017-03-29 15:39:23 +01:00 committed by Ross Nicoll
parent e0a2c76f39
commit 062dc67ab6
8 changed files with 43 additions and 43 deletions

View File

@ -14,7 +14,7 @@ import java.util.stream.Collectors
* Utility bindings for the [Amount] type, similar in spirit to [Bindings]
*/
object AmountBindings {
fun <T> sum(amounts: ObservableList<Amount<T>>, token: T) = EasyBind.map(
fun <T: Any> sum(amounts: ObservableList<Amount<T>>, token: T) = EasyBind.map(
Bindings.createLongBinding({
amounts.stream().collect(Collectors.summingLong {
require(it.token == token)

View File

@ -36,7 +36,7 @@ import java.util.*
* @param T the type of the token, for example [Currency].
*/
@CordaSerializable
data class Amount<T>(val quantity: Long, val token: T) : Comparable<Amount<T>> {
data class Amount<T: Any>(val quantity: Long, val token: T) : Comparable<Amount<T>> {
companion object {
/**
* Build a currency amount from a decimal representation. For example, with an input of "12.34" GBP,
@ -165,9 +165,9 @@ data class Amount<T>(val quantity: Long, val token: T) : Comparable<Amount<T>> {
*/
fun Amount<Currency>.toDecimal() : BigDecimal = BigDecimal(quantity).movePointLeft(token.defaultFractionDigits)
fun <T> Iterable<Amount<T>>.sumOrNull() = if (!iterator().hasNext()) null else sumOrThrow()
fun <T> Iterable<Amount<T>>.sumOrThrow() = reduce { left, right -> left + right }
fun <T> Iterable<Amount<T>>.sumOrZero(currency: T) = if (iterator().hasNext()) sumOrThrow() else Amount(0, currency)
fun <T: Any> Iterable<Amount<T>>.sumOrNull() = if (!iterator().hasNext()) null else sumOrThrow()
fun <T: Any> Iterable<Amount<T>>.sumOrThrow() = reduce { left, right -> left + right }
fun <T: Any> Iterable<Amount<T>>.sumOrZero(currency: T) = if (iterator().hasNext()) sumOrThrow() else Amount(0, currency)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//

View File

@ -19,7 +19,7 @@ class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException
* @param T a type that represents the asset in question. This should describe the basic type of the asset
* (GBP, USD, oil, shares in company <X>, etc.) and any additional metadata (issuer, grade, class, etc.).
*/
interface FungibleAsset<T> : OwnableState {
interface FungibleAsset<T: Any> : OwnableState {
val amount: Amount<Issued<T>>
/**
* There must be an ExitCommand signed by these keys to destroy the amount. While all states require their
@ -45,7 +45,7 @@ interface FungibleAsset<T> : OwnableState {
* A command stating that money has been withdrawn from the shared ledger and is now accounted for
* in some other way.
*/
interface Exit<T> : Commands {
interface Exit<T: Any> : Commands {
val amount: Amount<Issued<T>>
}
}
@ -54,8 +54,8 @@ interface FungibleAsset<T> : OwnableState {
// Small DSL extensions.
/** Sums the asset states in the list, returning null if there are none. */
fun <T> Iterable<ContractState>.sumFungibleOrNull() = filterIsInstance<FungibleAsset<T>>().map { it.amount }.sumOrNull()
fun <T: Any> Iterable<ContractState>.sumFungibleOrNull() = filterIsInstance<FungibleAsset<T>>().map { it.amount }.sumOrNull()
/** Sums the asset states in the list, returning zero of the given token if there are none. */
fun <T> Iterable<ContractState>.sumFungibleOrZero(token: Issued<T>) = filterIsInstance<FungibleAsset<T>>().map { it.amount }.sumOrZero(token)
fun <T: Any> Iterable<ContractState>.sumFungibleOrZero(token: Issued<T>) = filterIsInstance<FungibleAsset<T>>().map { it.amount }.sumOrZero(token)

View File

@ -173,7 +173,7 @@ interface IssuanceDefinition
* @param P the type of product underlying the definition, for example [Currency].
*/
@CordaSerializable
data class Issued<out P>(val issuer: PartyAndReference, val product: P) {
data class Issued<out P: Any>(val issuer: PartyAndReference, val product: P) {
override fun toString() = "$product issued by $issuer"
}
@ -182,7 +182,7 @@ data class Issued<out P>(val issuer: PartyAndReference, val product: P) {
* cares about specific issuers with code that will accept any, or which is imposing issuer constraints via some
* other mechanism and the additional type safety is not wanted.
*/
fun <T> Amount<Issued<T>>.withoutIssuer(): Amount<T> = Amount(quantity, token.product)
fun <T: Any> Amount<Issued<T>>.withoutIssuer(): Amount<T> = Amount(quantity, token.product)
/**
* A contract state that can have a single owner.

View File

@ -83,14 +83,14 @@ class TransactionStateGenerator<T : ContractState>(val stateGenerator: Generator
}
@Suppress("CAST_NEVER_SUCCEEDS", "UNCHECKED_CAST")
class IssuedGenerator<T>(val productGenerator: Generator<T>) : Generator<Issued<T>>(Issued::class.java as Class<Issued<T>>) {
class IssuedGenerator<T: Any>(val productGenerator: Generator<T>) : Generator<Issued<T>>(Issued::class.java as Class<Issued<T>>) {
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Issued<T> {
return Issued(PartyAndReferenceGenerator().generate(random, status), productGenerator.generate(random, status))
}
}
@Suppress("CAST_NEVER_SUCCEEDS", "UNCHECKED_CAST")
class AmountGenerator<T>(val tokenGenerator: Generator<T>) : Generator<Amount<T>>(Amount::class.java as Class<Amount<T>>) {
class AmountGenerator<T: Any>(val tokenGenerator: Generator<T>) : Generator<Amount<T>>(Amount::class.java as Class<Amount<T>>) {
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Amount<T> {
return Amount(random.nextLong(0, 1000000), tokenGenerator.generate(random, status))
}

View File

@ -29,7 +29,7 @@ val OBLIGATION_PROGRAM_ID = Obligation<Currency>()
*
* @param P the product the obligation is for payment of.
*/
class Obligation<P> : Contract {
class Obligation<P: Any> : Contract {
/**
* TODO:
@ -47,7 +47,7 @@ class Obligation<P> : Contract {
/**
* Parent clause for clauses that operate on grouped states (those which are fungible).
*/
class Group<P> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>(
class Group<P: Any> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>(
AllOf(
NoZeroSizedOutputs<State<P>, Commands, Terms<P>>(),
FirstOf(
@ -70,19 +70,19 @@ class Obligation<P> : Contract {
/**
* Generic issuance clause
*/
class Issue<P> : AbstractIssue<State<P>, Commands, Terms<P>>({ -> sumObligations() }, { token: Issued<Terms<P>> -> sumObligationsOrZero(token) }) {
class Issue<P: Any> : AbstractIssue<State<P>, Commands, Terms<P>>({ -> sumObligations() }, { token: Issued<Terms<P>> -> sumObligationsOrZero(token) }) {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Commands.Issue::class.java)
}
/**
* Generic move/exit clause for fungible assets
*/
class ConserveAmount<P> : AbstractConserveAmount<State<P>, Commands, Terms<P>>()
class ConserveAmount<P: Any> : AbstractConserveAmount<State<P>, Commands, Terms<P>>()
/**
* Clause for supporting netting of obligations.
*/
class Net<C : CommandData, P> : NetClause<C, P>() {
class Net<C : CommandData, P: Any> : NetClause<C, P>() {
val lifecycleClause = Clauses.VerifyLifecycle<ContractState, C, Unit, P>()
override fun toString(): String = "Net obligations"
@ -95,7 +95,7 @@ class Obligation<P> : Contract {
/**
* Obligation-specific clause for changing the lifecycle of one or more states.
*/
class SetLifecycle<P> : Clause<State<P>, Commands, Issued<Terms<P>>>() {
class SetLifecycle<P: Any> : Clause<State<P>, Commands, Issued<Terms<P>>>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Commands.SetLifecycle::class.java)
override fun verify(tx: TransactionForContract,
@ -115,7 +115,7 @@ class Obligation<P> : Contract {
* Obligation-specific clause for settling an outstanding obligation by witnessing
* change of ownership of other states to fulfil
*/
class Settle<P> : Clause<State<P>, Commands, Issued<Terms<P>>>() {
class Settle<P: Any> : Clause<State<P>, Commands, Issued<Terms<P>>>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Commands.Settle::class.java)
override fun verify(tx: TransactionForContract,
inputs: List<State<P>>,
@ -204,7 +204,7 @@ class Obligation<P> : Contract {
* any lifecycle change clause, which is the only clause that involve
* non-standard lifecycle states on input/output.
*/
class VerifyLifecycle<S : ContractState, C : CommandData, T : Any, P> : Clause<S, C, T>() {
class VerifyLifecycle<S : ContractState, C : CommandData, T : Any, P: Any> : Clause<S, C, T>() {
override fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,
@ -245,7 +245,7 @@ class Obligation<P> : Contract {
* @param P the product the obligation is for payment of.
*/
@CordaSerializable
data class Terms<P>(
data class Terms<P: Any>(
/** The hash of the asset contract we're willing to accept in payment for this debt. */
val acceptableContracts: NonEmptySet<SecureHash>,
/** The parties whose assets we are willing to accept in payment for this debt. */
@ -266,7 +266,7 @@ class Obligation<P> : Contract {
*
* @param P the product the obligation is for payment of.
*/
data class State<P>(
data class State<P: Any>(
var lifecycle: Lifecycle = Lifecycle.NORMAL,
/** Where the debt originates from (obligor) */
val obligor: AnonymousParty,
@ -354,7 +354,7 @@ class Obligation<P> : Contract {
* state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed.
* @see [MoveCommand].
*/
data class Settle<P>(val amount: Amount<Issued<Terms<P>>>) : Commands
data class Settle<P: Any>(val amount: Amount<Issued<Terms<P>>>) : Commands
/**
* A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled
@ -372,7 +372,7 @@ class Obligation<P> : Contract {
* A command stating that the debt is being released by the beneficiary. Normally would indicate
* either settlement outside of the ledger, or that the obligor is unable to pay.
*/
data class Exit<P>(override val amount: Amount<Issued<Terms<P>>>) : Commands, FungibleAsset.Commands.Exit<Terms<P>>
data class Exit<P: Any>(override val amount: Amount<Issued<Terms<P>>>) : Commands, FungibleAsset.Commands.Exit<Terms<P>>
}
override fun verify(tx: TransactionForContract) = verifyClause<Commands>(tx, FirstOf<ContractState, Commands, Unit>(
@ -629,7 +629,7 @@ class Obligation<P> : Contract {
*
* @return a map of obligor/beneficiary pairs to the balance due.
*/
fun <P> extractAmountsDue(product: Obligation.Terms<P>, states: Iterable<Obligation.State<P>>): Map<Pair<CompositeKey, CompositeKey>, Amount<Obligation.Terms<P>>> {
fun <P: Any> extractAmountsDue(product: Obligation.Terms<P>, states: Iterable<Obligation.State<P>>): Map<Pair<CompositeKey, CompositeKey>, Amount<Obligation.Terms<P>>> {
val balances = HashMap<Pair<CompositeKey, CompositeKey>, Amount<Obligation.Terms<P>>>()
states.forEach { state ->
@ -644,7 +644,7 @@ fun <P> extractAmountsDue(product: Obligation.Terms<P>, states: Iterable<Obligat
/**
* Net off the amounts due between parties.
*/
fun <P> netAmountsDue(balances: Map<Pair<CompositeKey, CompositeKey>, Amount<P>>): Map<Pair<CompositeKey, CompositeKey>, Amount<P>> {
fun <P: Any> netAmountsDue(balances: Map<Pair<CompositeKey, CompositeKey>, Amount<P>>): Map<Pair<CompositeKey, CompositeKey>, Amount<P>> {
val nettedBalances = HashMap<Pair<CompositeKey, CompositeKey>, Amount<P>>()
balances.forEach { balance ->
@ -669,7 +669,7 @@ fun <P> netAmountsDue(balances: Map<Pair<CompositeKey, CompositeKey>, Amount<P>>
* @param balances payments due, indexed by obligor and beneficiary. Zero balances are stripped from the map before being
* returned.
*/
fun <P> sumAmountsDue(balances: Map<Pair<CompositeKey, CompositeKey>, Amount<P>>): Map<CompositeKey, Long> {
fun <P: Any> sumAmountsDue(balances: Map<Pair<CompositeKey, CompositeKey>, Amount<P>>): Map<CompositeKey, Long> {
val sum = HashMap<CompositeKey, Long>()
// Fill the map with zeroes initially
@ -699,25 +699,25 @@ fun <P> sumAmountsDue(balances: Map<Pair<CompositeKey, CompositeKey>, Amount<P>>
}
/** Sums the obligation states in the list, throwing an exception if there are none. All state objects in the list are presumed to be nettable. */
fun <P> Iterable<ContractState>.sumObligations(): Amount<Issued<Obligation.Terms<P>>>
fun <P: Any> Iterable<ContractState>.sumObligations(): Amount<Issued<Obligation.Terms<P>>>
= filterIsInstance<Obligation.State<P>>().map { it.amount }.sumOrThrow()
/** Sums the obligation states in the list, returning null if there are none. */
fun <P> Iterable<ContractState>.sumObligationsOrNull(): Amount<Issued<Obligation.Terms<P>>>?
fun <P: Any> Iterable<ContractState>.sumObligationsOrNull(): Amount<Issued<Obligation.Terms<P>>>?
= filterIsInstance<Obligation.State<P>>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrNull()
/** Sums the obligation states in the list, returning zero of the given product if there are none. */
fun <P> Iterable<ContractState>.sumObligationsOrZero(issuanceDef: Issued<Obligation.Terms<P>>): Amount<Issued<Obligation.Terms<P>>>
fun <P: Any> Iterable<ContractState>.sumObligationsOrZero(issuanceDef: Issued<Obligation.Terms<P>>): Amount<Issued<Obligation.Terms<P>>>
= filterIsInstance<Obligation.State<P>>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrZero(issuanceDef)
infix fun <T> Obligation.State<T>.at(dueBefore: Instant) = copy(template = template.copy(dueBefore = dueBefore))
infix fun <T> Obligation.State<T>.between(parties: Pair<AbstractParty, CompositeKey>) = copy(obligor = parties.first.toAnonymous(), beneficiary = parties.second)
infix fun <T> Obligation.State<T>.`owned by`(owner: CompositeKey) = copy(beneficiary = owner)
infix fun <T> Obligation.State<T>.`issued by`(party: AbstractParty) = copy(obligor = party.toAnonymous())
infix fun <T: Any> Obligation.State<T>.at(dueBefore: Instant) = copy(template = template.copy(dueBefore = dueBefore))
infix fun <T: Any> Obligation.State<T>.between(parties: Pair<AbstractParty, CompositeKey>) = copy(obligor = parties.first.toAnonymous(), beneficiary = parties.second)
infix fun <T: Any> Obligation.State<T>.`owned by`(owner: CompositeKey) = copy(beneficiary = owner)
infix fun <T: Any> Obligation.State<T>.`issued by`(party: AbstractParty) = copy(obligor = party.toAnonymous())
// For Java users:
@Suppress("unused") fun <T> Obligation.State<T>.ownedBy(owner: CompositeKey) = copy(beneficiary = owner)
@Suppress("unused") fun <T: Any> Obligation.State<T>.ownedBy(owner: CompositeKey) = copy(beneficiary = owner)
@Suppress("unused") fun <T> Obligation.State<T>.issuedBy(party: AnonymousParty) = copy(obligor = party)
@Suppress("unused") fun <T: Any> Obligation.State<T>.issuedBy(party: AnonymousParty) = copy(obligor = party)
/** A randomly generated key. */
val DUMMY_OBLIGATION_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) }

View File

@ -12,7 +12,7 @@ import net.corda.core.crypto.CompositeKey
* Common interface for the state subsets used when determining nettability of two or more states. Exposes the
* underlying issued thing.
*/
interface NetState<P> {
interface NetState<P: Any> {
val template: Obligation.Terms<P>
}
@ -21,7 +21,7 @@ interface NetState<P> {
* If two obligation state objects produce equal bilateral net states, they are considered safe to net directly.
* Bilateral states are used in close-out netting.
*/
data class BilateralNetState<P>(
data class BilateralNetState<P: Any>(
val partyKeys: Set<CompositeKey>,
override val template: Obligation.Terms<P>
) : NetState<P>
@ -34,7 +34,7 @@ data class BilateralNetState<P>(
* input and output is handled elsewhere.
* Used in cases where all parties (or their proxies) are signing, such as central clearing.
*/
data class MultilateralNetState<P>(
data class MultilateralNetState<P: Any>(
override val template: Obligation.Terms<P>
) : NetState<P>
@ -42,7 +42,7 @@ data class MultilateralNetState<P>(
* Clause for netting contract states. Currently only supports obligation contract.
*/
// TODO: Make this usable for any nettable contract states
open class NetClause<C : CommandData, P> : Clause<ContractState, C, Unit>() {
open class NetClause<C : CommandData, P: Any> : Clause<ContractState, C, Unit>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Obligation.Commands.Net::class.java)
@Suppress("ConvertLambdaToReference")

View File

@ -12,12 +12,12 @@ val Positivity.sign: String get() = when (this) {
Positivity.Negative -> "-"
}
data class AmountDiff<T>(
data class AmountDiff<T: Any>(
val positivity: Positivity,
val amount: Amount<T>
) {
companion object {
fun <T> fromLong(quantity: Long, token: T) =
fun <T: Any> fromLong(quantity: Long, token: T) =
AmountDiff(
positivity = if (quantity < 0) Positivity.Negative else Positivity.Positive,
amount = Amount(Math.abs(quantity), token)