ContractState now references contract by class name (#1407)

* ContractState's contract type has been moved to TransactionState and is now a string representing the class name of the contract class to allow classloading of arbitrary contracts from custom classloaders.

* Upgraded isolated JAR to new version.
This commit is contained in:
Clinton
2017-09-11 16:44:18 +01:00
committed by GitHub
parent 10c4d46b97
commit bc6628a072
81 changed files with 669 additions and 685 deletions

View File

@ -23,6 +23,7 @@ import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.minClusterSize
import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.contracts.DummyContract
import net.corda.testing.dummyCommand
import net.corda.testing.node.MockNetwork
@ -72,7 +73,7 @@ class BFTNotaryServiceTests {
val notary = bftNotaryCluster(minClusterSize(1), true) // This true adds a sleep to expose the race.
val f = node.run {
val trivialTx = signInitialTransaction(notary) {
addOutputState(DummyContract.SingleOwnerState(owner = info.legalIdentity))
addOutputState(DummyContract.SingleOwnerState(owner = info.legalIdentity), DUMMY_PROGRAM_ID)
}
// Create a new consensus while the redundant replica is sleeping:
services.startFlow(NotaryFlow.Client(trivialTx)).resultFuture
@ -96,7 +97,7 @@ class BFTNotaryServiceTests {
val notary = bftNotaryCluster(clusterSize)
node.run {
val issueTx = signInitialTransaction(notary) {
addOutputState(DummyContract.SingleOwnerState(owner = info.legalIdentity))
addOutputState(DummyContract.SingleOwnerState(owner = info.legalIdentity), DUMMY_PROGRAM_ID)
}
database.transaction {
services.recordTransactions(issueTx)

View File

@ -13,6 +13,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.getX500Name
import net.corda.node.internal.AbstractNode
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.contracts.DummyContract
import net.corda.testing.dummyCommand
import net.corda.testing.node.NodeBasedTest
@ -45,7 +46,7 @@ class RaftNotaryServiceTests : NodeBasedTest() {
val secondSpendBuilder = TransactionBuilder(notaryParty).withItems(inputState).run {
val dummyState = DummyContract.SingleOwnerState(0, bankA.info.legalIdentity)
addOutputState(dummyState)
addOutputState(dummyState, DUMMY_PROGRAM_ID)
addCommand(dummyCommand(bankA.services.legalIdentityKey))
this
}

View File

@ -10,6 +10,7 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.testing.BOB
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.aliceBobAndNotary
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.contracts.DummyState
import net.corda.testing.driver.driver
import net.corda.testing.dummyCommand
@ -26,7 +27,7 @@ class LargeTransactionsTest {
@Suspendable
override fun call() {
val tx = TransactionBuilder(notary = DUMMY_NOTARY)
.addOutputState(DummyState())
.addOutputState(DummyState(), DUMMY_PROGRAM_ID)
.addCommand(dummyCommand(serviceHub.legalIdentityKey))
.addAttachment(hash1)
.addAttachment(hash2)

View File

@ -1,13 +1,7 @@
package net.corda.test.node
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.Command
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.Contract
import net.corda.core.contracts.LinearState
import net.corda.core.contracts.UniqueIdentifier
import net.corda.core.contracts.requireSingleCommand
import net.corda.core.contracts.requireThat
import net.corda.core.contracts.*
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC
@ -71,7 +65,6 @@ fun isQuasarAgentSpecified(): Boolean {
data class Message(val value: String)
data class MessageState(val message: Message, val by: Party, override val linearId: UniqueIdentifier = UniqueIdentifier()) : LinearState, QueryableState {
override val contract = MessageContract()
override val participants: List<AbstractParty> = listOf(by)
override fun generateMappedObject(schema: MappedSchema): PersistentState {
@ -104,6 +97,8 @@ object MessageSchemaV1 : MappedSchema(
) : PersistentState()
}
val MESSAGE_CONTRACT_PROGRAM_ID = "net.corda.test.node.MessageContract"
open class MessageContract : Contract {
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<Commands.Send>()
@ -146,7 +141,7 @@ class SendMessageFlow(private val message: Message) : FlowLogic<SignedTransactio
val messageState = MessageState(message = message, by = serviceHub.myInfo.legalIdentity)
val txCommand = Command(MessageContract.Commands.Send(), messageState.participants.map { it.owningKey })
val txBuilder = TransactionBuilder(notary).withItems(messageState, txCommand)
val txBuilder = TransactionBuilder(notary).withItems(StateAndContract(messageState, MESSAGE_CONTRACT_PROGRAM_ID), txCommand)
progressTracker.currentStep = VERIFYING_TRANSACTION
txBuilder.toWireTransaction().toLedgerTransaction(serviceHub).verify()

View File

@ -48,4 +48,4 @@ class ContractUpgradeServiceImpl : ContractUpgradeService {
override fun removeAuthorisedContractUpgrade(ref: StateRef) {
authorisedUpgrade.remove(ref.toString())
}
}
}

View File

@ -32,10 +32,7 @@ import net.corda.core.utilities.unwrap
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.finance.contracts.CommercialPaper
import net.corda.finance.contracts.asset.CASH
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.contracts.asset.`issued by`
import net.corda.finance.contracts.asset.`owned by`
import net.corda.finance.contracts.asset.*
import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
import net.corda.finance.flows.TwoPartyTradeFlow.Seller
import net.corda.node.internal.AbstractNode
@ -690,8 +687,8 @@ class TwoPartyTradeFlowTests {
// wants to sell to Bob.
val eb1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
// Issued money to itself.
output("elbonian money 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` interimOwner }
output("elbonian money 2", notary = notary) { 1000.DOLLARS.CASH `issued by` issuer `owned by` interimOwner }
output(CASH_PROGRAM_ID, "elbonian money 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` interimOwner }
output(CASH_PROGRAM_ID, "elbonian money 2", notary = notary) { 1000.DOLLARS.CASH `issued by` issuer `owned by` interimOwner }
if (!withError) {
command(issuer.party.owningKey) { Cash.Commands.Issue() }
} else {
@ -709,15 +706,15 @@ class TwoPartyTradeFlowTests {
// Bob gets some cash onto the ledger from BoE
val bc1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
input("elbonian money 1")
output("bob cash 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` owner }
output(CASH_PROGRAM_ID, "bob cash 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` owner }
command(interimOwner.owningKey) { Cash.Commands.Move() }
this.verifies()
}
val bc2 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
input("elbonian money 2")
output("bob cash 2", notary = notary) { 300.DOLLARS.CASH `issued by` issuer `owned by` owner }
output(notary = notary) { 700.DOLLARS.CASH `issued by` issuer `owned by` interimOwner } // Change output.
output(CASH_PROGRAM_ID, "bob cash 2", notary = notary) { 300.DOLLARS.CASH `issued by` issuer `owned by` owner }
output(CASH_PROGRAM_ID, notary = notary) { 700.DOLLARS.CASH `issued by` issuer `owned by` interimOwner } // Change output.
command(interimOwner.owningKey) { Cash.Commands.Move() }
this.verifies()
}
@ -734,7 +731,7 @@ class TwoPartyTradeFlowTests {
attachmentID: SecureHash?,
notary: Party): Pair<Vault<ContractState>, List<WireTransaction>> {
val ap = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
output("alice's paper", notary = notary) {
output(CommercialPaper.CP_PROGRAM_ID, "alice's paper", notary = notary) {
CommercialPaper.State(issuer, owner, amount, TEST_TX_TIME + 7.days)
}
command(issuer.party.owningKey) { CommercialPaper.Commands.Issue() }

View File

@ -15,6 +15,7 @@ import net.corda.node.internal.AbstractNode
import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.contracts.DummyContract
import net.corda.testing.dummyCommand
import net.corda.testing.getTestPartyAndCertificate
@ -142,9 +143,9 @@ class NotaryChangeTests {
val tx = TransactionBuilder(null).apply {
addCommand(Command(DummyContract.Commands.Create(), owner.party.owningKey))
addOutputState(stateA, notary, encumbrance = 2) // Encumbered by stateB
addOutputState(stateC, notary)
addOutputState(stateB, notary, encumbrance = 1) // Encumbered by stateC
addOutputState(stateA, DUMMY_PROGRAM_ID, notary, encumbrance = 2) // Encumbered by stateB
addOutputState(stateC, DUMMY_PROGRAM_ID, notary)
addOutputState(stateB, DUMMY_PROGRAM_ID, notary, encumbrance = 1) // Encumbered by stateC
}
val stx = node.services.signInitialTransaction(tx)
node.services.recordTransactions(stx)
@ -170,7 +171,7 @@ fun issueState(node: AbstractNode, notaryNode: AbstractNode): StateAndRef<*> {
fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode, notaryNode: AbstractNode): StateAndRef<DummyContract.MultiOwnerState> {
val state = TransactionState(DummyContract.MultiOwnerState(0,
listOf(nodeA.info.legalIdentity, nodeB.info.legalIdentity)), notaryNode.info.notaryIdentity)
listOf(nodeA.info.legalIdentity, nodeB.info.legalIdentity)), DUMMY_PROGRAM_ID, notaryNode.info.notaryIdentity)
val tx = TransactionBuilder(notary = notaryNode.info.notaryIdentity).withItems(state, dummyCommand())
val signedByA = nodeA.services.signInitialTransaction(tx)
val signedByAB = nodeB.services.addSignature(signedByA)

View File

@ -23,6 +23,7 @@ import net.corda.node.utilities.AffinityExecutor
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.testing.*
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockKeyManagementService
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
@ -131,9 +132,6 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? {
return ScheduledActivity(flowLogicRef, instant)
}
override val contract: Contract
get() = throw UnsupportedOperationException()
}
class TestFlowLogic(val increment: Int = 1) : FlowLogic<Unit>() {
@ -282,7 +280,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
val freshKey = services.keyManagementService.freshKey()
val state = TestState(FlowLogicRefFactoryImpl.createForRPC(TestFlowLogic::class.java, increment), instant, services.myInfo.legalIdentity)
val builder = TransactionBuilder(null).apply {
addOutputState(state, DUMMY_NOTARY)
addOutputState(state, DUMMY_PROGRAM_ID, DUMMY_NOTARY)
addCommand(Command(), freshKey)
}
val usefulTX = services.signInitialTransaction(builder, freshKey)

View File

@ -21,6 +21,7 @@ import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.contracts.DummyContract
import net.corda.testing.dummyCommand
import net.corda.testing.node.MockNetwork
@ -46,8 +47,7 @@ class ScheduledFlowTests {
val source: Party,
val destination: Party,
val processed: Boolean = false,
override val linearId: UniqueIdentifier = UniqueIdentifier(),
override val contract: Contract = DummyContract()) : SchedulableState, LinearState {
override val linearId: UniqueIdentifier = UniqueIdentifier()) : SchedulableState, LinearState {
override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? {
if (!processed) {
val logicRef = flowLogicRefFactory.create(ScheduledFlow::class.java, thisStateRef)
@ -68,7 +68,7 @@ class ScheduledFlowTests {
val notary = serviceHub.networkMapCache.getAnyNotary()
val builder = TransactionBuilder(notary)
.addOutputState(scheduledState)
.addOutputState(scheduledState, DUMMY_PROGRAM_ID)
.addCommand(dummyCommand(serviceHub.legalIdentityKey))
val tx = serviceHub.signInitialTransaction(builder)
subFlow(FinalityFlow(tx, setOf(serviceHub.myInfo.legalIdentity)))
@ -90,7 +90,7 @@ class ScheduledFlowTests {
val newStateOutput = scheduledState.copy(processed = true)
val builder = TransactionBuilder(notary)
.addInputState(state)
.addOutputState(newStateOutput)
.addOutputState(newStateOutput, DUMMY_PROGRAM_ID)
.addCommand(dummyCommand(serviceHub.legalIdentityKey))
val tx = serviceHub.signInitialTransaction(builder)
subFlow(FinalityFlow(tx, setOf(scheduledState.source, scheduledState.destination)))

View File

@ -12,6 +12,7 @@ import net.corda.node.services.api.SchemaService
import net.corda.node.utilities.DatabaseTransactionManager
import net.corda.node.utilities.configureDatabase
import net.corda.testing.MEGA_CORP
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.node.MockServices.Companion.makeTestIdentityService
@ -72,9 +73,6 @@ class HibernateObserverTests {
throw UnsupportedOperationException()
}
override val contract: Contract
get() = throw UnsupportedOperationException()
override val participants: List<AbstractParty>
get() = throw UnsupportedOperationException()
}
@ -101,7 +99,7 @@ class HibernateObserverTests {
@Suppress("UNUSED_VARIABLE")
val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig)
database.transaction {
rawUpdatesPublisher.onNext(Vault.Update(emptySet(), setOf(StateAndRef(TransactionState(TestState(), MEGA_CORP), StateRef(SecureHash.sha256("dummy"), 0)))))
rawUpdatesPublisher.onNext(Vault.Update(emptySet(), setOf(StateAndRef(TransactionState(TestState(), DUMMY_PROGRAM_ID, MEGA_CORP), StateRef(SecureHash.sha256("dummy"), 0)))))
val parentRowCountResult = DatabaseTransactionManager.current().connection.prepareStatement("select count(*) from Parents").executeQuery()
parentRowCountResult.next()
val parentRows = parentRowCountResult.getInt(1)

View File

@ -31,6 +31,7 @@ import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.persistence.checkpoints
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.testing.*
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.contracts.DummyState
import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
@ -599,7 +600,7 @@ class FlowFrameworkTests {
@Test
fun `wait for transaction`() {
val ptx = TransactionBuilder(notary = notary1.info.notaryIdentity)
.addOutputState(DummyState())
.addOutputState(DummyState(), DUMMY_PROGRAM_ID)
.addCommand(dummyCommand(node1.services.legalIdentityKey))
val stx = node1.services.signInitialTransaction(ptx)
@ -614,7 +615,7 @@ class FlowFrameworkTests {
@Test
fun `committer throws exception before calling the finality flow`() {
val ptx = TransactionBuilder(notary = notary1.info.notaryIdentity)
.addOutputState(DummyState())
.addOutputState(DummyState(), DUMMY_PROGRAM_ID)
.addCommand(dummyCommand())
val stx = node1.services.signInitialTransaction(ptx)
@ -631,7 +632,7 @@ class FlowFrameworkTests {
@Test
fun `verify vault query service is tokenizable by force checkpointing within a flow`() {
val ptx = TransactionBuilder(notary = notary1.info.notaryIdentity)
.addOutputState(DummyState())
.addOutputState(DummyState(), DUMMY_PROGRAM_ID)
.addCommand(dummyCommand(node1.services.legalIdentityKey))
val stx = node1.services.signInitialTransaction(ptx)

View File

@ -231,8 +231,8 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
// Issue a linear state
val dummyIssueBuilder = TransactionBuilder(notary = DUMMY_NOTARY).apply {
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)), DUMMY_LINEAR_CONTRACT_PROGRAM_ID)
addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)), DUMMY_LINEAR_CONTRACT_PROGRAM_ID)
addCommand(dummyCommand(notaryServices.legalIdentityKey))
}
val dummyIssue = notaryServices.signInitialTransaction(dummyIssueBuilder)
@ -252,7 +252,8 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
val dummyIssue =
database.transaction { // Issue a linear state
val dummyIssueBuilder = TransactionBuilder(notary = DUMMY_NOTARY)
.addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity))).addCommand(dummyCommand(notaryServices.legalIdentityKey))
.addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)), DUMMY_LINEAR_CONTRACT_PROGRAM_ID)
.addCommand(dummyCommand(notaryServices.legalIdentityKey))
val dummyIssuePtx = notaryServices.signInitialTransaction(dummyIssueBuilder)
val dummyIssue = services.addSignature(dummyIssuePtx)
@ -266,7 +267,7 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
// Move the same state
val dummyMoveBuilder = TransactionBuilder(notary = DUMMY_NOTARY)
.addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)))
.addOutputState(DummyLinearContract.State(linearId = linearId, participants = listOf(freshIdentity)), DUMMY_LINEAR_CONTRACT_PROGRAM_ID)
.addInputState(dummyIssue.tx.outRef<LinearState>(0))
.addCommand(dummyCommand(notaryServices.legalIdentityKey))
@ -340,8 +341,8 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
// Create a txn consuming different contract types
val dummyMoveBuilder = TransactionBuilder(notary = DUMMY_NOTARY).apply {
addOutputState(DummyLinearContract.State(participants = listOf(freshIdentity)))
addOutputState(DummyDealContract.State(ref = "999", participants = listOf(freshIdentity)))
addOutputState(DummyLinearContract.State(participants = listOf(freshIdentity)), DUMMY_LINEAR_CONTRACT_PROGRAM_ID)
addOutputState(DummyDealContract.State(ref = "999", participants = listOf(freshIdentity)), DUMMY_DEAL_PROGRAM_ID)
addInputState(linearStates.first())
addInputState(deals.first())
addCommand(dummyCommand(notaryServices.legalIdentityKey))