diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index f17c8f5aac..962f80736a 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -6,6 +6,7 @@ release, see :doc:`upgrade-notes`. Unreleased ========== +* Fixed an error thrown by NodeVaultService upon recording a transaction with a number of inputs greater than the default page size. * Changes to the JSON/YAML serialisation format from ``JacksonSupport``, which also applies to the node shell: diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt index 88a0d9a822..19cb690aa5 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt @@ -190,9 +190,18 @@ class NodeVaultService( } private fun loadStates(refs: Collection): Collection> { - return if (refs.isNotEmpty()) - queryBy(QueryCriteria.VaultQueryCriteria(stateRefs = refs.toList())).states - else emptySet() + val states = mutableListOf>() + if (refs.isNotEmpty()) { + val refsList = refs.toList() + val pageSize = PageSpecification().pageSize + (0..refsList.size / pageSize).forEach { + val offset = it * pageSize + val limit = minOf(offset + pageSize, refsList.size) + val page = queryBy(QueryCriteria.VaultQueryCriteria(stateRefs = refsList.subList(offset, limit))).states + states.addAll(page) + } + } + return states } private fun processAndNotify(updates: List>) { diff --git a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt index b0c367d6e7..f2354cb170 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt @@ -5,7 +5,9 @@ import com.nhaarman.mockito_kotlin.argThat import com.nhaarman.mockito_kotlin.doNothing import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.* +import net.corda.core.crypto.Crypto import net.corda.core.crypto.NullKeys +import net.corda.core.crypto.SignatureMetadata import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.* import net.corda.core.internal.NotaryChangeTransactionBuilder @@ -34,8 +36,7 @@ import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.vault.VaultFiller import net.corda.testing.node.MockServices import net.corda.testing.node.makeTestIdentityService -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.* import org.junit.After import org.junit.Before import org.junit.Rule @@ -51,7 +52,7 @@ import kotlin.test.assertTrue class NodeVaultServiceTest { private companion object { - val cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName) + val cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName, "net.corda.testing.internal.vault") val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10) val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1) val bankOfCorda = TestIdentity(BOC_NAME) @@ -715,4 +716,21 @@ class NodeVaultServiceTest { } assertThat(recordedStates).isEqualTo(coins.size) } + + @Test + fun `record a transaction with number of inputs greater than vault page size`() { + val notary = dummyNotary + val issuerKey = notary.keyPair + val signatureMetadata = SignatureMetadata(services.myInfo.platformVersion, Crypto.findSignatureScheme(issuerKey.public).schemeNumberID) + val states = database.transaction { + vaultFiller.fillWithSomeTestLinearStates(PageSpecification().pageSize + 1).states + } + + database.transaction { + val statesExitingTx = TransactionBuilder(notary.party).withItems(*states.toList().toTypedArray()).addCommand(dummyCommand()) + val signedStatesExitingTx = services.signInitialTransaction(statesExitingTx).withAdditionalSignature(issuerKey, signatureMetadata) + + assertThatCode { services.recordTransactions(signedStatesExitingTx) }.doesNotThrowAnyException() + } + } }