From a486625ae1a3e7f95484ddaa06c9425d2cf8d674 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Tue, 19 Sep 2023 21:11:01 +0800 Subject: [PATCH] fix(db/trans-cache): avoid recovering a wrong cached data --- .../org/tron/core/db/TransactionCache.java | 8 ++++++-- .../org/tron/core/db2/common/TxCacheDB.java | 20 ++++++++++++++----- .../org/tron/core/config/DefaultConfig.java | 7 ------- .../main/java/org/tron/core/db/Manager.java | 2 +- .../org/tron/core/db/TxCacheDBInitTest.java | 20 +++++++++++++++---- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/chainbase/src/main/java/org/tron/core/db/TransactionCache.java b/chainbase/src/main/java/org/tron/core/db/TransactionCache.java index 70b42ca7226..58ed9be9145 100644 --- a/chainbase/src/main/java/org/tron/core/db/TransactionCache.java +++ b/chainbase/src/main/java/org/tron/core/db/TransactionCache.java @@ -3,16 +3,20 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; import org.tron.core.capsule.BytesCapsule; import org.tron.core.db2.common.TxCacheDB; +import org.tron.core.store.DynamicPropertiesStore; @Slf4j +@Component public class TransactionCache extends TronStoreWithRevoking { @Autowired public TransactionCache(@Value("trans-cache") String dbName, - RecentTransactionStore recentTransactionStore) { - super(new TxCacheDB(dbName, recentTransactionStore)); + @Autowired RecentTransactionStore recentTransactionStore, + @Autowired DynamicPropertiesStore dynamicPropertiesStore) { + super(new TxCacheDB(dbName, recentTransactionStore, dynamicPropertiesStore)); } public void initCache() { diff --git a/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java b/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java index cefe014959e..8e5a2ee6787 100644 --- a/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java +++ b/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java @@ -40,6 +40,7 @@ import org.tron.core.db.RecentTransactionItem; import org.tron.core.db.RecentTransactionStore; import org.tron.core.db.common.iterator.DBIterator; +import org.tron.core.store.DynamicPropertiesStore; @Slf4j(topic = "DB") public class TxCacheDB implements DB, Flusher { @@ -59,7 +60,6 @@ public class TxCacheDB implements DB, Flusher { private BloomFilter[] bloomFilters = new BloomFilter[2]; // filterStartBlock record the start block of the active filter private volatile long filterStartBlock = INVALID_BLOCK; - private volatile long currentBlockNum = INVALID_BLOCK; // currentFilterIndex records the index of the active filter private volatile int currentFilterIndex = 0; @@ -75,6 +75,8 @@ public class TxCacheDB implements DB, Flusher { // replace persistentStore and optimizes startup performance private RecentTransactionStore recentTransactionStore; + private DynamicPropertiesStore dynamicPropertiesStore; + private final Path cacheFile0; private final Path cacheFile1; private final Path cacheProperties; @@ -85,11 +87,13 @@ public class TxCacheDB implements DB, Flusher { @Setter private volatile boolean alive; - public TxCacheDB(String name, RecentTransactionStore recentTransactionStore) { + public TxCacheDB(String name, RecentTransactionStore recentTransactionStore, + DynamicPropertiesStore dynamicPropertiesStore) { this.name = name; this.TRANSACTION_COUNT = CommonParameter.getInstance().getStorage().getEstimatedBlockTransactions(); this.recentTransactionStore = recentTransactionStore; + this.dynamicPropertiesStore = dynamicPropertiesStore; String dbEngine = CommonParameter.getInstance().getStorage().getDbEngine(); if ("LEVELDB".equals(dbEngine.toUpperCase())) { this.persistentStore = new LevelDB( @@ -211,7 +215,6 @@ public void put(byte[] key, byte[] value) { MAX_BLOCK_SIZE * TRANSACTION_COUNT); } bloomFilters[currentFilterIndex].put(key); - currentBlockNum = blockNum; if (lastMetricBlock != blockNum) { lastMetricBlock = blockNum; Metrics.gaugeSet(MetricKeys.Gauge.TX_CACHE, @@ -356,8 +359,14 @@ private boolean loadProperties() { Properties properties = new Properties(); properties.load(r); filterStartBlock = Long.parseLong(properties.getProperty("filterStartBlock")); - currentBlockNum = Long.parseLong(properties.getProperty("currentBlockNum")); + long currentBlockNum = Long.parseLong(properties.getProperty("currentBlockNum")); + long currentBlockNumFromDB = dynamicPropertiesStore.getLatestBlockHeaderNumberFromDB(); currentFilterIndex = Integer.parseInt(properties.getProperty("currentFilterIndex")); + if (currentBlockNum != currentBlockNumFromDB) { + throw new IllegalStateException( + String.format("currentBlockNum not match. filter: %d, db: %d", + currentBlockNum, currentBlockNumFromDB)); + } logger.info("filterStartBlock: {}, currentBlockNum: {}, currentFilterIndex: {}, load done.", filterStartBlock, currentBlockNum, currentFilterIndex); return true; @@ -369,6 +378,7 @@ private boolean loadProperties() { private void writeProperties() { try (Writer w = Files.newBufferedWriter(this.cacheProperties, StandardCharsets.UTF_8)) { Properties properties = new Properties(); + long currentBlockNum = dynamicPropertiesStore.getLatestBlockHeaderNumberFromDB(); properties.setProperty("filterStartBlock", String.valueOf(filterStartBlock)); properties.setProperty("currentBlockNum", String.valueOf(currentBlockNum)); properties.setProperty("currentFilterIndex", String.valueOf(currentFilterIndex)); @@ -382,7 +392,7 @@ private void writeProperties() { @Override public TxCacheDB newInstance() { - return new TxCacheDB(name, recentTransactionStore); + return new TxCacheDB(name, recentTransactionStore, dynamicPropertiesStore); } @Override diff --git a/framework/src/main/java/org/tron/core/config/DefaultConfig.java b/framework/src/main/java/org/tron/core/config/DefaultConfig.java index 2c4c2a8717e..7cc32d9a581 100755 --- a/framework/src/main/java/org/tron/core/config/DefaultConfig.java +++ b/framework/src/main/java/org/tron/core/config/DefaultConfig.java @@ -11,9 +11,7 @@ import org.springframework.context.annotation.Import; import org.tron.common.utils.StorageUtils; import org.tron.core.config.args.Args; -import org.tron.core.db.RecentTransactionStore; import org.tron.core.db.RevokingDatabase; -import org.tron.core.db.TransactionCache; import org.tron.core.db.backup.BackupRocksDBAspect; import org.tron.core.db.backup.NeedBeanCondition; import org.tron.core.db2.core.SnapshotManager; @@ -93,11 +91,6 @@ public HttpApiOnPBFTService getHttpApiOnPBFTService() { return null; } - @Bean - public TransactionCache transactionCache() { - return new TransactionCache("trans-cache", appCtx.getBean(RecentTransactionStore.class)); - } - @Bean @Conditional(NeedBeanCondition.class) public BackupRocksDBAspect backupRocksDBAspect() { diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index 9a2f53dd69a..b0d902eb84a 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -179,8 +179,8 @@ public class Manager { @Setter public boolean eventPluginLoaded = false; private int maxTransactionPendingSize = Args.getInstance().getMaxTransactionPendingSize(); - @Autowired(required = false) @Getter + @Autowired private TransactionCache transactionCache; @Autowired private KhaosDatabase khaosDb; diff --git a/framework/src/test/java/org/tron/core/db/TxCacheDBInitTest.java b/framework/src/test/java/org/tron/core/db/TxCacheDBInitTest.java index e415476d739..b976cf5f2da 100644 --- a/framework/src/test/java/org/tron/core/db/TxCacheDBInitTest.java +++ b/framework/src/test/java/org/tron/core/db/TxCacheDBInitTest.java @@ -15,6 +15,7 @@ import org.tron.core.capsule.BytesCapsule; import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; +import org.tron.core.store.DynamicPropertiesStore; import org.tron.keystore.Wallet; @Slf4j @@ -53,11 +54,22 @@ public void reload() { queryTransaction(); db.close(); defaultListableBeanFactory.destroySingleton("transactionCache"); - TransactionCache transactionCache = new TransactionCache("transactionCache", - context.getBean(RecentTransactionStore.class)); - transactionCache.initCache(); - defaultListableBeanFactory.registerSingleton("transactionCache",transactionCache); + db = new TransactionCache("transactionCache", + context.getBean(RecentTransactionStore.class), + context.getBean(DynamicPropertiesStore.class)); + db.initCache(); + defaultListableBeanFactory.registerSingleton("transactionCache",db); queryTransaction(); + db.close(); + defaultListableBeanFactory.destroySingleton("transactionCache"); + db = new TransactionCache("transactionCache", + context.getBean(RecentTransactionStore.class), + context.getBean(DynamicPropertiesStore.class)); + DynamicPropertiesStore dynamicPropertiesStore = context.getBean(DynamicPropertiesStore.class); + dynamicPropertiesStore.saveLatestBlockHeaderNumber(1); + defaultListableBeanFactory.registerSingleton("transactionCache",db); + db.initCache(); + Assert.assertFalse(db.has(hash[65538])); } private void putTransaction() {