corda/tests/core/TransactionGroupTests.kt

121 lines
3.8 KiB
Kotlin

package core
import contracts.Cash
import core.testutils.*
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNotEquals
class TransactionGroupTests {
val A_THOUSAND_POUNDS = Cash.State(InstitutionReference(MINI_CORP, OpaqueBytes.of(1, 2, 3)), 1000.POUNDS, MINI_CORP_KEY)
@Test
fun success() {
transactionGroup {
roots {
transaction(A_THOUSAND_POUNDS label "£1000")
}
transaction {
input("£1000")
output("alice's £1000") { A_THOUSAND_POUNDS `owned by` ALICE }
arg(MINI_CORP_KEY) { Cash.Commands.Move }
}
transaction {
input("alice's £1000")
arg(ALICE) { Cash.Commands.Move }
arg(MINI_CORP_KEY) { Cash.Commands.Exit(1000.POUNDS) }
}
verify()
}
}
@Test
fun conflict() {
transactionGroup {
val t = transaction {
output("cash") { A_THOUSAND_POUNDS }
arg(MINI_CORP_KEY) { Cash.Commands.Issue() }
}
val conflict1 = transaction {
input("cash")
val HALF = A_THOUSAND_POUNDS.copy(amount = 500.POUNDS) `owned by` BOB
output { HALF }
output { HALF }
arg(MINI_CORP_KEY) { Cash.Commands.Move }
}
verify()
// Alice tries to double spend back to herself.
val conflict2 = transaction {
input("cash")
val HALF = A_THOUSAND_POUNDS.copy(amount = 500.POUNDS) `owned by` ALICE
output { HALF }
output { HALF }
arg(MINI_CORP_KEY) { Cash.Commands.Move }
}
assertNotEquals(conflict1, conflict2)
val e = assertFailsWith(TransactionConflictException::class) {
verify()
}
assertEquals(ContractStateRef(t.hash, 0), e.conflictRef)
assertEquals(setOf(conflict1, conflict2), setOf(e.tx1, e.tx2))
}
}
@Test
fun disconnected() {
// Check that if we have a transaction in the group that doesn't connect to anything else, it's rejected.
val tg = transactionGroup {
transaction {
output("cash") { A_THOUSAND_POUNDS }
arg(MINI_CORP_KEY) { Cash.Commands.Issue() }
}
transaction {
input("cash")
output { A_THOUSAND_POUNDS `owned by` BOB }
}
}
// We have to do this manually without the DSL because transactionGroup { } won't let us create a tx that
// points nowhere.
val ref = ContractStateRef(SecureHash.randomSHA256(), 0)
tg.txns.add(LedgerTransaction(
listOf(ref), listOf(A_THOUSAND_POUNDS), listOf(AuthenticatedObject(listOf(BOB), emptyList(), Cash.Commands.Move)), TEST_TX_TIME, SecureHash.randomSHA256())
)
val e = assertFailsWith(TransactionResolutionException::class) {
tg.verify()
}
assertEquals(e.hash, ref.txhash)
}
@Test
fun duplicatedInputs() {
// Check that a transaction cannot refer to the same input more than once.
transactionGroup {
roots {
transaction(A_THOUSAND_POUNDS label "£1000")
}
transaction {
input("£1000")
input("£1000")
output { A_THOUSAND_POUNDS.copy(amount = A_THOUSAND_POUNDS.amount * 2) }
arg(MINI_CORP_KEY) { Cash.Commands.Move }
}
assertFailsWith(TransactionConflictException::class) {
verify()
}
}
}
}