mirror of
https://github.com/corda/corda.git
synced 2025-04-07 11:27:01 +00:00
Replaced programRef in ContractState with a simple reference to contract
This commit is contained in:
parent
e6ce1e5b76
commit
1344bfd6bb
@ -8,6 +8,7 @@
|
||||
|
||||
package contracts.isolated
|
||||
|
||||
import core.*
|
||||
import core.Contract
|
||||
import core.ContractState
|
||||
import core.TransactionForVerification
|
||||
@ -15,17 +16,20 @@ import core.crypto.SecureHash
|
||||
|
||||
// The dummy contract doesn't do anything useful. It exists for testing purposes.
|
||||
|
||||
val ANOTHER_DUMMY_PROGRAM_ID = SecureHash.sha256("dummy")
|
||||
val ANOTHER_DUMMY_PROGRAM_ID = AnotherDummyContract()
|
||||
|
||||
class AnotherDummyContract : Contract {
|
||||
class State : ContractState {
|
||||
override val programRef: SecureHash = ANOTHER_DUMMY_PROGRAM_ID
|
||||
data class State(val foo: Int) : ContractState {
|
||||
override val contract = ANOTHER_DUMMY_PROGRAM_ID
|
||||
}
|
||||
|
||||
override fun verify(tx: TransactionForVerification) {
|
||||
requireThat {
|
||||
"justice will be served" by false
|
||||
}
|
||||
// Always accepts.
|
||||
}
|
||||
|
||||
// The "empty contract"
|
||||
override val legalContractReference: SecureHash = SecureHash.sha256("https://anotherdummy.org")
|
||||
override val legalContractReference = SecureHash.sha256("https://anotherdummy.org")
|
||||
}
|
@ -32,7 +32,8 @@ import static kotlin.collections.CollectionsKt.single;
|
||||
*
|
||||
*/
|
||||
public class JavaCommercialPaper implements Contract {
|
||||
public static SecureHash JCP_PROGRAM_ID = SecureHash.sha256("java commercial paper (this should be a bytecode hash)");
|
||||
//public static SecureHash JCP_PROGRAM_ID = SecureHash.sha256("java commercial paper (this should be a bytecode hash)");
|
||||
public static Contract JCP_PROGRAM_ID = new JavaCommercialPaper();
|
||||
|
||||
public static class State implements ContractState, ICommercialPaperState {
|
||||
private PartyReference issuance;
|
||||
@ -87,8 +88,9 @@ public class JavaCommercialPaper implements Contract {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SecureHash getProgramRef() {
|
||||
return SecureHash.Companion.sha256("java commercial paper (this should be a bytecode hash)");
|
||||
public Contract getContract() {
|
||||
return JCP_PROGRAM_ID;
|
||||
//return SecureHash.Companion.sha256("java commercial paper (this should be a bytecode hash)");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,7 +22,8 @@ import java.util.*
|
||||
//
|
||||
|
||||
// Just a fake program identifier for now. In a real system it could be, for instance, the hash of the program bytecode.
|
||||
val CASH_PROGRAM_ID = SecureHash.sha256("cash")
|
||||
val CASH_PROGRAM_ID = Cash()
|
||||
//SecureHash.sha256("cash")
|
||||
|
||||
class InsufficientBalanceException(val amountMissing: Amount) : Exception()
|
||||
|
||||
@ -62,7 +63,7 @@ class Cash : Contract {
|
||||
/** There must be a MoveCommand signed by this key to claim the amount */
|
||||
override val owner: PublicKey
|
||||
) : OwnableState {
|
||||
override val programRef = CASH_PROGRAM_ID
|
||||
override val contract = CASH_PROGRAM_ID
|
||||
override fun toString() = "${Emoji.bagOfCash}Cash($amount at $deposit owned by ${owner.toStringShort()})"
|
||||
|
||||
override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner))
|
||||
|
@ -38,7 +38,7 @@ import java.time.Instant
|
||||
* to do this in the Apache BVal project).
|
||||
*/
|
||||
|
||||
val CP_PROGRAM_ID = SecureHash.sha256("replace-me-later-with-bytecode-hash")
|
||||
val CP_PROGRAM_ID = CommercialPaper()
|
||||
|
||||
// TODO: Generalise the notion of an owned instrument into a superclass/supercontract. Consider composition vs inheritance.
|
||||
class CommercialPaper : Contract {
|
||||
@ -51,7 +51,7 @@ class CommercialPaper : Contract {
|
||||
val faceValue: Amount,
|
||||
val maturityDate: Instant
|
||||
) : OwnableState, ICommercialPaperState {
|
||||
override val programRef = CP_PROGRAM_ID
|
||||
override val contract = CP_PROGRAM_ID
|
||||
|
||||
fun withoutOwner() = copy(owner = NullPublicKey)
|
||||
override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner))
|
||||
|
@ -15,7 +15,7 @@ import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
|
||||
val CROWDFUND_PROGRAM_ID = SecureHash.sha256("crowdsourcing")
|
||||
val CROWDFUND_PROGRAM_ID = CrowdFund()
|
||||
|
||||
/**
|
||||
* This is a basic crowd funding contract. It allows a party to create a funding opportunity, then for others to
|
||||
@ -57,7 +57,7 @@ class CrowdFund : Contract {
|
||||
val closed: Boolean = false,
|
||||
val pledges: List<Pledge> = ArrayList()
|
||||
) : ContractState {
|
||||
override val programRef = CROWDFUND_PROGRAM_ID
|
||||
override val contract = CROWDFUND_PROGRAM_ID
|
||||
|
||||
val pledgedAmount: Amount get() = pledges.map { it.amount }.sumOrZero(campaign.target.currency)
|
||||
}
|
||||
|
@ -15,11 +15,11 @@ import core.crypto.SecureHash
|
||||
|
||||
// The dummy contract doesn't do anything useful. It exists for testing purposes.
|
||||
|
||||
val DUMMY_PROGRAM_ID = SecureHash.sha256("dummy")
|
||||
val DUMMY_PROGRAM_ID = DummyContract()
|
||||
|
||||
class DummyContract : Contract {
|
||||
class State : ContractState {
|
||||
override val programRef: SecureHash = DUMMY_PROGRAM_ID
|
||||
override val contract = DUMMY_PROGRAM_ID
|
||||
}
|
||||
|
||||
override fun verify(tx: TransactionForVerification) {
|
||||
|
@ -18,7 +18,7 @@ import java.math.RoundingMode
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
|
||||
val IRS_PROGRAM_ID = SecureHash.sha256("replace-me-later-with-bytecode-hash-of-irs-code")
|
||||
val IRS_PROGRAM_ID = InterestRateSwap()
|
||||
|
||||
// This is a placeholder for some types that we haven't identified exactly what they are just yet for things still in discussion
|
||||
open class UnknownType()
|
||||
@ -349,7 +349,7 @@ class InterestRateSwap() : Contract {
|
||||
val calculation: Calculation,
|
||||
val common: Common
|
||||
) : ContractState {
|
||||
override val programRef = IRS_PROGRAM_ID
|
||||
override val contract = IRS_PROGRAM_ID
|
||||
|
||||
/**
|
||||
* For evaluating arbitrary java on the platform
|
||||
|
@ -32,11 +32,9 @@ interface NamedByHash {
|
||||
*/
|
||||
interface ContractState {
|
||||
/**
|
||||
* Refers to a bytecode program that has previously been published to the network. This contract program
|
||||
* will be executed any time this state is used in an input. It must accept in order for the
|
||||
* transaction to proceed.
|
||||
* Contract by which the state belongs
|
||||
*/
|
||||
val programRef: SecureHash
|
||||
val contract: Contract
|
||||
}
|
||||
|
||||
interface OwnableState : ContractState {
|
||||
@ -144,19 +142,6 @@ interface Contract {
|
||||
val legalContractReference: SecureHash
|
||||
}
|
||||
|
||||
/** A contract factory knows how to lazily load and instantiate contract objects. */
|
||||
interface ContractFactory {
|
||||
/**
|
||||
* Loads, instantiates and returns a contract object from its class bytecodes, given the hash of that bytecode.
|
||||
*
|
||||
* @throws UnknownContractException if the hash doesn't map to any known contract.
|
||||
* @throws ClassCastException if the hash mapped to a contract, but it was not of type T
|
||||
*/
|
||||
operator fun <T : Contract> get(hash: SecureHash): T
|
||||
}
|
||||
|
||||
class UnknownContractException : Exception()
|
||||
|
||||
/**
|
||||
* An attachment is a ZIP (or an optionally signed JAR) that contains one or more files. Attachments are meant to
|
||||
* contain public static data which can be referenced from transactions and utilised from contracts. Good examples
|
||||
|
@ -28,7 +28,7 @@ class TransactionGroup(val transactions: Set<LedgerTransaction>, val nonVerified
|
||||
/**
|
||||
* Verifies the group and returns the set of resolved transactions.
|
||||
*/
|
||||
fun verify(programMap: ContractFactory): Set<TransactionForVerification> {
|
||||
fun verify(): Set<TransactionForVerification> {
|
||||
// Check that every input can be resolved to an output.
|
||||
// Check that no output is referenced by more than one input.
|
||||
// Cycles should be impossible due to the use of hashes as pointers.
|
||||
@ -55,7 +55,7 @@ class TransactionGroup(val transactions: Set<LedgerTransaction>, val nonVerified
|
||||
}
|
||||
|
||||
for (tx in resolved)
|
||||
tx.verify(programMap)
|
||||
tx.verify()
|
||||
return resolved
|
||||
}
|
||||
|
||||
@ -79,13 +79,11 @@ data class TransactionForVerification(val inStates: List<ContractState>,
|
||||
* @throws IllegalStateException if a state refers to an unknown contract.
|
||||
*/
|
||||
@Throws(TransactionVerificationException::class, IllegalStateException::class)
|
||||
fun verify(programMap: ContractFactory) {
|
||||
fun verify() {
|
||||
// For each input and output state, locate the program to run. Then execute the verification function. If any
|
||||
// throws an exception, the entire transaction is invalid.
|
||||
val programHashes = (inStates.map { it.programRef } + outStates.map { it.programRef }).toSet()
|
||||
for (hash in programHashes) {
|
||||
// TODO: Change this interface to ensure that attachment JARs are put on the classpath before execution.
|
||||
val program: Contract = programMap[hash]
|
||||
val programs = (inStates.map { it.contract } + outStates.map { it.contract }).toSet()
|
||||
for (program in programs) {
|
||||
try {
|
||||
program.verify(this)
|
||||
} catch(e: Throwable) {
|
||||
|
@ -16,8 +16,7 @@ import com.esotericsoftware.kryo.Serializer
|
||||
import com.esotericsoftware.kryo.io.Input
|
||||
import com.esotericsoftware.kryo.io.Output
|
||||
import com.esotericsoftware.kryo.serializers.JavaSerializer
|
||||
import core.SignedTransaction
|
||||
import core.WireTransaction
|
||||
import core.*
|
||||
import core.crypto.SecureHash
|
||||
import core.crypto.generateKeyPair
|
||||
import core.crypto.sha256
|
||||
@ -179,6 +178,19 @@ class ImmutableClassSerializer<T : Any>(val klass: KClass<T>) : Serializer<T>()
|
||||
}
|
||||
}
|
||||
|
||||
fun Kryo.useClassLoader(cl: ClassLoader, body: () -> Unit) {
|
||||
val tmp = this.classLoader
|
||||
this.classLoader = cl
|
||||
try {
|
||||
body()
|
||||
}
|
||||
finally {
|
||||
if (tmp != null) {
|
||||
this.classLoader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createKryo(k: Kryo = Kryo()): Kryo {
|
||||
return k.apply {
|
||||
// Allow any class to be deserialized (this is insecure but for prototyping we don't care)
|
||||
@ -201,6 +213,34 @@ fun createKryo(k: Kryo = Kryo()): Kryo {
|
||||
}
|
||||
})
|
||||
|
||||
register(WireTransaction::class.java, object : Serializer<WireTransaction>() {
|
||||
override fun write(kryo: Kryo, output: Output, obj: WireTransaction) {
|
||||
|
||||
kryo.writeClassAndObject( output, obj.inputs )
|
||||
kryo.writeClassAndObject( output, obj.attachments )
|
||||
|
||||
kryo.writeClassAndObject( output, obj.outputs )
|
||||
kryo.writeClassAndObject( output, obj.commands )
|
||||
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<WireTransaction>): WireTransaction {
|
||||
var inputs = kryo.readClassAndObject( input ) as List<StateRef>
|
||||
var attachments = kryo.readClassAndObject( input ) as List<SecureHash>
|
||||
|
||||
// had we access to AttachmentStorage here, a ClassLoader could be created
|
||||
|
||||
// val customClassLoader = createClassLoader( attachments )
|
||||
// kryo.useClassLoader(customClassLoader) {
|
||||
|
||||
var outputs = kryo.readClassAndObject(input) as List<ContractState>
|
||||
var commands = kryo.readClassAndObject(input) as List<Command>
|
||||
|
||||
return WireTransaction(inputs, attachments, outputs, commands)
|
||||
// }
|
||||
}
|
||||
})
|
||||
|
||||
// Some things where the JRE provides an efficient custom serialisation.
|
||||
val ser = JavaSerializer()
|
||||
val keyPair = generateKeyPair()
|
||||
|
@ -66,22 +66,6 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
|
||||
val legallyIdentifableAddress: LegallyIdentifiableNode get() = LegallyIdentifiableNode(net.myAddress, storage.myLegalIdentity)
|
||||
|
||||
// TODO: This will be obsoleted by "PLT-12: Basic module/sandbox system for contracts"
|
||||
protected val contractFactory = object : ContractFactory {
|
||||
private val contracts = mapOf(
|
||||
CASH_PROGRAM_ID to Cash::class.java,
|
||||
CP_PROGRAM_ID to CommercialPaper::class.java,
|
||||
CROWDFUND_PROGRAM_ID to CrowdFund::class.java,
|
||||
DUMMY_PROGRAM_ID to DummyContract::class.java
|
||||
)
|
||||
|
||||
override fun <T : Contract> get(hash: SecureHash): T {
|
||||
val c = contracts[hash] ?: throw UnknownContractException()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return c.newInstance() as T
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var storage: StorageService
|
||||
lateinit var smm: StateMachineManager
|
||||
lateinit var wallet: WalletService
|
||||
@ -147,12 +131,11 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
val attachments = makeAttachmentStorage(dir)
|
||||
_servicesThatAcceptUploads += attachments
|
||||
val (identity, keypair) = obtainKeyPair(dir)
|
||||
return constructStorageService(attachments, keypair, identity, contractFactory)
|
||||
return constructStorageService(attachments, keypair, identity)
|
||||
}
|
||||
|
||||
protected open fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party,
|
||||
contractFactory: ContractFactory) =
|
||||
StorageServiceImpl(attachments, contractFactory, keypair, identity)
|
||||
protected open fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party) =
|
||||
StorageServiceImpl(attachments, keypair, identity)
|
||||
|
||||
private fun obtainKeyPair(dir: Path): Pair<Party, KeyPair> {
|
||||
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that
|
||||
|
@ -6,6 +6,8 @@ import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
import java.security.AccessControlContext
|
||||
import java.security.ProtectionDomain
|
||||
import java.util.*
|
||||
import java.util.jar.JarEntry
|
||||
|
||||
@ -28,6 +30,10 @@ class ClassLoader private constructor(val tmpFiles: List<File> )
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadClass(name: String?, resolve: Boolean): Class<*>? {
|
||||
return super.loadClass(name, resolve)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(streams: List<Attachment>) : ClassLoader {
|
||||
|
||||
|
@ -116,11 +116,6 @@ interface StorageService {
|
||||
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
|
||||
val attachments: AttachmentStorage
|
||||
|
||||
/**
|
||||
* A map of program hash->contract class type, used for verification.
|
||||
*/
|
||||
val contractPrograms: ContractFactory
|
||||
|
||||
/**
|
||||
* Returns the legal identity that this node is configured with. Assumed to be initialised when the node is
|
||||
* first installed.
|
||||
@ -186,6 +181,6 @@ interface ServiceHub {
|
||||
storageService.validatedTransactions[it.txhash] ?: throw TransactionResolutionException(it.txhash)
|
||||
}
|
||||
val ltxns = dependencies.map { it.verifyToLedgerTransaction(identityService, storageService.attachments) }
|
||||
TransactionGroup(setOf(ltx), ltxns.toSet()).verify(storageService.contractPrograms)
|
||||
TransactionGroup(setOf(ltx), ltxns.toSet()).verify()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package core.node.services
|
||||
|
||||
import core.ContractFactory
|
||||
import core.Party
|
||||
import core.SignedTransaction
|
||||
import core.crypto.SecureHash
|
||||
@ -10,7 +9,6 @@ import java.security.KeyPair
|
||||
import java.util.*
|
||||
|
||||
open class StorageServiceImpl(attachments: AttachmentStorage,
|
||||
contractFactory: ContractFactory,
|
||||
keypair: KeyPair,
|
||||
identity: Party = Party("Unit test party", keypair.public),
|
||||
// This parameter is for unit tests that want to observe operation details.
|
||||
@ -39,7 +37,6 @@ open class StorageServiceImpl(attachments: AttachmentStorage,
|
||||
get() = getMapOriginal("state-machines")
|
||||
|
||||
override val attachments: AttachmentStorage = attachments
|
||||
override val contractPrograms = contractFactory
|
||||
override val myLegalIdentity = identity
|
||||
override val myLegalIdentityKey = keypair
|
||||
}
|
@ -66,7 +66,7 @@ class ResolveTransactionsProtocol(private val txHashes: Set<SecureHash>,
|
||||
}
|
||||
|
||||
// Run all the contracts and throw an exception if any of them reject.
|
||||
TransactionGroup(toVerify, alreadyVerified).verify(serviceHub.storageService.contractPrograms)
|
||||
TransactionGroup(toVerify, alreadyVerified).verify()
|
||||
|
||||
// Now write all the transactions we just validated back to the database for next time, including
|
||||
// signatures so we can serve up these transactions to other peers when we, in turn, send one that
|
||||
|
@ -219,11 +219,11 @@ class CommercialPaperTestsGeneric {
|
||||
val validRedemption = makeRedeemTX(TEST_TX_TIME + 31.days)
|
||||
|
||||
val e = assertFailsWith(TransactionVerificationException::class) {
|
||||
TransactionGroup(setOf(issueTX, moveTX, tooEarlyRedemption), setOf(corpWalletTX, alicesWalletTX)).verify(MockContractFactory)
|
||||
TransactionGroup(setOf(issueTX, moveTX, tooEarlyRedemption), setOf(corpWalletTX, alicesWalletTX)).verify()
|
||||
}
|
||||
assertTrue(e.cause!!.message!!.contains("paper must have matured"))
|
||||
|
||||
TransactionGroup(setOf(issueTX, moveTX, validRedemption), setOf(corpWalletTX, alicesWalletTX)).verify(MockContractFactory)
|
||||
TransactionGroup(setOf(issueTX, moveTX, validRedemption), setOf(corpWalletTX, alicesWalletTX)).verify()
|
||||
}
|
||||
|
||||
// Generate a trade lifecycle with various parameters.
|
||||
|
@ -160,11 +160,11 @@ class CrowdFundTests {
|
||||
val validClose = makeFundedTX(TEST_TX_TIME + 8.days)
|
||||
|
||||
val e = assertFailsWith(TransactionVerificationException::class) {
|
||||
TransactionGroup(setOf(registerTX, pledgeTX, tooEarlyClose), setOf(miniCorpWalletTx, aliceWalletTX)).verify(MockContractFactory)
|
||||
TransactionGroup(setOf(registerTX, pledgeTX, tooEarlyClose), setOf(miniCorpWalletTx, aliceWalletTX)).verify()
|
||||
}
|
||||
assertTrue(e.cause!!.message!!.contains("the closing date has past"))
|
||||
|
||||
// This verification passes
|
||||
TransactionGroup(setOf(registerTX, pledgeTX, validClose), setOf(aliceWalletTX)).verify(MockContractFactory)
|
||||
TransactionGroup(setOf(registerTX, pledgeTX, validClose), setOf(aliceWalletTX)).verify()
|
||||
}
|
||||
}
|
@ -116,15 +116,7 @@ class MockAttachmentStorage : AttachmentStorage {
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
class MockStorageService : StorageServiceImpl(MockAttachmentStorage(), MockContractFactory, generateKeyPair()) {
|
||||
}
|
||||
|
||||
object MockContractFactory : ContractFactory {
|
||||
override operator fun <T : Contract> get(hash: SecureHash): T {
|
||||
val clazz = TEST_PROGRAM_MAP[hash] ?: throw UnknownContractException()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return clazz.newInstance() as T
|
||||
}
|
||||
class MockStorageService : StorageServiceImpl(MockAttachmentStorage(), generateKeyPair()) {
|
||||
}
|
||||
|
||||
class MockServices(
|
||||
|
@ -153,6 +153,6 @@ class TransactionGroupTests {
|
||||
|
||||
// Now go through the conversion -> verification path with them.
|
||||
val ltxns = signedTxns.map { it.verifyToLedgerTransaction(MockIdentityService, MockStorageService().attachments) }.toSet()
|
||||
TransactionGroup(ltxns, emptySet()).verify(MockContractFactory)
|
||||
TransactionGroup(ltxns, emptySet()).verify()
|
||||
}
|
||||
}
|
@ -195,10 +195,9 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
||||
return net.createNode(null) { path, config, net, tsNode ->
|
||||
object : MockNetwork.MockNode(path, config, net, tsNode) {
|
||||
// That constructs the storage service object in a customised way ...
|
||||
override fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party,
|
||||
contractFactory: ContractFactory): StorageServiceImpl {
|
||||
override fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party): StorageServiceImpl {
|
||||
// To use RecordingMaps instead of ordinary HashMaps.
|
||||
return StorageServiceImpl(attachments, contractFactory, keypair, identity, { tableName -> name })
|
||||
return StorageServiceImpl(attachments, keypair, identity, { tableName -> name })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,4 +173,9 @@ class ClassLoaderTests {
|
||||
assertNotNull(state2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `white list serialization`() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -74,7 +74,7 @@ val TEST_KEYS_TO_CORP_MAP: Map<PublicKey, Party> = mapOf(
|
||||
|
||||
// In a real system this would be a persistent map of hash to bytecode and we'd instantiate the object as needed inside
|
||||
// a sandbox. For unit tests we just have a hard-coded list.
|
||||
val TEST_PROGRAM_MAP: Map<SecureHash, Class<out Contract>> = mapOf(
|
||||
val TEST_PROGRAM_MAP: Map<Contract, Class<out Contract>> = mapOf(
|
||||
CASH_PROGRAM_ID to Cash::class.java,
|
||||
CP_PROGRAM_ID to CommercialPaper::class.java,
|
||||
JavaCommercialPaper.JCP_PROGRAM_ID to JavaCommercialPaper::class.java,
|
||||
@ -162,7 +162,7 @@ open class TransactionForTest : AbstractTransactionForTest() {
|
||||
protected fun run(time: Instant) {
|
||||
val cmds = commandsToAuthenticatedObjects()
|
||||
val tx = TransactionForVerification(inStates, outStates.map { it.state }, emptyList(), cmds, SecureHash.randomSHA256())
|
||||
tx.verify(MockContractFactory)
|
||||
tx.verify()
|
||||
}
|
||||
|
||||
fun accepts(time: Instant = TEST_TX_TIME) = run(time)
|
||||
@ -319,7 +319,7 @@ class TransactionGroupDSL<T : ContractState>(private val stateType: Class<T>) {
|
||||
fun verify() {
|
||||
val group = toTransactionGroup()
|
||||
try {
|
||||
group.verify(MockContractFactory)
|
||||
group.verify()
|
||||
} catch (e: TransactionVerificationException) {
|
||||
// Let the developer know the index of the transaction that failed.
|
||||
val wtx: WireTransaction = txns.find { it.id == e.tx.origHash }!!
|
||||
|
Loading…
x
Reference in New Issue
Block a user