Updated Corda in preparation for the merging of the Vega cordapp. Includes

some minor changes, including gitignore rule changes. The largest change
is replacing the current fresh key for each transaction with a single
static identity in preparation for aimproved and more fleshed out key
sharing infrastructure.
This commit is contained in:
Clinton Alexander 2016-09-26 13:02:33 +01:00
parent 6c96517f6f
commit 43de27c4c1
21 changed files with 65 additions and 74 deletions

26
.gitignore vendored
View File

@ -5,20 +5,28 @@
tags
.DS_Store
*.log
*.log.gz
*.orig
# Created by .ignore support plugin (hsz.mobi)
.gradle
/build/
/node/build/
/contracts/build
/contracts/isolated/build
/core/build
/experimental/build
/docs/build/doctrees
/test-utils/build
/client/build
/explorer/build
# General build files
**/build/classes/**
**/build/install/**
**/build/kotlin-classes/**
**/build/libs/**
**/build/resources/**
**/build/tmp/**
**/build/reports/**
**/build/jacoco/***
**/build/test-results/**
**/build/[0-9]*/**
**/build/nodes/**
**/build/scripts/**
**/build/publications/**
# gradle's buildSrc build/
/buildSrc/build/

View File

@ -201,7 +201,7 @@ class InterestRateSwap() : Contract {
val threshold: Amount<Currency>,
val minimumTransferAmount: Amount<Currency>,
val rounding: Amount<Currency>,
val valuationDate: String,
val valuationDateDescription: String, // This describes (in english) how regularly the swap is to be valued, e.g. "every local working day"
val notificationTime: String,
val resolutionTime: String,
val interestRate: ReferenceRate,
@ -679,22 +679,6 @@ class InterestRateSwap() : Contract {
return ScheduledActivity(protocolLogicRefFactory.create(TwoPartyDealProtocol.FixingRoleDecider::class.java, thisStateRef, duration), instant)
}
// TODO: This changing of the public key violates the assumption that Party is a fixed identity key.
override fun withPublicKey(before: Party, after: PublicKey): DealState {
val newParty = Party(before.name, after)
if (before == fixedLeg.fixedRatePayer) {
val deal = copy()
deal.fixedLeg.fixedRatePayer = newParty
return deal
} else if (before == floatingLeg.floatingRatePayer) {
val deal = copy()
deal.floatingLeg.floatingRatePayer = newParty
return deal
} else {
throw IllegalArgumentException("No such party: $before")
}
}
override fun generateAgreement(notary: Party): TransactionBuilder = InterestRateSwap().generateAgreement(floatingLeg, fixedLeg, calculation, common, notary)
override fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix) {

View File

@ -6,11 +6,8 @@ import com.r3corda.core.transactions.SignedTransaction
import com.r3corda.core.utilities.DUMMY_NOTARY
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
import com.r3corda.core.utilities.TEST_TX_TIME
import com.r3corda.testing.LedgerDSL
import com.r3corda.testing.TestLedgerDSLInterpreter
import com.r3corda.testing.TestTransactionDSLInterpreter
import com.r3corda.testing.node.MockServices
import com.r3corda.testing.*
import com.r3corda.testing.node.MockServices
import org.junit.Test
import java.math.BigDecimal
import java.time.LocalDate
@ -92,7 +89,7 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
threshold = Amount(0, EUR),
minimumTransferAmount = Amount(250000 * 100, EUR),
rounding = Amount(10000 * 100, EUR),
valuationDate = "Every Local Business Day",
valuationDateDescription = "Every Local Business Day",
notificationTime = "2:00pm London",
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),
@ -182,7 +179,7 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
threshold = Amount(0, EUR),
minimumTransferAmount = Amount(250000 * 100, EUR),
rounding = Amount(10000 * 100, EUR),
valuationDate = "Every Local Business Day",
valuationDateDescription = "Every Local Business Day",
notificationTime = "2:00pm London",
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),

View File

@ -23,6 +23,7 @@ fun commodity(code: String) = Commodity.getInstance(code)!!
@JvmField val USD = currency("USD")
@JvmField val GBP = currency("GBP")
@JvmField val EUR = currency("EUR")
@JvmField val CHF = currency("CHF")
@JvmField val FCOJ = commodity("FCOJ")

View File

@ -279,9 +279,6 @@ interface DealState : LinearState {
/** Exposes the Parties involved in a generic way */
val parties: List<Party>
// TODO: This works by editing the keys used by a Party which is invalid.
fun withPublicKey(before: Party, after: PublicKey): DealState
/**
* Generate a partial transaction representing an agreement (command) to this deal, allowing a general
* deal/agreement protocol to generate the necessary transaction for potential implementations.

View File

@ -231,7 +231,7 @@ object X509Utilities {
fun generateECDSAKeyPairForSSL(): KeyPair {
val keyGen = KeyPairGenerator.getInstance(KEY_GENERATION_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME)
val ecSpec = ECGenParameterSpec(ECDSA_CURVE) // Force named curve, because TLS implementations don't support many curves
keyGen.initialize(ecSpec, SecureRandom())
keyGen.initialize(ecSpec, newSecureRandom())
return keyGen.generateKeyPair()
}

View File

@ -150,6 +150,10 @@ interface VaultService {
}
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
inline fun <reified T : DealState> VaultService.dealsWith(party: Party) = linearHeadsOfType<T>().values.filter {
// TODO: Replace name comparison with full party comparison (keys are currenty not equal)
it.state.data.parties.any { it.name == party.name }
}
/**
* The KMS is responsible for storing and using private keys to sign things. An implementation of this may, for example,

View File

@ -2,8 +2,11 @@ package com.r3corda.core.protocols
import co.paralleluniverse.fibers.Suspendable
import com.r3corda.core.crypto.Party
import com.r3corda.core.messaging.Message
import com.r3corda.core.messaging.runOnNextMessage
import com.r3corda.core.node.ServiceHub
import com.r3corda.core.node.services.DEFAULT_SESSION_ID
import com.r3corda.core.serialization.deserialize
import com.r3corda.core.utilities.ProgressTracker
import com.r3corda.core.utilities.UntrustworthyData
import com.r3corda.core.utilities.debug
@ -11,6 +14,7 @@ import com.r3corda.protocols.HandshakeMessage
import org.slf4j.Logger
import rx.Observable
import java.util.*
import java.util.concurrent.CompletableFuture
/**
* A sub-class of [ProtocolLogic<T>] implements a protocol flow using direct, straight line blocking code. Thus you
@ -108,6 +112,11 @@ abstract class ProtocolLogic<out T> {
throw IllegalStateException("Session with party $otherParty hasn't been established yet")
}
/**
* Check if we already have a session with this party
*/
protected fun hasSession(otherParty: Party) = sessions.containsKey(otherParty)
/**
* Invokes the given subprotocol by simply passing through this [ProtocolLogic]s reference to the
* [ProtocolStateMachine] and then calling the [call] method.

View File

@ -70,8 +70,8 @@ abstract class AbstractStateReplacementProtocol<T> {
return finalTx.tx.outRef(0)
}
abstract internal fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): Proposal<T>
abstract internal fun assembleTx(): Pair<SignedTransaction, List<PublicKey>>
abstract protected fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): Proposal<T>
abstract protected fun assembleTx(): Pair<SignedTransaction, List<PublicKey>>
@Suspendable
private fun collectSignatures(participants: List<PublicKey>, stx: SignedTransaction): List<DigitalSignature.WithKey> {
@ -93,7 +93,10 @@ abstract class AbstractStateReplacementProtocol<T> {
private fun getParticipantSignature(party: Party, stx: SignedTransaction): DigitalSignature.WithKey {
val proposal = assembleProposal(originalState.ref, modification, stx)
send(party, Handshake(serviceHub.storageService.myLegalIdentity))
// TODO: Move this into protocol logic as a func on the lines of handshake(Party, HandshakeMessage)
if (!hasSession(party)) {
send(party, Handshake(serviceHub.storageService.myLegalIdentity))
}
val response = sendAndReceive<Result>(party, proposal)
val participantSignature = response.unwrap {
@ -179,7 +182,7 @@ abstract class AbstractStateReplacementProtocol<T> {
* on the change proposed, and may further depend on the node itself (for example configuration). The
* proposal is returned if acceptable, otherwise an exception is thrown.
*/
abstract fun verifyProposal(maybeProposal: UntrustworthyData<Proposal<T>>): Proposal<T>
abstract protected fun verifyProposal(maybeProposal: UntrustworthyData<Proposal<T>>): Proposal<T>
@Suspendable
private fun verifyTx(stx: SignedTransaction) {
@ -219,4 +222,4 @@ class StateReplacementRefused(val identity: Party, val state: StateRef, val deta
override fun toString() = "A participant $identity refused to change state $state: " + (detail ?: "no reason provided")
}
class StateReplacementException(val error: StateReplacementRefused) : Exception("State change failed - $error")
class StateReplacementException(val error: StateReplacementRefused) : Exception("State change failed - $error")

View File

@ -6,6 +6,7 @@ import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.DigitalSignature
import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.signWithECDSA
import com.r3corda.core.crypto.toBase58String
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.protocols.ProtocolLogic
@ -285,22 +286,11 @@ object TwoPartyDealProtocol {
override fun validateHandshake(handshake: Handshake<T>): Handshake<T> {
// What is the seller trying to sell us?
val deal: T = handshake.payload
val otherKey = handshake.publicKey
logger.trace { "Got deal request for: ${handshake.payload.ref}" }
check(dealToBuy == deal)
// We need to substitute in the new public keys for the Parties
val myName = serviceHub.storageService.myLegalIdentity.name
val myOldParty = deal.parties.single { it.name == myName }
val theirOldParty = deal.parties.single { it.name != myName }
@Suppress("UNCHECKED_CAST")
val newDeal = deal.
withPublicKey(myOldParty, serviceHub.keyManagementService.freshKey().public).
withPublicKey(theirOldParty, otherKey) as T
return handshake.copy(payload = newDeal)
return handshake.copy(payload = deal)
}

View File

@ -261,7 +261,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
private fun scheduleTX(instant: Instant, increment: Int = 1): ScheduledStateRef? {
var scheduledRef: ScheduledStateRef? = null
apply {
val freshKey = services.keyManagementService.freshKey()
val freshKey = services.storageService.myLegalIdentityKey
val state = TestState(factory.create(TestProtocolLogic::class.java, increment), instant)
val usefulTX = TransactionType.General.Builder(null).apply {
addOutputState(state, DUMMY_NOTARY)

View File

@ -83,7 +83,7 @@ class VaultWithCashTest {
fun `issue and spend total correctly and irrelevant ignored`() {
databaseTransaction(database) {
// A tx that sends us money.
val freshKey = services.keyManagementService.freshKey()
val freshKey = services.storageService.myLegalIdentityKey
val usefulTX = TransactionType.General.Builder(null).apply {
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY)
signWith(MEGA_CORP_KEY)
@ -121,7 +121,7 @@ class VaultWithCashTest {
@Test
fun `branching LinearStates fails to verify`() {
databaseTransaction(database) {
val freshKey = services.keyManagementService.freshKey()
val freshKey = services.storageService.myLegalIdentityKey
val linearId = UniqueIdentifier()
// Issue a linear state
@ -141,7 +141,7 @@ class VaultWithCashTest {
@Test
fun `sequencing LinearStates works`() {
databaseTransaction(database) {
val freshKey = services.keyManagementService.freshKey()
val freshKey = services.storageService.myLegalIdentityKey
val linearId = UniqueIdentifier()

View File

@ -85,7 +85,7 @@ fun main(args: Array<String>) {
// Make a garbage transaction that includes a rate fix.
val tx = TransactionType.General.Builder(notaryNode.identity)
tx.addOutputState(TransactionState(Cash.State(1500.DOLLARS `issued by` node.storage.myLegalIdentity.ref(1), node.keyManagement.freshKey().public), notaryNode.identity))
tx.addOutputState(TransactionState(Cash.State(1500.DOLLARS `issued by` node.storage.myLegalIdentity.ref(1), node.storage.myLegalIdentityKey.public), notaryNode.identity))
val protocol = RatesFixProtocol(tx, rateOracle.identity, fixOf, expectedRate, rateTolerance)
node.services.startProtocol("demo.ratefix", protocol).get()
node.stop()

View File

@ -202,7 +202,7 @@ private fun runBuyer(node: Node, amount: Amount<Currency>) {
databaseTransaction(node.database) {
node.services.fillWithSomeTestCash(300000.DOLLARS,
outputNotary = node.info.identity, // In this demo, the buyer and notary are the same.
ownedBy = node.services.keyManagementService.freshKey().public)
ownedBy = node.storage.myLegalIdentityKey.public)
}
// Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band
@ -314,7 +314,7 @@ private class TraderDemoProtocolSeller(val otherSide: Party,
progressTracker.currentStep = SELF_ISSUING
val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0]
val cpOwnerKey = serviceHub.keyManagementService.freshKey()
val cpOwnerKey = serviceHub.storageService.myLegalIdentityKey
val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public, notary)
progressTracker.currentStep = TRADING

View File

@ -107,7 +107,7 @@ object AutoOfferProtocol {
otherParty,
notary,
dealToBeOffered,
serviceHub.keyManagementService.freshKey(),
serviceHub.storageService.myLegalIdentityKey,
progressTracker.getChildProgressTracker(DEALING)!!
)
val stx = subProtocol(instigator, inheritParentSessions = true)

View File

@ -32,17 +32,11 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
currentDateAndTime = LocalDate.of(2016, 3, 8).atStartOfDay()
}
private var nodeAKey: KeyPair? = null
private var nodeBKey: KeyPair? = null
private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>())
override fun startMainSimulation(): ListenableFuture<Unit> {
val future = SettableFuture.create<Unit>()
nodeAKey = banks[0].keyManagement.freshKey()
nodeBKey = banks[1].keyManagement.freshKey()
startIRSDealBetween(0, 1).success {
// Next iteration is a pause.
executeOnNextIteration.add {}
@ -121,7 +115,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
irs.fixedLeg.fixedRatePayer = node1.info.identity
irs.floatingLeg.floatingRatePayer = node2.info.identity
val instigator = TwoPartyDealProtocol.Instigator(node2.info.identity, notary.info.identity, irs, nodeAKey!!)
val instigator = TwoPartyDealProtocol.Instigator(node2.info.identity, notary.info.identity, irs, node1.keyPair!!)
val acceptor = TwoPartyDealProtocol.Acceptor(node1.info.identity, notary.info.identity, irs)
connectProtocols(instigator, acceptor)

View File

@ -3,6 +3,7 @@ package com.r3corda.simulation
import com.google.common.net.HostAndPort
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import com.r3corda.core.crypto.generateKeyPair
import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.CityDatabase
import com.r3corda.core.node.PhysicalLocation
@ -73,8 +74,11 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair)
}
fun createAll(): List<SimulatedNode> = bankLocations.
map { network.createNode(networkMap.info.address, start = false, nodeFactory = this) as SimulatedNode }
fun createAll(): List<SimulatedNode> {
return bankLocations.map {
network.createNode(networkMap.info.address, start = false, nodeFactory = this, keyPair = generateKeyPair()) as SimulatedNode
}
}
}
val bankFactory = BankFactory()

View File

@ -82,7 +82,7 @@
"quantity": 1000000,
"token": "EUR"
},
"valuationDate": "Every Local Business Day",
"valuationDateDescription": "Every Local Business Day",
"notificationTime": "2:00pm London",
"resolutionTime": "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
"interestRate": {

View File

@ -18,7 +18,7 @@ define([], () => {
rounding: {
quantity: 1000000
},
valuationDate: "Every Local Business Day",
valuationDateDescription: "Every Local Business Day",
notificationTime: "2:00pm London",
resolutionTime: "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given",
interestRate: {

View File

@ -23,7 +23,7 @@
</tr>
<tr class="center aligned">
<td>Valuation Date</td>
<td>{{deal.common.valuationDate}}</td>
<td>{{deal.common.valuationDateDescription}}</td>
</tr>
<tr class="center aligned">
<td>Legal Document Hash</td>

View File

@ -82,7 +82,7 @@
"quantity": 1000000,
"token": "EUR"
},
"valuationDate": "Every Local Business Day",
"valuationDateDescription": "Every Local Business Day",
"notificationTime": "2:00pm London",
"resolutionTime": "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
"interestRate": {