mirror of
https://github.com/corda/corda.git
synced 2025-06-01 23:20:54 +00:00
Minor: provide a random63BitValue() function and use it instead of the previously duplicated code. Update docs.
This commit is contained in:
parent
020a594a60
commit
06ee9db3f6
@ -140,8 +140,8 @@ Let's unpack what this code does:
|
|||||||
- Two of the classes are simply wrappers for parameters to the trade; things like what is being sold, what the price
|
- Two of the classes are simply wrappers for parameters to the trade; things like what is being sold, what the price
|
||||||
of the asset is, how much the buyer is willing to pay and so on. The ``myKeyPair`` field is simply the public key
|
of the asset is, how much the buyer is willing to pay and so on. The ``myKeyPair`` field is simply the public key
|
||||||
that the seller wishes the buyer to send the cash to. The session ID field is sent from buyer to seller when the
|
that the seller wishes the buyer to send the cash to. The session ID field is sent from buyer to seller when the
|
||||||
trade is being set up and is just a big random number. It's used to keep messages separated on the network, and stop
|
trade is being set up and is used to keep messages separated on the network, and stop malicious entities trying to
|
||||||
malicious entities trying to interfere with the message stream.
|
interfere with the message stream.
|
||||||
- The other two classes define empty abstract classes called ``Buyer`` and ``Seller``. These inherit from a class
|
- The other two classes define empty abstract classes called ``Buyer`` and ``Seller``. These inherit from a class
|
||||||
called ``ProtocolStateMachine`` and provide two type parameters: the arguments class we just defined for each side
|
called ``ProtocolStateMachine`` and provide two type parameters: the arguments class we just defined for each side
|
||||||
and the type of the object that the protocol finally produces (this doesn't have to be identical for each side, even
|
and the type of the object that the protocol finally produces (this doesn't have to be identical for each side, even
|
||||||
@ -149,6 +149,9 @@ Let's unpack what this code does:
|
|||||||
- Finally it simply defines a static method that creates an instance of an object that inherits from this base class
|
- Finally it simply defines a static method that creates an instance of an object that inherits from this base class
|
||||||
and returns it, with a ``StateMachineManager`` as an instance. The Impl class will be defined below.
|
and returns it, with a ``StateMachineManager`` as an instance. The Impl class will be defined below.
|
||||||
|
|
||||||
|
.. note:: Session IDs keep different traffic streams separated, so for security they must be large and random enough
|
||||||
|
to be unguessable. 63 bits is good enough.
|
||||||
|
|
||||||
Alright, so using this protocol shouldn't be too hard: in the simplest case we can just pass in the details of the trade
|
Alright, so using this protocol shouldn't be too hard: in the simplest case we can just pass in the details of the trade
|
||||||
to either runBuyer or runSeller, depending on who we are, and then call ``.get()`` on the resulting future to block the
|
to either runBuyer or runSeller, depending on who we are, and then call ``.get()`` on the resulting future to block the
|
||||||
calling thread until the protocol has finished. Or we could register a callback on the returned future that will be
|
calling thread until the protocol has finished. Or we could register a callback on the returned future that will be
|
||||||
@ -179,7 +182,6 @@ Implementing the seller
|
|||||||
private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) : TwoPartyTradeProtocol() {
|
private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) : TwoPartyTradeProtocol() {
|
||||||
companion object {
|
companion object {
|
||||||
val TRADE_TOPIC = "com.r3cev.protocols.trade"
|
val TRADE_TOPIC = "com.r3cev.protocols.trade"
|
||||||
fun makeSessionID() = Math.abs(SecureRandom.getInstanceStrong().nextLong())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SellerImpl : Seller() {
|
class SellerImpl : Seller() {
|
||||||
@ -206,10 +208,7 @@ Implementing the seller
|
|||||||
|
|
||||||
We start with a skeleton on which we will build the protocol. Putting things in a *companion object* in Kotlin is like
|
We start with a skeleton on which we will build the protocol. Putting things in a *companion object* in Kotlin is like
|
||||||
declaring them as static members in Java. Here, we define a "topic" that will identify trade related messages that
|
declaring them as static members in Java. Here, we define a "topic" that will identify trade related messages that
|
||||||
arrive at a node (see :doc:`messaging` for details), and a convenience function to pick a large random session ID.
|
arrive at a node (see :doc:`messaging` for details).
|
||||||
|
|
||||||
.. note:: Session IDs keep different traffic streams separated, so for security they must be large and random enough
|
|
||||||
to be unguessable. 63 bits is good enough.
|
|
||||||
|
|
||||||
The runSeller and runBuyer methods simply start the state machines, passing in a reference to the classes and the topics
|
The runSeller and runBuyer methods simply start the state machines, passing in a reference to the classes and the topics
|
||||||
each side will use.
|
each side will use.
|
||||||
@ -240,7 +239,7 @@ Next we add some code to the ``SellerImpl.call`` method:
|
|||||||
|
|
||||||
.. sourcecode:: kotlin
|
.. sourcecode:: kotlin
|
||||||
|
|
||||||
val sessionID = makeSessionID()
|
val sessionID = random63BitValue()
|
||||||
|
|
||||||
// Make the first message we'll send to kick off the protocol.
|
// Make the first message we'll send to kick off the protocol.
|
||||||
val hello = SellerTradeInfo(args.assetToSell, args.price, args.myKeyPair.public, sessionID)
|
val hello = SellerTradeInfo(args.assetToSell, args.price, args.myKeyPair.public, sessionID)
|
||||||
|
@ -16,7 +16,6 @@ import core.serialization.deserialize
|
|||||||
import core.utilities.trace
|
import core.utilities.trace
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.security.SecureRandom
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This asset trading protocol has two parties (B and S for buyer and seller) and the following steps:
|
* This asset trading protocol has two parties (B and S for buyer and seller) and the following steps:
|
||||||
@ -73,7 +72,6 @@ abstract class TwoPartyTradeProtocol {
|
|||||||
private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) : TwoPartyTradeProtocol() {
|
private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) : TwoPartyTradeProtocol() {
|
||||||
companion object {
|
companion object {
|
||||||
val TRADE_TOPIC = "com.r3cev.protocols.trade"
|
val TRADE_TOPIC = "com.r3cev.protocols.trade"
|
||||||
fun makeSessionID() = Math.abs(SecureRandom.getInstanceStrong().nextLong())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This object is serialised to the network and is the first protocol message the seller sends to the buyer.
|
// This object is serialised to the network and is the first protocol message the seller sends to the buyer.
|
||||||
@ -92,7 +90,7 @@ private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) :
|
|||||||
// learn more about the protocol state machine framework.
|
// learn more about the protocol state machine framework.
|
||||||
class SellerImpl : Seller() {
|
class SellerImpl : Seller() {
|
||||||
override fun call(args: SellerInitialArgs): Pair<TimestampedWireTransaction, LedgerTransaction> {
|
override fun call(args: SellerInitialArgs): Pair<TimestampedWireTransaction, LedgerTransaction> {
|
||||||
val sessionID = makeSessionID()
|
val sessionID = random63BitValue()
|
||||||
|
|
||||||
// Make the first message we'll send to kick off the protocol.
|
// Make the first message we'll send to kick off the protocol.
|
||||||
val hello = SellerTradeInfo(args.assetToSell, args.price, args.myKeyPair.public, sessionID)
|
val hello = SellerTradeInfo(args.assetToSell, args.price, args.myKeyPair.public, sessionID)
|
||||||
|
@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
|||||||
import com.google.common.util.concurrent.MoreExecutors
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
import java.security.SecureRandom
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
@ -44,6 +45,12 @@ val Int.hours: Duration get() = Duration.ofHours(this.toLong())
|
|||||||
val Int.minutes: Duration get() = Duration.ofMinutes(this.toLong())
|
val Int.minutes: Duration get() = Duration.ofMinutes(this.toLong())
|
||||||
val Int.seconds: Duration get() = Duration.ofSeconds(this.toLong())
|
val Int.seconds: Duration get() = Duration.ofSeconds(this.toLong())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random positive long generated using a secure RNG. This function sacrifies a bit of entropy in order to
|
||||||
|
* avoid potential bugs where the value is used in a context where negative numbers are not expected.
|
||||||
|
*/
|
||||||
|
fun random63BitValue(): Long = Math.abs(SecureRandom.getInstanceStrong().nextLong())
|
||||||
|
|
||||||
fun <T> ListenableFuture<T>.whenComplete(executor: Executor? = null, body: () -> Unit) {
|
fun <T> ListenableFuture<T>.whenComplete(executor: Executor? = null, body: () -> Unit) {
|
||||||
addListener(Runnable { body() }, executor ?: MoreExecutors.directExecutor())
|
addListener(Runnable { body() }, executor ?: MoreExecutors.directExecutor())
|
||||||
}
|
}
|
||||||
|
@ -12,15 +12,11 @@ import com.google.common.util.concurrent.MoreExecutors
|
|||||||
import contracts.Cash
|
import contracts.Cash
|
||||||
import contracts.CommercialPaper
|
import contracts.CommercialPaper
|
||||||
import contracts.protocols.TwoPartyTradeProtocol
|
import contracts.protocols.TwoPartyTradeProtocol
|
||||||
import core.ContractState
|
import core.*
|
||||||
import core.DOLLARS
|
|
||||||
import core.StateAndRef
|
|
||||||
import core.days
|
|
||||||
import core.testutils.*
|
import core.testutils.*
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.security.SecureRandom
|
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.logging.Formatter
|
import java.util.logging.Formatter
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
@ -77,7 +73,7 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
|||||||
val tpSeller = TwoPartyTradeProtocol.create(StateMachineManager(alicesServices, backgroundThread))
|
val tpSeller = TwoPartyTradeProtocol.create(StateMachineManager(alicesServices, backgroundThread))
|
||||||
val tpBuyer = TwoPartyTradeProtocol.create(StateMachineManager(bobsServices, backgroundThread))
|
val tpBuyer = TwoPartyTradeProtocol.create(StateMachineManager(bobsServices, backgroundThread))
|
||||||
|
|
||||||
val buyerSessionID = SecureRandom.getInstanceStrong().nextLong()
|
val buyerSessionID = random63BitValue()
|
||||||
|
|
||||||
val aliceResult = tpSeller.runSeller(
|
val aliceResult = tpSeller.runSeller(
|
||||||
bobsAddress,
|
bobsAddress,
|
||||||
@ -134,7 +130,7 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
|||||||
val smmBuyer = StateMachineManager(bobsServices, MoreExecutors.directExecutor())
|
val smmBuyer = StateMachineManager(bobsServices, MoreExecutors.directExecutor())
|
||||||
val tpBuyer = TwoPartyTradeProtocol.create(smmBuyer)
|
val tpBuyer = TwoPartyTradeProtocol.create(smmBuyer)
|
||||||
|
|
||||||
val buyerSessionID = SecureRandom.getInstanceStrong().nextLong()
|
val buyerSessionID = random63BitValue()
|
||||||
|
|
||||||
tpSeller.runSeller(
|
tpSeller.runSeller(
|
||||||
bobsAddress,
|
bobsAddress,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user