mirror of
https://github.com/corda/corda.git
synced 2025-02-26 03:18:57 +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
|
||||
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
|
||||
trade is being set up and is just a big random number. It's used to keep messages separated on the network, and stop
|
||||
malicious entities trying to interfere with the message stream.
|
||||
trade is being set up and is used to keep messages separated on the network, and stop malicious entities trying to
|
||||
interfere with the message stream.
|
||||
- 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
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -179,7 +182,6 @@ Implementing the seller
|
||||
private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) : TwoPartyTradeProtocol() {
|
||||
companion object {
|
||||
val TRADE_TOPIC = "com.r3cev.protocols.trade"
|
||||
fun makeSessionID() = Math.abs(SecureRandom.getInstanceStrong().nextLong())
|
||||
}
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
.. 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.
|
||||
arrive at a node (see :doc:`messaging` for details).
|
||||
|
||||
The runSeller and runBuyer methods simply start the state machines, passing in a reference to the classes and the topics
|
||||
each side will use.
|
||||
@ -240,7 +239,7 @@ Next we add some code to the ``SellerImpl.call`` method:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
val sessionID = makeSessionID()
|
||||
val sessionID = random63BitValue()
|
||||
|
||||
// Make the first message we'll send to kick off the protocol.
|
||||
val hello = SellerTradeInfo(args.assetToSell, args.price, args.myKeyPair.public, sessionID)
|
||||
|
@ -16,7 +16,6 @@ import core.serialization.deserialize
|
||||
import core.utilities.trace
|
||||
import java.security.KeyPair
|
||||
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:
|
||||
@ -73,7 +72,6 @@ abstract class TwoPartyTradeProtocol {
|
||||
private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) : TwoPartyTradeProtocol() {
|
||||
companion object {
|
||||
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.
|
||||
@ -92,7 +90,7 @@ private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) :
|
||||
// learn more about the protocol state machine framework.
|
||||
class SellerImpl : Seller() {
|
||||
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.
|
||||
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.SettableFuture
|
||||
import org.slf4j.Logger
|
||||
import java.security.SecureRandom
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
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.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) {
|
||||
addListener(Runnable { body() }, executor ?: MoreExecutors.directExecutor())
|
||||
}
|
||||
|
@ -12,15 +12,11 @@ import com.google.common.util.concurrent.MoreExecutors
|
||||
import contracts.Cash
|
||||
import contracts.CommercialPaper
|
||||
import contracts.protocols.TwoPartyTradeProtocol
|
||||
import core.ContractState
|
||||
import core.DOLLARS
|
||||
import core.StateAndRef
|
||||
import core.days
|
||||
import core.*
|
||||
import core.testutils.*
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.security.SecureRandom
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.logging.Formatter
|
||||
import java.util.logging.Level
|
||||
@ -77,7 +73,7 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
||||
val tpSeller = TwoPartyTradeProtocol.create(StateMachineManager(alicesServices, backgroundThread))
|
||||
val tpBuyer = TwoPartyTradeProtocol.create(StateMachineManager(bobsServices, backgroundThread))
|
||||
|
||||
val buyerSessionID = SecureRandom.getInstanceStrong().nextLong()
|
||||
val buyerSessionID = random63BitValue()
|
||||
|
||||
val aliceResult = tpSeller.runSeller(
|
||||
bobsAddress,
|
||||
@ -134,7 +130,7 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
||||
val smmBuyer = StateMachineManager(bobsServices, MoreExecutors.directExecutor())
|
||||
val tpBuyer = TwoPartyTradeProtocol.create(smmBuyer)
|
||||
|
||||
val buyerSessionID = SecureRandom.getInstanceStrong().nextLong()
|
||||
val buyerSessionID = random63BitValue()
|
||||
|
||||
tpSeller.runSeller(
|
||||
bobsAddress,
|
||||
|
Loading…
x
Reference in New Issue
Block a user