mirror of
https://github.com/corda/corda.git
synced 2025-05-31 06:31:08 +00:00
CORDA-2334 - Net Params non-downgrade verification in transaction resolution / building. (#4351)
* Add FetchParametersFlow * No downgrade parameters in ResolveTransactionsFlow Make sure that parameters in the transaction graph are ordered (this is to prevent the downgrade attack, when the malicious notary and participants sign transaction that shouldn't be notarised otherwise). We ensure that by checking that epochs of network parameters in the transaction chain are ordered. * Addressed some minor items from RP review feedback. * Refactoring following rebase from master. * Address RP PR review comments (round 2) * Addressed a couple of minor PR review points. * Renaming of unit tests and cleanup. * Changes discusses with RP to ensure Network Param checking is applied at txn verify time + resolve order checking gated on existence of tagged NPs in txn and associated minimum platform version. * Do not fail on missing ServiceHub impl + return nothing if txn not NP tagged. * Unify HistoricNetworkParametersStorage and NetworkParametersStorageInternal * SignedDataWithCert implements NamedByHash * Cleanup * Move parameters ordering check to signed transaction resolution * Fixes after merge, address comments * Address Andrius comments
This commit is contained in:
parent
db35f73bcc
commit
f729453fee
@ -5,6 +5,7 @@ import net.corda.core.KeepForDJVM
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
@ -189,6 +190,27 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
|
||||
For details see: https://docs.corda.net/api-contract-constraints.html#contract-state-agreement
|
||||
""".trimIndent(), null)
|
||||
|
||||
|
||||
/**
|
||||
* If the network parameters associated with an input or reference state in a transaction are more recent than the network parameters of the new transaction itself.
|
||||
*/
|
||||
@KeepForDJVM
|
||||
class TransactionNetworkParameterOrderingException(txId: SecureHash, inputStateRef: StateRef, txnNetworkParameters: NetworkParameters, inputNetworkParameters: NetworkParameters)
|
||||
: TransactionVerificationException(txId, "The network parameters epoch (${txnNetworkParameters.epoch}) of this transaction " +
|
||||
"is older than the epoch (${inputNetworkParameters.epoch}) of input state: $inputStateRef", null)
|
||||
|
||||
/**
|
||||
* Thrown when the network parameters with hash: missingNetworkParametersHash is not available at this node. Usually all the parameters
|
||||
* that are in the resolution chain for transaction with txId should be fetched from peer via [FetchParametersFlow] or from network map.
|
||||
*
|
||||
* @param txId Id of the transaction that has missing parameters hash in the resolution chain
|
||||
* @param missingNetworkParametersHash Missing hash of the network parameters associated to this transaction
|
||||
*/
|
||||
@KeepForDJVM
|
||||
class MissingNetworkParametersException(txId: SecureHash, missingNetworkParametersHash: SecureHash)
|
||||
: TransactionVerificationException(txId, "Couldn't find network parameters with hash: $missingNetworkParametersHash related to this transaction: $txId", null)
|
||||
|
||||
|
||||
/** Whether the inputs or outputs list contains an encumbrance issue, see [TransactionMissingEncumbranceException]. */
|
||||
@CordaSerializable
|
||||
@KeepForDJVM
|
||||
|
@ -2,10 +2,13 @@ package net.corda.core.internal
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.DeleteForDJVM
|
||||
import net.corda.core.contracts.TransactionResolutionException
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowSession
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.StatesToRecord
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.ContractUpgradeWireTransaction
|
||||
@ -28,6 +31,8 @@ class ResolveTransactionsFlow(txHashesArg: Set<SecureHash>,
|
||||
|
||||
// Need it ordered in terms of iteration. Needs to be a variable for the check-pointing logic to work.
|
||||
private val txHashes = txHashesArg.toList()
|
||||
/** Transaction to fetch attachments for. */
|
||||
private var signedTransaction: SignedTransaction? = null
|
||||
|
||||
/**
|
||||
* Resolves and validates the dependencies of the specified [SignedTransaction]. Fetches the attachments, but does
|
||||
@ -63,9 +68,6 @@ class ResolveTransactionsFlow(txHashesArg: Set<SecureHash>,
|
||||
@CordaSerializable
|
||||
class ExcessivelyLargeTransactionGraph : FlowException()
|
||||
|
||||
/** Transaction to fetch attachments for. */
|
||||
private var signedTransaction: SignedTransaction? = null
|
||||
|
||||
// TODO: Figure out a more appropriate DOS limit here, 5000 is simply a very bad guess.
|
||||
/** The maximum number of transactions this flow will try to download before bailing out. */
|
||||
var transactionCountLimit = 5000
|
||||
@ -77,15 +79,16 @@ class ResolveTransactionsFlow(txHashesArg: Set<SecureHash>,
|
||||
@Suspendable
|
||||
@Throws(FetchDataFlow.HashNotFound::class, FetchDataFlow.IllegalTransactionRequest::class)
|
||||
override fun call() {
|
||||
val counterpartyPlatformVersion = serviceHub.networkMapCache.getNodeByLegalIdentity(otherSide.counterparty)?.platformVersion ?:
|
||||
throw FlowException("Couldn't retrieve party's ${otherSide.counterparty} platform version from NetworkMapCache")
|
||||
val counterpartyPlatformVersion = serviceHub.networkMapCache.getNodeByLegalIdentity(otherSide.counterparty)?.platformVersion
|
||||
?: throw FlowException("Couldn't retrieve party's ${otherSide.counterparty} platform version from NetworkMapCache")
|
||||
val newTxns = ArrayList<SignedTransaction>(txHashes.size)
|
||||
// Start fetching data.
|
||||
for (pageNumber in 0..(txHashes.size - 1) / RESOLUTION_PAGE_SIZE) {
|
||||
val page = page(pageNumber, RESOLUTION_PAGE_SIZE)
|
||||
|
||||
newTxns += downloadDependencies(page)
|
||||
val txsWithMissingAttachments = if (pageNumber == 0) signedTransaction?.let { newTxns + it } ?: newTxns else newTxns
|
||||
val txsWithMissingAttachments = if (pageNumber == 0) signedTransaction?.let { newTxns + it }
|
||||
?: newTxns else newTxns
|
||||
fetchMissingAttachments(txsWithMissingAttachments)
|
||||
// Fetch missing parameters flow was added in version 4. This check is needed so we don't end up with node V4 sending parameters
|
||||
// request to node V3 that doesn't know about this protocol.
|
||||
@ -160,6 +163,7 @@ class ResolveTransactionsFlow(txHashesArg: Set<SecureHash>,
|
||||
|
||||
// Add all input states and reference input states to the work queue.
|
||||
val inputHashes = downloads.flatMap { it.inputs + it.references }.map { it.txhash }
|
||||
|
||||
nextRequests.addAll(inputHashes)
|
||||
|
||||
limitCounter = limitCounter exactAdd nextRequests.size
|
||||
|
@ -157,6 +157,8 @@ data class SignedTransaction(val txBits: SerializedBytes<CoreTransaction>,
|
||||
} else {
|
||||
checkSignaturesAreValid()
|
||||
}
|
||||
// We need parameters check here, because finality flow calls stx.toLedgerTransaction() and then verify.
|
||||
resolveAndCheckNetworkParameters(services)
|
||||
return tx.toLedgerTransaction(services)
|
||||
}
|
||||
|
||||
@ -174,6 +176,7 @@ data class SignedTransaction(val txBits: SerializedBytes<CoreTransaction>,
|
||||
@DeleteForDJVM
|
||||
@Throws(SignatureException::class, AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class)
|
||||
fun verify(services: ServiceHub, checkSufficientSignatures: Boolean = true) {
|
||||
resolveAndCheckNetworkParameters(services)
|
||||
when (coreTransaction) {
|
||||
is NotaryChangeWireTransaction -> verifyNotaryChangeTransaction(services, checkSufficientSignatures)
|
||||
is ContractUpgradeWireTransaction -> verifyContractUpgradeTransaction(services, checkSufficientSignatures)
|
||||
@ -181,6 +184,22 @@ data class SignedTransaction(val txBits: SerializedBytes<CoreTransaction>,
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteForDJVM
|
||||
private fun resolveAndCheckNetworkParameters(services: ServiceHub) {
|
||||
val hashOrDefault = networkParametersHash ?: services.networkParametersService.defaultHash
|
||||
val txNetworkParameters = services.networkParametersService.lookup(hashOrDefault)
|
||||
?: throw TransactionResolutionException(id)
|
||||
val groupedInputsAndRefs = (inputs + references).groupBy { it.txhash }
|
||||
groupedInputsAndRefs.map { entry ->
|
||||
val tx = services.validatedTransactions.getTransaction(entry.key)?.coreTransaction
|
||||
?: throw TransactionResolutionException(id)
|
||||
val paramHash = tx.networkParametersHash ?: services.networkParametersService.defaultHash
|
||||
val params = services.networkParametersService.lookup(paramHash) ?: throw TransactionResolutionException(id)
|
||||
if (txNetworkParameters.epoch < params.epoch)
|
||||
throw TransactionVerificationException.TransactionNetworkParameterOrderingException(id, entry.value.first(), txNetworkParameters, params)
|
||||
}
|
||||
}
|
||||
|
||||
/** No contract code is run when verifying notary change transactions, it is sufficient to check invariants during initialisation. */
|
||||
@DeleteForDJVM
|
||||
private fun verifyNotaryChangeTransaction(services: ServiceHub, checkSufficientSignatures: Boolean) {
|
||||
|
@ -190,7 +190,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
||||
|
||||
val resolvedNetworkParameters = resolveParameters(networkParametersHash) ?: throw TransactionResolutionException(id)
|
||||
|
||||
//keep resolvedInputs lazy and resolve the inputs separately here to get Version
|
||||
// Keep resolvedInputs lazy and resolve the inputs separately here to get Version.
|
||||
val inputStateContractClassToStateRefs: Map<ContractClassName, List<StateAndRef<ContractState>>> = serializedResolvedInputs.map {
|
||||
it.toStateAndRef()
|
||||
}.groupBy { it.state.contract }
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.core.internal
|
||||
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SignableData
|
||||
import net.corda.core.crypto.SignatureMetadata
|
||||
@ -8,7 +9,6 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.NotaryInfo
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.serialization.SerializationFactory
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
@ -25,12 +25,16 @@ import net.corda.testing.node.StartedMockNode
|
||||
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
|
||||
import net.corda.testing.node.internal.cordappForClasses
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class NetworkParametersResolutionTest {
|
||||
private lateinit var defaultParams: NetworkParameters
|
||||
private lateinit var params2: NetworkParameters
|
||||
private lateinit var params3: NetworkParameters
|
||||
private val certKeyPair: CertificateAndKeyPair = createDevNetworkMapCa()
|
||||
private lateinit var mockNet: MockNetwork
|
||||
private lateinit var notaryNode: StartedMockNode
|
||||
@ -43,14 +47,16 @@ class NetworkParametersResolutionTest {
|
||||
@Before
|
||||
fun setup() {
|
||||
mockNet = MockNetwork(MockNetworkParameters(
|
||||
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, cordappForClasses(ResolveTransactionsFlowTest.TestFlow::class.java, ResolveTransactionsFlowTest.TestResponseFlow::class.java))))
|
||||
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, cordappForClasses(ResolveTransactionsFlowTest.TestFlow::class.java, ResolveTransactionsFlowTest.TestResponseFlow::class.java))))
|
||||
notaryNode = mockNet.defaultNotaryNode
|
||||
megaCorpNode = mockNet.createPartyNode(CordaX500Name("MegaCorp", "London", "GB"))
|
||||
miniCorpNode = mockNet.createPartyNode(CordaX500Name("MiniCorp", "London", "GB"))
|
||||
notaryParty = mockNet.defaultNotaryIdentity
|
||||
megaCorpParty = megaCorpNode.info.singleIdentity()
|
||||
miniCorpParty = miniCorpNode.info.singleIdentity()
|
||||
defaultParams = miniCorpNode.services.networkParameters
|
||||
params2 = testNetworkParameters(epoch = 2, minimumPlatformVersion = 3, notaries = listOf((NotaryInfo(notaryParty, true))))
|
||||
params3 = testNetworkParameters(epoch = 3, minimumPlatformVersion = 4, notaries = listOf((NotaryInfo(notaryParty, true))))
|
||||
}
|
||||
|
||||
@After
|
||||
@ -61,20 +67,18 @@ class NetworkParametersResolutionTest {
|
||||
// This function is resolving and signing WireTransaction with special parameters.
|
||||
private fun TransactionBuilder.toSignedTransactionWithParameters(parameters: NetworkParameters?, services: ServiceHub): SignedTransaction {
|
||||
val wtx = toWireTransaction(services)
|
||||
val wtxWithHash = SerializationFactory.defaultFactory.withCurrentContext(null) {
|
||||
WireTransaction(
|
||||
createComponentGroups(
|
||||
wtx.inputs,
|
||||
wtx.outputs,
|
||||
wtx.commands,
|
||||
wtx.attachments,
|
||||
wtx.notary,
|
||||
wtx.timeWindow,
|
||||
wtx.references,
|
||||
parameters?.serialize()?.hash),
|
||||
wtx.privacySalt
|
||||
)
|
||||
}
|
||||
val wtxWithHash = WireTransaction(
|
||||
createComponentGroups(
|
||||
wtx.inputs,
|
||||
wtx.outputs,
|
||||
wtx.commands,
|
||||
wtx.attachments,
|
||||
wtx.notary,
|
||||
wtx.timeWindow,
|
||||
wtx.references,
|
||||
parameters?.serialize()?.hash),
|
||||
wtx.privacySalt
|
||||
)
|
||||
val publicKey = services.myInfo.singleIdentity().owningKey
|
||||
val signatureMetadata = SignatureMetadata(services.myInfo.platformVersion, Crypto.findSignatureScheme(publicKey).schemeNumberID)
|
||||
val signableData = SignableData(wtxWithHash.id, signatureMetadata)
|
||||
@ -105,13 +109,52 @@ class NetworkParametersResolutionTest {
|
||||
return Pair(dummy1, dummy2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parameters all null`() {
|
||||
val (stx1, stx2) = makeTransactions(null, null)
|
||||
assertThat(stx1.networkParametersHash).isNull()
|
||||
assertThat(stx2.networkParametersHash).isNull()
|
||||
val p = ResolveTransactionsFlowTest.TestFlow(setOf(stx2.id), megaCorpParty)
|
||||
val future = miniCorpNode.startFlow(p)
|
||||
mockNet.runNetwork()
|
||||
future.getOrThrow()
|
||||
miniCorpNode.transaction {
|
||||
assertEquals(stx1, miniCorpNode.services.validatedTransactions.getTransaction(stx1.id))
|
||||
assertEquals(stx2, miniCorpNode.services.validatedTransactions.getTransaction(stx2.id))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `transaction chain out of order parameters`() {
|
||||
val hash2 = params2.serialize().hash
|
||||
val hash3 = params3.serialize().hash
|
||||
val (stx1, stx2) = makeTransactions(params3, params2)
|
||||
assertThat(stx1.networkParametersHash).isEqualTo(hash3)
|
||||
assertThat(stx2.networkParametersHash).isEqualTo(hash2)
|
||||
miniCorpNode.transaction {
|
||||
assertThat(miniCorpNode.services.networkParametersService.lookup(hash2)).isNull()
|
||||
assertThat(miniCorpNode.services.networkParametersService.lookup(hash3)).isNull()
|
||||
}
|
||||
val p = ResolveTransactionsFlowTest.TestFlow(setOf(stx2.id), megaCorpParty)
|
||||
val future = miniCorpNode.startFlow(p)
|
||||
mockNet.runNetwork()
|
||||
assertThatExceptionOfType(TransactionVerificationException.TransactionNetworkParameterOrderingException::class.java).isThrownBy {
|
||||
future.getOrThrow()
|
||||
}.withMessageContaining("The network parameters epoch (${params2.epoch}) of this transaction " +
|
||||
"is older than the epoch (${params3.epoch}) of input state: ${stx2.inputs.first()}")
|
||||
miniCorpNode.transaction {
|
||||
assertThat(miniCorpNode.services.validatedTransactions.getTransaction(stx1.id)).isNull()
|
||||
assertThat(miniCorpNode.services.validatedTransactions.getTransaction(stx2.id)).isNull()
|
||||
// Even though the resolution failed, we should still have downloaded the parameters to the storage.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request parameters that are not in the storage`() {
|
||||
val params1 = miniCorpNode.services.networkParameters
|
||||
val hash1 = params1.serialize().hash
|
||||
val hash1 = defaultParams.serialize().hash
|
||||
val hash2 = params2.serialize().hash
|
||||
// Create two transactions on megaCorpNode
|
||||
val (stx1, stx2) = makeTransactions(params1, params2)
|
||||
val (stx1, stx2) = makeTransactions(defaultParams, params2)
|
||||
assertThat(stx1.networkParametersHash).isEqualTo(hash1)
|
||||
assertThat(stx2.networkParametersHash).isEqualTo(hash2)
|
||||
miniCorpNode.transaction {
|
||||
@ -125,8 +168,60 @@ class NetworkParametersResolutionTest {
|
||||
future.getOrThrow()
|
||||
miniCorpNode.transaction {
|
||||
// Check that parameters were downloaded to the storage.
|
||||
assertThat(miniCorpNode.services.networkParametersService.lookup(hash1)).isEqualTo(params1)
|
||||
assertThat(miniCorpNode.services.networkParametersService.lookup(hash1)).isEqualTo(defaultParams)
|
||||
assertThat(miniCorpNode.services.networkParametersService.lookup(hash2)).isEqualTo(params2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `transaction chain out of order parameters with default`() {
|
||||
val hash3 = params3.serialize().hash
|
||||
// stx1 with epoch 3 -> stx2 with default epoch, which is 1
|
||||
val (stx1, stx2) = makeTransactions(params3, null)
|
||||
assertThat(stx2.networkParametersHash).isNull()
|
||||
assertThat(stx1.networkParametersHash).isEqualTo(hash3)
|
||||
val p = ResolveTransactionsFlowTest.TestFlow(setOf(stx2.id), megaCorpParty)
|
||||
val future = miniCorpNode.startFlow(p)
|
||||
mockNet.runNetwork()
|
||||
assertThatExceptionOfType(TransactionVerificationException.TransactionNetworkParameterOrderingException::class.java).isThrownBy {
|
||||
future.getOrThrow()
|
||||
}.withMessageContaining("The network parameters epoch (${defaultParams.epoch}) of this transaction " +
|
||||
"is older than the epoch (${params3.epoch}) of input state: ${stx2.inputs.first()}")
|
||||
miniCorpNode.transaction {
|
||||
assertThat(miniCorpNode.services.validatedTransactions.getTransaction(stx1.id)).isNull()
|
||||
assertThat(miniCorpNode.services.validatedTransactions.getTransaction(stx2.id)).isNull()
|
||||
assertThat(miniCorpNode.services.networkParametersService.lookup(hash3)).isEqualTo(params3)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `incorrect triangle of transactions`() {
|
||||
// stx1 with epoch 2, stx2 with epoch 1, stx3 with epoch 3
|
||||
// stx1 -> stx2, stx1 -> stx3, stx2 -> stx3
|
||||
val stx1 = makeTransactions(params2, null).first
|
||||
|
||||
val stx2 = DummyContract.move(stx1.tx.outRef(0), miniCorpParty).let { builder ->
|
||||
val ptx = builder.toSignedTransactionWithParameters(defaultParams, megaCorpNode.services)
|
||||
notaryNode.services.addSignature(ptx, notaryParty.owningKey)
|
||||
}
|
||||
|
||||
val stx3 = DummyContract.move(listOf(stx1.tx.outRef(0), stx2.tx.outRef(0)), miniCorpParty).let { builder ->
|
||||
val ptx = builder.toSignedTransactionWithParameters(params3, megaCorpNode.services)
|
||||
notaryNode.services.addSignature(ptx, notaryParty.owningKey)
|
||||
}
|
||||
|
||||
megaCorpNode.transaction {
|
||||
megaCorpNode.services.recordTransactions(stx2, stx3)
|
||||
(megaCorpNode.services.networkParametersService as NetworkParametersStorage).saveParameters(certKeyPair.sign(defaultParams))
|
||||
(megaCorpNode.services.networkParametersService as NetworkParametersStorage).saveParameters(certKeyPair.sign(params3))
|
||||
}
|
||||
|
||||
val p = ResolveTransactionsFlowTest.TestFlow(setOf(stx3.id), megaCorpParty)
|
||||
val future = miniCorpNode.startFlow(p)
|
||||
mockNet.runNetwork()
|
||||
assertThatExceptionOfType(TransactionVerificationException.TransactionNetworkParameterOrderingException::class.java).isThrownBy {
|
||||
future.getOrThrow()
|
||||
}.withMessageContaining("The network parameters epoch (${defaultParams.epoch}) of this transaction " +
|
||||
"is older than the epoch (${params2.epoch}) of input state: ${stx2.inputs.first()}")
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import net.corda.node.utilities.AppendOnlyPersistentMap
|
||||
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
|
||||
import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert
|
||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||
@ -82,7 +83,7 @@ class DBNetworkParametersStorage(
|
||||
|
||||
override fun saveParameters(signedNetworkParameters: SignedNetworkParameters) {
|
||||
log.trace { "Saving new network parameters to network parameters storage." }
|
||||
val networkParameters = signedNetworkParameters.verified()
|
||||
val networkParameters = signedNetworkParameters.verifiedNetworkMapCert(trustRoot)
|
||||
val hash = signedNetworkParameters.raw.hash
|
||||
log.trace { "Parameters to save $networkParameters with hash $hash" }
|
||||
database.transaction {
|
||||
|
@ -17,7 +17,6 @@ import java.time.Instant
|
||||
class MockNetworkParametersStorage(private var currentParameters: NetworkParameters = testNetworkParameters(modifiedTime = Instant.MIN)) : NetworkParametersStorage {
|
||||
private val hashToParametersMap: HashMap<SecureHash, NetworkParameters> = HashMap()
|
||||
private val hashToSignedParametersMap: HashMap<SecureHash, SignedNetworkParameters> = HashMap()
|
||||
|
||||
init {
|
||||
storeCurrentParameters()
|
||||
}
|
||||
@ -44,8 +43,8 @@ class MockNetworkParametersStorage(private var currentParameters: NetworkParamet
|
||||
}
|
||||
}
|
||||
override val defaultHash: SecureHash get() = currentHash
|
||||
override fun getEpochFromHash(hash: SecureHash): Int? = lookup(hash)?.epoch
|
||||
override fun lookup(hash: SecureHash): NetworkParameters? = hashToParametersMap[hash]
|
||||
override fun getEpochFromHash(hash: SecureHash): Int? = lookup(hash)?.epoch
|
||||
override fun saveParameters(signedNetworkParameters: SignedDataWithCert<NetworkParameters>) {
|
||||
val networkParameters = signedNetworkParameters.verified()
|
||||
val hash = signedNetworkParameters.raw.hash
|
||||
|
Loading…
x
Reference in New Issue
Block a user