CORDA-941 - Add Network Parameters contract implementation Whitelist (#2539)

* CORDA-941 Add Network Parameters contract implementation Whitelist

* CORDA-941 fix merge

* CORDA-941 added uploader support to Attachments and added check into the AttachmentClassloader to only allow loading attachments that were uploaded from the local cordapps folder

* CORDA-941 update api spec

* CORDA-941 address some code review changes and fix and add classloader test

* CORDA-941 fix test

* CORDA-941 address code review comments

* CORDA-941 address code review comments - use and update existing whitelist

* CORDA-941 address code review comments

* CORDA-941 fix compile error

* CORDA-941 address code review comments

* CORDA-941 removed: whitelistAllContractsForTest

* CORDA-941 removed: whitelistAllContractsForTest

* CORDA-941 add comment

* CORDA-941 remove toLedgerTransaction

* CORDA-941 add warning when node not using latest CorDapp

* CORDA-941 remove the stubbing approach for cleaning LedgerTransaction

* CORDA-941 Code review changes

* CORDA-941 Fix merge

* CORDA-941 workaround for api scanner bug

* Fixed JacksonSupportTest.
This commit is contained in:
Tudor Malene
2018-02-20 11:09:23 +00:00
committed by Katelyn Baker
parent 34e82026f3
commit 60a4bcba5b
50 changed files with 539 additions and 235 deletions

View File

@ -226,7 +226,7 @@ open class MockServices private constructor(
return NodeInfo(listOf(NetworkHostAndPort("mock.node.services", 10000)), listOf(initialIdentity.identity), 1, serial = 1L)
}
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments)
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments, networkParameters.whitelistedContractImplementations)
override val cordappProvider: CordappProvider get() = mockCordappProvider
internal fun makeVaultService(hibernateConfig: HibernateConfiguration, schemaService: SchemaService): VaultServiceInternal {

View File

@ -39,7 +39,7 @@ class NetworkMapServer(private val cacheTimeout: Duration,
private val myHostNameValue: String = "test.host.name",
vararg additionalServices: Any) : Closeable {
companion object {
private val stubNetworkParameters = NetworkParameters(1, emptyList(), 10485760, Int.MAX_VALUE, Instant.now(), 10)
private val stubNetworkParameters = NetworkParameters(1, emptyList(), 10485760, Int.MAX_VALUE, Instant.now(), 10, emptyMap())
}
private val server: Server

View File

@ -19,6 +19,7 @@ fun testNetworkParameters(
modifiedTime = modifiedTime,
maxMessageSize = maxMessageSize,
maxTransactionSize = maxTransactionSize,
epoch = epoch
epoch = epoch,
whitelistedContractImplementations = emptyMap()
)
}

View File

@ -2,6 +2,7 @@ package net.corda.testing.internal
import net.corda.core.contracts.ContractClassName
import net.corda.core.cordapp.Cordapp
import net.corda.core.internal.TEST_UPLOADER
import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.node.services.AttachmentId
import net.corda.core.node.services.AttachmentStorage
@ -11,7 +12,9 @@ import net.corda.testing.services.MockAttachmentStorage
import java.nio.file.Paths
import java.util.*
class MockCordappProvider(cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage) : CordappProviderImpl(cordappLoader, attachmentStorage) {
class MockCordappProvider(cordappLoader: CordappLoader,
attachmentStorage: AttachmentStorage,
whitelistedContractImplementations: Map<String, List<AttachmentId>>) : CordappProviderImpl(cordappLoader, attachmentStorage, whitelistedContractImplementations) {
val cordappRegistry = mutableListOf<Pair<Cordapp, AttachmentId>>()
fun addMockCordapp(contractClassName: ContractClassName, attachments: MockAttachmentStorage) {
@ -27,20 +30,21 @@ class MockCordappProvider(cordappLoader: CordappLoader, attachmentStorage: Attac
customSchemas = emptySet(),
jarPath = Paths.get("").toUri().toURL())
if (cordappRegistry.none { it.first.contractClassNames.contains(contractClassName) }) {
cordappRegistry.add(Pair(cordapp, findOrImportAttachment(contractClassName.toByteArray(), attachments)))
cordappRegistry.add(Pair(cordapp, findOrImportAttachment(listOf(contractClassName), contractClassName.toByteArray(), attachments)))
}
}
override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? = cordappRegistry.find { it.first.contractClassNames.contains(contractClassName) }?.second ?: super.getContractAttachmentID(contractClassName)
override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? = cordappRegistry.find { it.first.contractClassNames.contains(contractClassName) }?.second
?: super.getContractAttachmentID(contractClassName)
private fun findOrImportAttachment(data: ByteArray, attachments: MockAttachmentStorage): AttachmentId {
private fun findOrImportAttachment(contractClassNames: List<ContractClassName>, data: ByteArray, attachments: MockAttachmentStorage): AttachmentId {
val existingAttachment = attachments.files.filter {
Arrays.equals(it.value, data)
Arrays.equals(it.value.second, data)
}
return if (!existingAttachment.isEmpty()) {
existingAttachment.keys.first()
} else {
attachments.importAttachment(data.inputStream())
attachments.importContractAttachment(contractClassNames, TEST_UPLOADER, data.inputStream())
}
}
}

View File

@ -1,14 +1,18 @@
package net.corda.testing.services
import net.corda.core.contracts.Attachment
import net.corda.core.contracts.ContractAttachment
import net.corda.core.contracts.ContractClassName
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256
import net.corda.core.internal.AbstractAttachment
import net.corda.core.internal.UNKNOWN_UPLOADER
import net.corda.core.node.services.AttachmentId
import net.corda.core.node.services.AttachmentStorage
import net.corda.core.node.services.vault.AttachmentQueryCriteria
import net.corda.core.node.services.vault.AttachmentSort
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.nodeapi.internal.withContractsInJar
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.util.*
@ -24,31 +28,17 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
}
}
override fun importAttachment(jar: InputStream): AttachmentId {
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
require(jar !is JarInputStream)
val files = HashMap<SecureHash, Pair<Attachment, ByteArray>>()
val bytes = getBytes(jar)
override fun importAttachment(jar: InputStream): AttachmentId = importAttachment(jar, UNKNOWN_UPLOADER, null)
val sha256 = bytes.sha256()
if (!files.containsKey(sha256)) {
files[sha256] = bytes
override fun importAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId {
return withContractsInJar(jar) { contractClassNames, inputStream ->
importAttachmentInternal(inputStream, uploader, filename, contractClassNames)
}
return sha256
}
override fun importAttachment(jar: InputStream, uploader: String, filename: String): AttachmentId {
return importAttachment(jar)
}
val files = HashMap<SecureHash, ByteArray>()
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash): AbstractAttachment(dataLoader)
override fun openAttachment(id: SecureHash): Attachment? {
val f = files[id] ?: return null
return MockAttachment({f}, id)
}
override fun openAttachment(id: SecureHash): Attachment? = files[id]?.first
override fun queryAttachments(criteria: AttachmentQueryCriteria, sorting: AttachmentSort?): List<AttachmentId> {
throw NotImplementedError("Querying for attachments not implemented")
@ -56,18 +46,33 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
override fun hasAttachment(attachmentId: AttachmentId) = files.containsKey(attachmentId)
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> {
val bytes = getBytes(jar)
return Pair(bytes.sha256(), bytes)
}
override fun importOrGetAttachment(jar: InputStream): AttachmentId {
try {
return importAttachment(jar)
}
catch (faee: java.nio.file.FileAlreadyExistsException) {
} catch (faee: java.nio.file.FileAlreadyExistsException) {
return AttachmentId.parse(faee.message!!)
}
}
fun importContractAttachment(contractClassNames: List<ContractClassName>, uploader: String, jar: InputStream): AttachmentId = importAttachmentInternal(jar, uploader, null, contractClassNames)
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> = getBytes(jar).let { bytes -> Pair(bytes.sha256(), bytes) }
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash): AbstractAttachment(dataLoader)
private fun importAttachmentInternal(jar: InputStream, uploader: String, filename: String?, contractClassNames: List<ContractClassName>? = null): AttachmentId {
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
require(jar !is JarInputStream)
val bytes = getBytes(jar)
val sha256 = bytes.sha256()
if (sha256 !in files.keys) {
val baseAttachment = MockAttachment({ bytes }, sha256)
val attachment = if (contractClassNames == null || contractClassNames.isEmpty()) baseAttachment else ContractAttachment(baseAttachment, contractClassNames.first(), contractClassNames.toSet(), uploader)
files[sha256] = Pair(attachment, bytes)
}
return sha256
}
}