Fix trans order of subscription transactions stream (#882)

Fix #833
This commit is contained in:
cyan317
2023-10-04 09:11:32 +01:00
committed by GitHub
parent 0818b6ce5b
commit fa42c5c900
4 changed files with 72 additions and 5 deletions

View File

@@ -163,7 +163,7 @@ public:
[&](auto yield) { return backend_->fetchFees(lgrInfo.seq, yield); });
assert(fees);
std::vector<data::TransactionAndMetadata> const transactions = data::synchronousAndRetryOnTimeout(
std::vector<data::TransactionAndMetadata> transactions = data::synchronousAndRetryOnTimeout(
[&](auto yield) { return backend_->fetchAllTransactionsInLedger(lgrInfo.seq, yield); });
auto const ledgerRange = backend_->fetchLedgerRange();
@@ -174,7 +174,17 @@ public:
subscriptions_->pubLedger(lgrInfo, *fees, range, transactions.size());
for (auto const& txAndMeta : transactions)
// order with transaction index
std::sort(transactions.begin(), transactions.end(), [](auto const& t1, auto const& t2) {
ripple::SerialIter iter1{t1.metadata.data(), t1.metadata.size()};
ripple::STObject const object1(iter1, ripple::sfMetadata);
ripple::SerialIter iter2{t2.metadata.data(), t2.metadata.size()};
ripple::STObject const object2(iter2, ripple::sfMetadata);
return object1.getFieldU32(ripple::sfTransactionIndex) <
object2.getFieldU32(ripple::sfTransactionIndex);
});
for (auto& txAndMeta : transactions)
subscriptions_->pubTransaction(txAndMeta, lgrInfo);
subscriptions_->pubBookChanges(lgrInfo, transactions);

View File

@@ -247,3 +247,58 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqStopIsFalse)
EXPECT_TRUE(publisher.publish(SEQ, {}));
ctx.run();
}
TEST_F(ETLLedgerPublisherTest, PublishMultipleTxInOrder)
{
SystemState dummyState;
dummyState.isWriting = true;
auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, 0); // age is 0
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
mockBackendPtr->updateRange(SEQ - 1);
mockBackendPtr->updateRange(SEQ);
publisher.publish(dummyLedgerInfo);
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0);
// mock fetch fee
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
.WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0)));
// mock fetch transactions
EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1);
// t1 index > t2 index
TransactionAndMetadata t1;
t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData();
t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30, 2).getSerializer().peekData();
t1.ledgerSequence = SEQ;
t1.date = 1;
TransactionAndMetadata t2;
t2.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData();
t2.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30, 1).getSerializer().peekData();
t2.ledgerSequence = SEQ;
t2.date = 2;
ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ, _))
.WillByDefault(Return(std::vector<TransactionAndMetadata>{t1, t2}));
// setLastPublishedSequence not in strand, should verify before run
EXPECT_TRUE(publisher.getLastPublishedSequence());
EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ);
MockSubscriptionManager* rawSubscriptionManagerPtr =
dynamic_cast<MockSubscriptionManager*>(mockSubscriptionManagerPtr.get());
EXPECT_CALL(*rawSubscriptionManagerPtr, pubLedger(_, _, fmt::format("{}-{}", SEQ - 1, SEQ), 2)).Times(1);
EXPECT_CALL(*rawSubscriptionManagerPtr, pubBookChanges).Times(1);
// should call pubTransaction t2 first (greater tx index)
Sequence const s;
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction(t2, _)).InSequence(s);
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction(t1, _)).InSequence(s);
ctx.run();
// last publish time should be set
EXPECT_TRUE(publisher.lastPublishAgeSeconds() <= 1);
}

View File

@@ -106,7 +106,8 @@ CreatePaymentTransactionMetaObject(
std::string_view accountId1,
std::string_view accountId2,
int finalBalance1,
int finalBalance2)
int finalBalance2,
uint32_t transactionIndex)
{
ripple::STObject finalFields(ripple::sfFinalFields);
finalFields.setAccountID(ripple::sfAccount, GetAccountIDWithString(accountId1));
@@ -128,7 +129,7 @@ CreatePaymentTransactionMetaObject(
metaArray.push_back(node2);
metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray);
metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS);
metaObj.setFieldU32(ripple::sfTransactionIndex, 0);
metaObj.setFieldU32(ripple::sfTransactionIndex, transactionIndex);
return metaObj;
}

View File

@@ -75,7 +75,8 @@ CreatePaymentTransactionMetaObject(
std::string_view accountId1,
std::string_view accountId2,
int finalBalance1,
int finalBalance2);
int finalBalance2,
uint32_t transactionIndex = 0);
/*
* Create an account root ledger object