diff --git a/plugins/src/main/java/org/tron/plugins/Db.java b/plugins/src/main/java/org/tron/plugins/Db.java index c60b60cff44..8e51133a4fb 100644 --- a/plugins/src/main/java/org/tron/plugins/Db.java +++ b/plugins/src/main/java/org/tron/plugins/Db.java @@ -15,6 +15,7 @@ DbRoot.class, DbCheckpointCompare.class, DbQuery.class, + DbBlockScan.class, }, commandListHeading = "%nCommands:%n%nThe most commonly used db commands are:%n" ) diff --git a/plugins/src/main/java/org/tron/plugins/DbBlockScan.java b/plugins/src/main/java/org/tron/plugins/DbBlockScan.java new file mode 100644 index 00000000000..c36838a1662 --- /dev/null +++ b/plugins/src/main/java/org/tron/plugins/DbBlockScan.java @@ -0,0 +1,107 @@ +package org.tron.plugins; + +import static org.tron.protos.Protocol.Transaction.Contract.ContractType.ShieldedTransferContract; + +import com.google.protobuf.InvalidProtocolBufferException; +import java.io.IOException; +import java.nio.file.Path; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicLong; +import lombok.extern.slf4j.Slf4j; +import me.tongfei.progressbar.ProgressBar; +import org.rocksdb.RocksDBException; +import org.tron.plugins.utils.BlockId; +import org.tron.plugins.utils.Sha256Hash; +import org.tron.plugins.utils.db.DBInterface; +import org.tron.plugins.utils.db.DBIterator; +import org.tron.plugins.utils.db.DbTool; +import org.tron.protos.Protocol; +import picocli.CommandLine; + + +@Slf4j(topic = "block-scan") +@CommandLine.Command(name = "block-scan", + description = "scan data from block.", + exitCodeListHeading = "Exit Codes:%n", + exitCodeList = { + "0:Successful", + "n:query failed,please check toolkit.log"}) +public class DbBlockScan implements Callable { + + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + @CommandLine.Parameters(index = "0", + description = " db path for block") + private Path db; + + @CommandLine.Option(names = {"-h", "--help"}, help = true, description = "display a help message") + private boolean help; + + private static final String DB = "block"; + + private final AtomicLong last = new AtomicLong(0); + private final AtomicLong scanTotal = new AtomicLong(0); + + + @Override + public Integer call() throws Exception { + if (help) { + spec.commandLine().usage(System.out); + return 0; + } + if (!db.toFile().exists()) { + logger.info(" {} does not exist.", db); + spec.commandLine().getErr().println(spec.commandLine().getColorScheme() + .errorText(String.format("%s does not exist.", db))); + return 404; + } + return query(); + } + + + private int query() throws RocksDBException, IOException { + try (DBInterface database = DbTool.getDB(this.db, DB); + DBIterator iterator = database.iterator()) { + iterator.seekToFirst(); + long min = new BlockId(Sha256Hash.wrap(iterator.getKey())).getNum(); + iterator.seekToLast(); + long max = new BlockId(Sha256Hash.wrap(iterator.getKey())).getNum(); + long total = max - min + 1; + spec.commandLine().getOut().format("scan block start from %d to %d ", min, max).println(); + logger.info("scan block start from {} to {}", min, max); + try (ProgressBar pb = new ProgressBar("block-scan", total)) { + for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) { + print(iterator.getKey(), iterator.getValue()); + pb.step(); + pb.setExtraMessage("Reading..."); + scanTotal.getAndIncrement(); + } + } + spec.commandLine().getOut().format("last block has ShieldedTransferContract : %d", + last.get()).println(); + spec.commandLine().getOut().format("total scan block size: %d", scanTotal.get()).println(); + logger.info("last block has ShieldedTransferContract : {}", last.get()); + logger.info("total scan block size: {}", scanTotal.get()); + } + return 0; + } + + private void print(byte[] k, byte[] v) { + try { + Protocol.Block block = Protocol.Block.parseFrom(v); + long num = block.getBlockHeader().getRawData().getNumber(); + boolean ret = block.getTransactionsList().stream().anyMatch(this::check); + if (ret) { + last.set(num); + } + } catch (InvalidProtocolBufferException e) { + logger.error("{},{}", k, v); + } + } + + private boolean check(Protocol.Transaction trans) { + return trans.getRawData().getContractList() + .stream() + .anyMatch(c -> c.getType() == ShieldedTransferContract); + } +} \ No newline at end of file diff --git a/plugins/src/main/java/org/tron/plugins/utils/BlockId.java b/plugins/src/main/java/org/tron/plugins/utils/BlockId.java new file mode 100644 index 00000000000..08a01894832 --- /dev/null +++ b/plugins/src/main/java/org/tron/plugins/utils/BlockId.java @@ -0,0 +1,54 @@ +package org.tron.plugins.utils; + +import com.google.common.primitives.Longs; +import java.util.Arrays; + +public class BlockId extends Sha256Hash { + + private final long num; + + public BlockId(Sha256Hash blockId) { + super(blockId.getBytes()); + byte[] blockNum = new byte[8]; + System.arraycopy(blockId.getBytes(), 0, blockNum, 0, 8); + num = Longs.fromByteArray(blockNum); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || (getClass() != o.getClass() && !(o instanceof Sha256Hash))) { + return false; + } + return Arrays.equals(getBytes(), ((Sha256Hash) o).getBytes()); + } + + public String getString() { + return "Num:" + num + ",ID:" + super.toString(); + } + + @Override + public String toString() { + return super.toString(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public int compareTo(Sha256Hash other) { + if (other.getClass().equals(BlockId.class)) { + long otherNum = ((BlockId) other).getNum(); + return Long.compare(num, otherNum); + } + return super.compareTo(other); + } + + public long getNum() { + return num; + } +} \ No newline at end of file