mirror of
https://github.com/corda/corda.git
synced 2025-06-11 03:41:41 +00:00
Merged in rnicoll-notify-tx (pull request #282)
Add observable for transactions being stored
This commit is contained in:
commit
a9ec3c253e
@ -11,6 +11,12 @@ interface ReadOnlyTransactionStorage {
|
|||||||
* Return the transaction with the given [id], or null if no such transaction exists.
|
* Return the transaction with the given [id], or null if no such transaction exists.
|
||||||
*/
|
*/
|
||||||
fun getTransaction(id: SecureHash): SignedTransaction?
|
fun getTransaction(id: SecureHash): SignedTransaction?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate
|
||||||
|
* the update.
|
||||||
|
*/
|
||||||
|
val updates: rx.Observable<SignedTransaction>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +15,8 @@ import com.r3corda.core.serialization.SingletonSerializeAsToken
|
|||||||
import com.r3corda.core.testing.DUMMY_NOTARY
|
import com.r3corda.core.testing.DUMMY_NOTARY
|
||||||
import com.r3corda.core.testing.MEGA_CORP
|
import com.r3corda.core.testing.MEGA_CORP
|
||||||
import com.r3corda.core.testing.MINI_CORP
|
import com.r3corda.core.testing.MINI_CORP
|
||||||
|
import rx.Observable
|
||||||
|
import rx.subjects.PublishSubject
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -116,9 +118,19 @@ class MockAttachmentStorage : AttachmentStorage {
|
|||||||
|
|
||||||
open class MockTransactionStorage : TransactionStorage {
|
open class MockTransactionStorage : TransactionStorage {
|
||||||
private val txns = HashMap<SecureHash, SignedTransaction>()
|
private val txns = HashMap<SecureHash, SignedTransaction>()
|
||||||
|
|
||||||
|
private val _updatesPublisher = PublishSubject.create<SignedTransaction>()
|
||||||
|
|
||||||
|
override val updates: Observable<SignedTransaction>
|
||||||
|
get() = _updatesPublisher
|
||||||
|
|
||||||
|
private fun notify(transaction: SignedTransaction) = _updatesPublisher.onNext(transaction)
|
||||||
|
|
||||||
override fun addTransaction(transaction: SignedTransaction) {
|
override fun addTransaction(transaction: SignedTransaction) {
|
||||||
txns[transaction.id] = transaction
|
txns[transaction.id] = transaction
|
||||||
|
notify(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTransaction(id: SecureHash): SignedTransaction? = txns[id]
|
override fun getTransaction(id: SecureHash): SignedTransaction? = txns[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import java.util.*
|
|||||||
* Events triggered by changes in the node, and sent to monitoring client(s).
|
* Events triggered by changes in the node, and sent to monitoring client(s).
|
||||||
*/
|
*/
|
||||||
sealed class ServiceToClientEvent(val time: Instant) {
|
sealed class ServiceToClientEvent(val time: Instant) {
|
||||||
|
class Transaction(time: Instant, val transaction: SignedTransaction) : ServiceToClientEvent(time)
|
||||||
class OutputState(time: Instant, val consumed: Set<StateRef>, val produced: Set<StateAndRef<ContractState>>) : ServiceToClientEvent(time)
|
class OutputState(time: Instant, val consumed: Set<StateRef>, val produced: Set<StateAndRef<ContractState>>) : ServiceToClientEvent(time)
|
||||||
class StateMachine(time: Instant, val fiberId: Long, val label: String, val addOrRemove: AddOrRemove) : ServiceToClientEvent(time)
|
class StateMachine(time: Instant, val fiberId: Long, val label: String, val addOrRemove: AddOrRemove) : ServiceToClientEvent(time)
|
||||||
class Progress(time: Instant, val fiberId: Long, val message: String) : ServiceToClientEvent(time)
|
class Progress(time: Instant, val fiberId: Long, val message: String) : ServiceToClientEvent(time)
|
||||||
|
@ -62,6 +62,7 @@ class WalletMonitorService(net: MessagingService, val smm: StateMachineManager,
|
|||||||
addMessageHandler(OUT_EVENT_TOPIC) { req: ClientToServiceCommandMessage -> processEventRequest(req) }
|
addMessageHandler(OUT_EVENT_TOPIC) { req: ClientToServiceCommandMessage -> processEventRequest(req) }
|
||||||
|
|
||||||
// Notify listeners on state changes
|
// Notify listeners on state changes
|
||||||
|
services.storageService.validatedTransactions.updates.subscribe { tx -> notifyTransaction(tx) }
|
||||||
services.walletService.updates.subscribe { update -> notifyWalletUpdate(update) }
|
services.walletService.updates.subscribe { update -> notifyWalletUpdate(update) }
|
||||||
smm.changes.subscribe { change ->
|
smm.changes.subscribe { change ->
|
||||||
val fiberId: Long = change.third
|
val fiberId: Long = change.third
|
||||||
@ -86,6 +87,10 @@ class WalletMonitorService(net: MessagingService, val smm: StateMachineManager,
|
|||||||
internal fun notifyWalletUpdate(update: Wallet.Update)
|
internal fun notifyWalletUpdate(update: Wallet.Update)
|
||||||
= notifyEvent(ServiceToClientEvent.OutputState(Instant.now(), update.consumed, update.produced))
|
= notifyEvent(ServiceToClientEvent.OutputState(Instant.now(), update.consumed, update.produced))
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
internal fun notifyTransaction(transaction: SignedTransaction)
|
||||||
|
= notifyEvent(ServiceToClientEvent.Transaction(Instant.now(), transaction))
|
||||||
|
|
||||||
private fun processEventRequest(reqMessage: ClientToServiceCommandMessage) {
|
private fun processEventRequest(reqMessage: ClientToServiceCommandMessage) {
|
||||||
val req = reqMessage.command
|
val req = reqMessage.command
|
||||||
val result: TransactionBuildResult? =
|
val result: TransactionBuildResult? =
|
||||||
|
@ -7,6 +7,8 @@ import com.r3corda.core.serialization.deserialize
|
|||||||
import com.r3corda.core.serialization.serialize
|
import com.r3corda.core.serialization.serialize
|
||||||
import com.r3corda.core.utilities.loggerFor
|
import com.r3corda.core.utilities.loggerFor
|
||||||
import com.r3corda.core.utilities.trace
|
import com.r3corda.core.utilities.trace
|
||||||
|
import rx.Observable
|
||||||
|
import rx.subjects.PublishSubject
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@ -25,6 +27,13 @@ class PerFileTransactionStorage(val storeDir: Path) : TransactionStorage {
|
|||||||
|
|
||||||
private val _transactions = ConcurrentHashMap<SecureHash, SignedTransaction>()
|
private val _transactions = ConcurrentHashMap<SecureHash, SignedTransaction>()
|
||||||
|
|
||||||
|
private val _updatesPublisher = PublishSubject.create<SignedTransaction>()
|
||||||
|
|
||||||
|
override val updates: Observable<SignedTransaction>
|
||||||
|
get() = _updatesPublisher
|
||||||
|
|
||||||
|
private fun notify(transaction: SignedTransaction) = _updatesPublisher.onNext(transaction)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
logger.trace { "Initialising per file transaction storage on $storeDir" }
|
logger.trace { "Initialising per file transaction storage on $storeDir" }
|
||||||
Files.createDirectories(storeDir)
|
Files.createDirectories(storeDir)
|
||||||
@ -39,6 +48,7 @@ class PerFileTransactionStorage(val storeDir: Path) : TransactionStorage {
|
|||||||
transaction.serialize().writeToFile(transactionFile)
|
transaction.serialize().writeToFile(transactionFile)
|
||||||
_transactions[transaction.id] = transaction
|
_transactions[transaction.id] = transaction
|
||||||
logger.trace { "Stored $transaction to $transactionFile" }
|
logger.trace { "Stored $transaction to $transactionFile" }
|
||||||
|
notify(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTransaction(id: SecureHash): SignedTransaction? = _transactions[id]
|
override fun getTransaction(id: SecureHash): SignedTransaction? = _transactions[id]
|
||||||
|
@ -28,6 +28,7 @@ import org.assertj.core.api.Assertions.assertThat
|
|||||||
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 rx.Observable
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -503,6 +504,8 @@ class TwoPartyTradeProtocolTests {
|
|||||||
class RecordingTransactionStorage(val delegate: TransactionStorage) : TransactionStorage {
|
class RecordingTransactionStorage(val delegate: TransactionStorage) : TransactionStorage {
|
||||||
|
|
||||||
val records: MutableList<TxRecord> = Collections.synchronizedList(ArrayList<TxRecord>())
|
val records: MutableList<TxRecord> = Collections.synchronizedList(ArrayList<TxRecord>())
|
||||||
|
override val updates: Observable<SignedTransaction>
|
||||||
|
get() = delegate.updates
|
||||||
|
|
||||||
override fun addTransaction(transaction: SignedTransaction) {
|
override fun addTransaction(transaction: SignedTransaction) {
|
||||||
records.add(TxRecord.Add(transaction))
|
records.add(TxRecord.Add(transaction))
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.r3corda.node.services.persistence
|
package com.r3corda.node.services.persistence
|
||||||
|
|
||||||
|
import co.paralleluniverse.strands.SettableFuture
|
||||||
import com.google.common.jimfs.Configuration.unix
|
import com.google.common.jimfs.Configuration.unix
|
||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import com.google.common.primitives.Ints
|
import com.google.common.primitives.Ints
|
||||||
@ -12,6 +13,8 @@ import org.junit.After
|
|||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class PerFileTransactionStorageTests {
|
class PerFileTransactionStorageTests {
|
||||||
|
|
||||||
@ -69,6 +72,16 @@ class PerFileTransactionStorageTests {
|
|||||||
assertThat(transactionStorage.transactions).containsExactly(transactions)
|
assertThat(transactionStorage.transactions).containsExactly(transactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `updates are fired`() {
|
||||||
|
val future = SettableFuture<SignedTransaction>()
|
||||||
|
transactionStorage.updates.subscribe { tx -> future.set(tx) }
|
||||||
|
val expected = newTransaction()
|
||||||
|
transactionStorage.addTransaction(expected)
|
||||||
|
val actual = future.get(1, TimeUnit.SECONDS)
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
private fun newTransactionStorage() {
|
private fun newTransactionStorage() {
|
||||||
transactionStorage = PerFileTransactionStorage(storeDir)
|
transactionStorage = PerFileTransactionStorage(storeDir)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user