Skip to content

Commit 58e39b0

Browse files
committed
update txs infos
1 parent 2b52ee8 commit 58e39b0

File tree

4 files changed

+182
-117
lines changed

4 files changed

+182
-117
lines changed

nodecore-spv/src/main/java/org/veriblock/spv/SpvContext.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ class SpvContext(
148148
logger.info { "SPV Disconnected" }
149149
}
150150
)
151-
startPendingTransactionsUpdateTask()
152151
startAddressStateUpdateTask()
153152

154153
Threading.PEER_TABLE_SCOPE.launchWithFixedDelay(40_000, 120_000) {

nodecore-spv/src/main/java/org/veriblock/spv/net/PeerEventListener.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ class PeerEventListener(
115115
))
116116
return
117117
}
118-
// TODO: add mempool management
118+
val fullBlock = MessageSerializer.deserialize(event.content)
119+
pendingTransactionContainer.updateTransactionsByBlock(fullBlock)
119120
} catch (e: Exception) {
120121
logger.warn("Could not queue network block $blockHash", e)
121122
}

nodecore-spv/src/main/java/org/veriblock/spv/service/PendingTransactionContainer.kt

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,24 @@ import kotlinx.coroutines.CoroutineScope
44
import kotlinx.coroutines.asCoroutineDispatcher
55
import kotlinx.coroutines.delay
66
import kotlinx.coroutines.launch
7+
import nodecore.api.grpc.RpcOutput
8+
import nodecore.api.grpc.RpcTransaction
79
import nodecore.api.grpc.RpcTransactionUnion
810
import nodecore.api.grpc.utilities.ByteStringUtility
11+
import nodecore.api.grpc.utilities.extensions.toHex
12+
import nodecore.api.grpc.utilities.extensions.toProperAddressType
913
import org.veriblock.core.crypto.VbkTxId
14+
import org.veriblock.core.crypto.asVbkTxId
1015
import org.veriblock.core.utilities.createLogger
1116
import org.veriblock.sdk.models.Address
1217
import org.veriblock.sdk.models.VeriBlockBlock
1318
import org.veriblock.spv.SpvContext
19+
import org.veriblock.spv.model.FullBlock
1420
import org.veriblock.spv.model.Transaction
1521
import org.veriblock.spv.serialization.MessageSerializer
1622
import org.veriblock.spv.util.SpvEventBus
1723
import org.veriblock.spv.util.Threading
24+
import java.lang.IllegalArgumentException
1825
import java.util.concurrent.ConcurrentHashMap
1926
import java.util.concurrent.locks.ReentrantLock
2027
import kotlin.concurrent.withLock
@@ -27,10 +34,13 @@ class PendingTransactionContainer(
2734
) {
2835
// TODO(warchant): use Address as a key, instead of String
2936
private val pendingTransactionsByAddress: MutableMap<String, MutableList<Transaction>> = ConcurrentHashMap()
30-
private val confirmedTransactionReplies: MutableMap<VbkTxId, TransactionInfo> = ConcurrentHashMap()
31-
private val confirmedTransactions: MutableMap<VbkTxId, Transaction> = ConcurrentHashMap()
3237
private val pendingTransactions: MutableMap<VbkTxId, Transaction> = ConcurrentHashMap()
33-
private val transactionsToMonitor: MutableSet<VbkTxId> = ConcurrentHashMap.newKeySet()
38+
// FIXME: add converting between TransactionData <-> Transaction and delete this
39+
private val pendingTransactionsInfo: MutableMap<VbkTxId, TransactionInfo> = ConcurrentHashMap()
40+
41+
private val addedToBlockchainTransactions: MutableMap<VbkTxId, Transaction> = ConcurrentHashMap()
42+
// FIXME: add converting between TransactionData <-> Transaction and delete this
43+
private val addedToBlockchainTransactionsInfo: MutableMap<VbkTxId, TransactionInfo> = ConcurrentHashMap()
3444

3545
private val lock = ReentrantLock()
3646

@@ -45,48 +55,50 @@ class PendingTransactionContainer(
4555
.sortedBy { it.value.getSignatureIndex() }
4656
.map { it.key }
4757
.toSet()
48-
return pendingTransactions + transactionsToMonitor
58+
return pendingTransactions
4959
}
5060

5161
fun getTransactionInfo(txId: VbkTxId): TransactionInfo? {
52-
confirmedTransactionReplies[txId]?.let {
62+
pendingTransactionsInfo[txId]?.let {
5363
return it
5464
}
55-
if (!pendingTransactions.containsKey(txId)) {
56-
transactionsToMonitor.add(txId)
65+
addedToBlockchainTransactionsInfo[txId]?.let {
66+
return it
5767
}
5868
return null
5969
}
6070

6171
fun updateTransactionInfo(transactionInfo: TransactionInfo) = lock.withLock {
6272
val transaction = transactionInfo.transaction
63-
if (pendingTransactions.containsKey(transaction.txId) || transactionsToMonitor.contains(transaction.txId)) {
64-
confirmedTransactionReplies[transaction.txId] = transactionInfo
73+
if (pendingTransactions.containsKey(transaction.txId)) {
74+
pendingTransactionsInfo[transaction.txId] = transactionInfo
6575
val pendingTx = pendingTransactions[transaction.txId]
6676
if (pendingTx != null) {
67-
confirmedTransactions[transaction.txId] = pendingTx
6877
if (pendingTx.getSignatureIndex() > lastConfirmedSignatureIndex) {
6978
lastConfirmedSignatureIndex = pendingTx.getSignatureIndex()
7079
}
7180
}
7281
if (transactionInfo.confirmations > 0) {
82+
addedToBlockchainTransactions[transaction.txId] = pendingTx!!
83+
addedToBlockchainTransactionsInfo[transaction.txId] = pendingTransactionsInfo[transaction.txId]!!
84+
7385
pendingTransactions.remove(transaction.txId)
74-
transactionsToMonitor.remove(transaction.txId)
86+
pendingTransactionsInfo.remove(transaction.txId)
7587
pendingTransactionsByAddress[transaction.sourceAddress]?.removeIf { it.txId == transaction.txId }
7688
}
7789
}
7890

7991
// Prune confirmed transactions
80-
if (confirmedTransactionReplies.size > 10_000) {
81-
val topConfirmedBlockHeight = confirmedTransactionReplies.values.maxOf { it.blockNumber }
82-
val txToRemove = confirmedTransactionReplies.values.asSequence().filter {
92+
if (addedToBlockchainTransactionsInfo.size > 10_000) {
93+
val topConfirmedBlockHeight = addedToBlockchainTransactionsInfo.values.maxOf { it.blockNumber }
94+
val txToRemove = addedToBlockchainTransactionsInfo.values.asSequence().filter {
8395
it.blockNumber < topConfirmedBlockHeight - 1_000
8496
}.map {
8597
it.transaction.txId
8698
}
8799
for (txId in txToRemove) {
88-
confirmedTransactionReplies.remove(txId)
89-
confirmedTransactions.remove(txId)
100+
addedToBlockchainTransactions.remove(txId)
101+
addedToBlockchainTransactionsInfo.remove(txId)
90102
}
91103
}
92104
}
@@ -170,7 +182,6 @@ class PendingTransactionContainer(
170182
logger.info { "All the transactions for that address will be pruned in order to prevent further transactions from being rejected." }
171183
for (tx in newTransactions) {
172184
pendingTransactions.remove(tx.txId)
173-
transactionsToMonitor.remove(tx.txId)
174185
}
175186
newTransactions.clear()
176187
}
@@ -182,21 +193,75 @@ class PendingTransactionContainer(
182193
}
183194

184195
private fun handleRemovedBestBlock(removedBlock: VeriBlockBlock) = lock.withLock {
185-
val reorganizedTransactions = confirmedTransactionReplies.values.filter {
196+
val reorganizedTransactions = addedToBlockchainTransactionsInfo.values.filter {
186197
it.blockNumber == removedBlock.height
187198
}.mapNotNull {
188-
confirmedTransactions[it.transaction.txId]
199+
addedToBlockchainTransactions[it.transaction.txId]
189200
}
190201
for (transaction in reorganizedTransactions) {
191-
confirmedTransactionReplies.remove(transaction.txId)
192-
confirmedTransactions.remove(transaction.txId)
202+
addedToBlockchainTransactions.remove(transaction.txId)
193203
addTransaction(transaction)
194204
}
195205
}
196206

207+
fun updateTransactionsByBlock(block: FullBlock) = lock.withLock {
208+
/*
209+
* We are removing only transactions that match the exact String from the block. If the block validation
210+
* fails, NO transactions are removed from the transaction pool.
211+
*/
212+
val normalTransactions = block.normalTransactions
213+
?: throw IllegalArgumentException(
214+
"removeTransactionsInBlock cannot be called with a block with a " +
215+
"null transaction set!"
216+
)
217+
var allSuccessful = true
218+
for (transaction in normalTransactions) {
219+
// FIXME: convert StandardTransaction to TransactionData
220+
val builder = transaction.getSignedMessageBuilder(context.config.networkParameters)
221+
val rpcTx = builder.build()
222+
val txData = rpcTx.transaction.toModel()
223+
224+
val txInfo = TransactionInfo(
225+
blockNumber = block.height,
226+
timestamp = block.timestamp,
227+
transaction = txData,
228+
confirmations = context.blockchain.getChainHeadIndex().height + 1 - block.height,
229+
blockHash = block.hash.toString(),
230+
merklePath = "", // FIXME: is it possible to calculate merklePath in SPV?
231+
endorsedBlockHash = "", // FIXME: for POP
232+
bitcoinBlockHash = "", // FIXME: for POP
233+
bitcoinTxId = "", // FIXME: for POP
234+
bitcoinConfirmations = 0, // FIXME: for POP
235+
)
236+
updateTransactionInfo(txInfo)
237+
}
238+
}
239+
197240
enum class AddTransactionResult {
198241
SUCCESS,
199242
INVALID,
200243
DUPLICATE
201244
}
245+
246+
private fun RpcTransaction.toModel() = TransactionData(
247+
type = TransactionType.valueOf(type.name),
248+
sourceAddress = sourceAddress.toProperAddressType(),
249+
sourceAmount = sourceAmount,
250+
outputs = outputsList.map { it.toModel() },
251+
transactionFee = transactionFee,
252+
data = data.toHex(),
253+
bitcoinTransaction = bitcoinTransaction.toHex(),
254+
endorsedBlockHeader = endorsedBlockHeader.toHex(),
255+
bitcoinBlockHeaderOfProof = "",
256+
merklePath = merklePath,
257+
contextBitcoinBlockHeaders = listOf(),
258+
timestamp = timestamp,
259+
size = size,
260+
txId = txId.toByteArray().asVbkTxId()
261+
)
262+
263+
private fun RpcOutput.toModel() = OutputData(
264+
address = address.toHex(),
265+
amount = amount
266+
)
202267
}

0 commit comments

Comments
 (0)