Skip to content

Commit

Permalink
feat(state-root): add check.root.disable
Browse files Browse the repository at this point in the history
  • Loading branch information
halibobo1205 committed Jul 29, 2024
1 parent f1d6cd1 commit 3ada991
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 17 deletions.
10 changes: 10 additions & 0 deletions chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,16 @@ public String toString() {
return toStringBuff.toString();
}

public Sha256Hash getStateRoot() {
ByteString stateRoot = this.block.getBlockHeader().getStateRoot();
return stateRoot.isEmpty() ? Sha256Hash.ZERO_HASH : Sha256Hash.wrap(stateRoot);
}

public void clearStateRoot() {
BlockHeader blockHeader = this.block.getBlockHeader().toBuilder().clearStateRoot().build();
this.block = this.block.toBuilder().setBlockHeader(blockHeader).build();
}

public static class BlockId extends Sha256Hash {

private long num;
Expand Down
30 changes: 26 additions & 4 deletions chainbase/src/main/java/org/tron/core/service/RootHashService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,36 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.tron.common.context.GlobalContext;
import org.tron.common.error.TronDBException;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.MerkleRoot;
import org.tron.common.utils.Pair;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.db.TronDatabase;
import org.tron.core.store.CorruptedCheckpointStore;

@Slf4j(topic = "DB")
@Component
public class RootHashService {

private static final byte[] HEADER_KEY = Bytes.concat(simpleEncode("properties"),
"latest_block_header_number".getBytes());

private static Optional<CorruptedCheckpointStore> corruptedCheckpointStore = Optional.empty();

@Autowired
public RootHashService(@Autowired CorruptedCheckpointStore corruptedCheckpointStore) {
RootHashService.corruptedCheckpointStore = Optional.ofNullable(corruptedCheckpointStore);
}

public static Pair<Optional<Long>, Sha256Hash> getRootHash(Map<byte[], byte[]> rows) {
AtomicReference<Optional<Long>> height = new AtomicReference<>(Optional.empty());
List<Sha256Hash> ids = Streams.stream(rows.entrySet()).parallel().map(entry -> {
Expand All @@ -29,10 +44,17 @@ public static Pair<Optional<Long>, Sha256Hash> getRootHash(Map<byte[], byte[]> r
}
return getHash(entry);
}).sorted().collect(Collectors.toList());
Sha256Hash root = MerkleRoot.root(ids);
logger.info("blockNum: {}, stateRoot: {}",
height.get().orElseThrow(() -> new IllegalStateException("blockNum is null")), root);
return new Pair<>(height.get(), root);
Sha256Hash actual = MerkleRoot.root(ids);
long num = height.get().orElseThrow(() -> new TronDBException("blockNum is null"));
Optional<Sha256Hash> expected = GlobalContext.popBlockHash(num);
if (expected.isPresent() && !Objects.equals(expected.get(), actual)) {
corruptedCheckpointStore.ifPresent(TronDatabase::reset);
corruptedCheckpointStore.ifPresent(store -> store.updateByBatch(rows));
throw new TronDBException(String.format(
"Root hash mismatch for blockNum: %s, expected: %s, actual: %s", num, expected, actual));
}

return new Pair<>(height.get(), actual);
}

private static Sha256Hash getHash(Map.Entry<byte[], byte[]> entry) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.tron.common.storage.WriteOptionsWrapper;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Pair;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.db.TronDatabase;
Expand Down Expand Up @@ -88,10 +87,9 @@ public void close() {

@Override
public void updateByBatch(Map<byte[], byte[]> rows, WriteOptionsWrapper writeOptions) {
super.updateByBatch(rows, writeOptions);
Pair<Optional<Long>, Sha256Hash> ret = RootHashService.getRootHash(rows);
ret.getKey().ifPresent(height -> stateRootStore.put(ByteArray.fromLong(height),
ret.getValue().getBytes()));
super.updateByBatch(rows, writeOptions);
ret.getKey().ifPresent(height -> stateRootStore.put(height, ret.getValue()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.tron.common.storage.WriteOptionsWrapper;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Pair;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.db.TronDatabase;
Expand Down Expand Up @@ -59,9 +58,8 @@ public Spliterator spliterator() {

@Override
public void updateByBatch(Map<byte[], byte[]> rows, WriteOptionsWrapper writeOptions) {
super.updateByBatch(rows, writeOptions);
Pair<Optional<Long>, Sha256Hash> ret = RootHashService.getRootHash(rows);
ret.getKey().ifPresent(height -> stateRootStore.put(ByteArray.fromLong(height),
ret.getValue().getBytes()));
super.updateByBatch(rows, writeOptions);
ret.getKey().ifPresent(height -> stateRootStore.put(height, ret.getValue()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.tron.core.store;

import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Spliterator;
import java.util.function.Consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.tron.core.db.TronDatabase;
import org.tron.core.exception.BadItemException;
import org.tron.core.exception.ItemNotFoundException;

@Component
public class CorruptedCheckpointStore extends TronDatabase<byte[]> {

@Autowired
public CorruptedCheckpointStore(@Value("corrupted-checkpoint") String dbName) {
super(dbName);
}

@Override
public void put(byte[] key, byte[] item) {
}

@Override
public void delete(byte[] key) {
}

@Override
public byte[] get(byte[] key)
throws InvalidProtocolBufferException, ItemNotFoundException, BadItemException {
return null;
}

@Override
public boolean has(byte[] key) {
return false;
}

@Override
public void forEach(Consumer action) {

}

@Override
public Spliterator spliterator() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.db.TronDatabase;
import org.tron.core.db.common.iterator.DBIterator;

Expand All @@ -31,6 +32,11 @@ public void put(byte[] key, byte[] item) {
dbSource.putData(key, item);
}

public void put(long key, Sha256Hash root) {
logger.info("block: {}, stateRoot: {}", key, root);
this.put(ByteArray.fromLong(key), root.getBytes());
}

@Override
public void delete(byte[] key) {
throw new UnsupportedOperationException();
Expand Down
27 changes: 26 additions & 1 deletion common/src/main/java/org/tron/common/context/GlobalContext.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package org.tron.common.context;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.tron.common.utils.Sha256Hash;

public class GlobalContext {

private static final ThreadLocal<Long> HEADER = new ThreadLocal<>();

private static final ThreadLocal<Boolean> LOG = ThreadLocal.withInitial(() -> true);

private static final ThreadLocal<Map<Long, Sha256Hash>> BLOCK_HASHES =
ThreadLocal.withInitial(() -> Collections.synchronizedMap(new HashMap<>()));

private GlobalContext() {
}

Expand All @@ -34,4 +40,23 @@ public static void enableLog() {
public static void disableLog() {
LOG.set(false);
}

public static void putBlockHash(long blockNumber, Sha256Hash blockHash) {
BLOCK_HASHES.get().put(blockNumber, blockHash);
}

public static Optional<Sha256Hash> popBlockHash(long blockNumber) {
return Optional.ofNullable(BLOCK_HASHES.get().remove(blockNumber));
}

public static void clearBlockHashes() {
BLOCK_HASHES.get().clear();
}

public static void clear() {
removeHeader();
enableLog();
clearBlockHashes();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,11 @@ public class CommonParameter {
@Setter
public long maxCreateAccountTxSize = 1000L;

@Getter
@Setter
@Parameter(names = {"--check.root.disable"}, description = "disable check state root")
public boolean checkRootHashDisable = false;

private static double calcMaxTimeRatio() {
//return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1)));
return 5.0;
Expand Down
18 changes: 14 additions & 4 deletions framework/src/main/java/org/tron/core/db/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -1017,8 +1017,20 @@ public void pushVerifiedBlock(BlockCapsule block) throws ContractValidateExcepti
NonCommonBlockException, BadNumberBlockException, BadBlockException, ZksnarkException,
EventBloomException {
block.generatedByMyself = true;
long start = System.currentTimeMillis();
pushBlock(block);
final long start = System.currentTimeMillis();
Sha256Hash stateRoot = block.getStateRoot();
if (!CommonParameter.getInstance().isCheckRootHashDisable()
&& !Objects.equals(Sha256Hash.ZERO_HASH, stateRoot)) {
GlobalContext.putBlockHash(block.getNum(), stateRoot);
}
// clear stateRoot for block
block.clearStateRoot();
try {
GlobalContext.setHeader(block.getNum());
pushBlock(block);
} finally {
GlobalContext.removeHeader();
}
logger.info("Push block cost: {} ms, blockNum: {}, blockHash: {}, trx count: {}.",
System.currentTimeMillis() - start,
block.getNum(),
Expand Down Expand Up @@ -1220,7 +1232,6 @@ public void pushBlock(final BlockCapsule block)
setBlockWaitLock(true);
try {
synchronized (this) {
GlobalContext.setHeader(block.getNum());
Metrics.histogramObserve(blockedTimer.get());
blockedTimer.remove();
long headerNumber = getDynamicPropertiesStore().getLatestBlockHeaderNumber();
Expand Down Expand Up @@ -1360,7 +1371,6 @@ public void pushBlock(final BlockCapsule block)
}
} finally {
setBlockWaitLock(false);
GlobalContext.removeHeader();
}
}

Expand Down

0 comments on commit 3ada991

Please sign in to comment.