mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Bug fix for cash selection on H2 where the accumulated pennies amount is larger than max int
This commit is contained in:
parent
8e7165db41
commit
332915f08b
@ -13,7 +13,6 @@ import java.sql.ResultSet
|
||||
import java.util.*
|
||||
|
||||
class CashSelectionH2Impl : AbstractCashSelection() {
|
||||
|
||||
companion object {
|
||||
const val JDBC_DRIVER_NAME = "H2 JDBC Driver"
|
||||
val log = loggerFor<CashSelectionH2Impl>()
|
||||
@ -25,7 +24,6 @@ class CashSelectionH2Impl : AbstractCashSelection() {
|
||||
|
||||
override fun toString() = "${this::class.java} for $JDBC_DRIVER_NAME"
|
||||
|
||||
|
||||
// We are using an H2 specific means of selecting a minimum set of rows that match a request amount of coins:
|
||||
// 1) There is no standard SQL mechanism of calculating a cumulative total on a field and restricting row selection on the
|
||||
// running total of such an accumulator
|
||||
@ -34,7 +32,7 @@ class CashSelectionH2Impl : AbstractCashSelection() {
|
||||
// 3) H2 does not support JOIN's in FOR UPDATE (hence we are forced to execute 2 queries)
|
||||
override fun executeQuery(connection: Connection, amount: Amount<Currency>, lockId: UUID, notary: Party?,
|
||||
onlyFromIssuerParties: Set<AbstractParty>, withIssuerRefs: Set<OpaqueBytes>) : ResultSet {
|
||||
connection.createStatement().execute("CALL SET(@t, 0);")
|
||||
connection.createStatement().execute("CALL SET(@t, CAST(0 AS BIGINT));")
|
||||
|
||||
val selectJoin = """
|
||||
SELECT vs.transaction_id, vs.output_index, ccs.pennies, SET(@t, ifnull(@t,0)+ccs.pennies) total_pennies, vs.lock_id
|
||||
|
@ -1,8 +1,12 @@
|
||||
package net.corda.finance.contracts.asset
|
||||
package net.corda.finance.contracts.asset.cash.selection
|
||||
|
||||
import net.corda.core.internal.concurrent.transpose
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.finance.POUNDS
|
||||
import net.corda.finance.flows.CashException
|
||||
import net.corda.finance.flows.CashIssueFlow
|
||||
import net.corda.finance.flows.CashPaymentFlow
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
@ -10,8 +14,9 @@ import net.corda.testing.startFlow
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.After
|
||||
import org.junit.Test
|
||||
import java.util.Collections.nCopies
|
||||
|
||||
class CashSelectionH2Test {
|
||||
class CashSelectionH2ImplTest {
|
||||
private val mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance"))
|
||||
|
||||
@After
|
||||
@ -19,6 +24,19 @@ class CashSelectionH2Test {
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `selecting pennies amount larger than max int, which is split across multiple cash states`() {
|
||||
val node = mockNet.createNode()
|
||||
// The amount has to split across at least two states, probably to trigger the H2 accumulator variable during the
|
||||
// spend operation below.
|
||||
// Issuing Integer.MAX_VALUE will not cause an exception since PersistentCashState.pennies is a long
|
||||
nCopies(2, Integer.MAX_VALUE).map { issueAmount ->
|
||||
node.services.startFlow(CashIssueFlow(issueAmount.POUNDS, OpaqueBytes.of(1), mockNet.defaultNotaryIdentity)).resultFuture
|
||||
}.transpose().getOrThrow()
|
||||
// The spend must be more than the size of a single cash state to force the accumulator onto the second state.
|
||||
node.services.startFlow(CashPaymentFlow((Integer.MAX_VALUE + 1L).POUNDS, node.info.legalIdentities[0])).resultFuture.getOrThrow()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `check does not hold connection over retries`() {
|
||||
val bankA = mockNet.createNode(MockNodeParameters(configOverrides = {
|
Loading…
Reference in New Issue
Block a user