diff --git a/src/main/java/org/tron/common/utils/ForkController.java b/src/main/java/org/tron/common/utils/ForkController.java new file mode 100644 index 00000000000..333b181c507 --- /dev/null +++ b/src/main/java/org/tron/common/utils/ForkController.java @@ -0,0 +1,90 @@ +package org.tron.common.utils; + +import com.google.protobuf.ByteString; +import java.util.Arrays; +import java.util.List; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.tron.core.capsule.BlockCapsule; +import org.tron.core.capsule.TransactionCapsule; +import org.tron.core.config.Parameter.ChainConstant; +import org.tron.core.db.Manager; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; + +@Slf4j +@Component +public class ForkController { + + public static final int DISCARD_SCOPE = ContractType.UpdateAssetContract.getNumber(); + + @Getter + private Manager manager; + private volatile int[] slots = new int[0]; + private boolean forked; + + public void init(Manager manager) { + this.manager = manager; + forked = manager.getDynamicPropertiesStore().getForked(); + } + + public synchronized boolean shouldBeForked() { + if (forked) { + logger.info("*****shouldBeForked:" + true); + return true; + } + + for (int version : slots) { + if (version != ChainConstant.version) { + logger.info("*****shouldBeForked:" + false); + return false; + } + } + + // todo add Maintenance or block number + forked = true; + manager.getDynamicPropertiesStore().forked(); + logger.info("*****shouldBeForked:" + true); + return true; + } + + public synchronized boolean forkOrNot(TransactionCapsule capsule) { + logger.info("*****forkOrNot:" + (shouldBeForked() + || capsule.getInstance().getRawData().getContractList().get(0).getType().getNumber() + <= DISCARD_SCOPE)); + return shouldBeForked() + || capsule.getInstance().getRawData().getContractList().get(0).getType().getNumber() + <= DISCARD_SCOPE; + } + + public synchronized void update(BlockCapsule blockCapsule) { + if (forked) { + return; + } + + List witnesses = manager.getWitnessController().getActiveWitnesses(); + if (witnesses.size() != slots.length) { + slots = new int[witnesses.size()]; + } + + ByteString witness = blockCapsule.getWitnessAddress(); + int slot = witnesses.indexOf(witness); + if (slot < 0) { + return; + } + slots[slot] = blockCapsule.getInstance().getBlockHeader().getRawData().getVersion(); + + logger.info( + "*******update:" + Arrays.toString(slots) + + ",witness size:" + witnesses.size() + + "," + slots + + ",slot:" + slot + + ",version:" + blockCapsule.getInstance().getBlockHeader().getRawData().getVersion() + ); + } + + public void reset() { + Arrays.fill(slots, 0); + } + +} diff --git a/src/main/java/org/tron/core/Wallet.java b/src/main/java/org/tron/core/Wallet.java index 36fe49a3c43..e476b3e7e44 100755 --- a/src/main/java/org/tron/core/Wallet.java +++ b/src/main/java/org/tron/core/Wallet.java @@ -20,7 +20,6 @@ import com.google.common.primitives.Longs; import com.google.protobuf.ByteString; -import java.math.BigInteger; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -230,8 +229,7 @@ public static byte[] generateContractAddress(Transaction trx) { } - public static byte[] generateContractAddress(byte[] ownerAddress,byte[] txRawDataHash) { - + public static byte[] generateContractAddress(byte[] ownerAddress, byte[] txRawDataHash) { byte[] combined = new byte[txRawDataHash.length + ownerAddress.length]; System.arraycopy(txRawDataHash, 0, combined, 0, txRawDataHash.length); @@ -241,7 +239,7 @@ public static byte[] generateContractAddress(byte[] ownerAddress,byte[] txRawDat } - public static byte[] generateContractAddress(byte[] transactionRootId, long nonce){ + public static byte[] generateContractAddress(byte[] transactionRootId, long nonce) { byte[] nonceBytes = Longs.toByteArray(nonce); byte[] combined = new byte[transactionRootId.length + nonceBytes.length]; System.arraycopy(transactionRootId, 0, combined, 0, transactionRootId.length); @@ -407,8 +405,11 @@ public GrpcAPI.Return broadcastTransaction(Transaction signaturedTransaction) { dbManager.getTransactionIdCache().put(trx.getTransactionId(), true); } - dbManager.pushTransaction(trx); - p2pNode.broadcast(message); + if (dbManager.getForkController().forkOrNot(trx)) { + dbManager.pushTransaction(trx); + p2pNode.broadcast(message); + } + return builder.setResult(true).setCode(response_code.SUCCESS).build(); } catch (ValidateSignatureException e) { logger.info(e.getMessage()); diff --git a/src/main/java/org/tron/core/capsule/BlockCapsule.java b/src/main/java/org/tron/core/capsule/BlockCapsule.java index 0a7ecf0b683..5e5346ebb62 100755 --- a/src/main/java/org/tron/core/capsule/BlockCapsule.java +++ b/src/main/java/org/tron/core/capsule/BlockCapsule.java @@ -33,6 +33,7 @@ import org.tron.common.utils.Sha256Hash; import org.tron.common.utils.Time; import org.tron.core.capsule.utils.MerkleTree; +import org.tron.core.config.Parameter.ChainConstant; import org.tron.core.exception.BadItemException; import org.tron.core.exception.ValidateSignatureException; import org.tron.protos.Protocol.Block; @@ -128,7 +129,9 @@ public BlockCapsule(long number, Sha256Hash hash, long when, ByteString witnessA .setNumber(number) .setParentHash(hash.getByteString()) .setTimestamp(when) - .setWitnessAddress(witnessAddress).build(); + .setVersion(ChainConstant.version) + .setWitnessAddress(witnessAddress) + .build(); // block header BlockHeader.Builder blockHeaderBuild = BlockHeader.newBuilder(); diff --git a/src/main/java/org/tron/core/config/Parameter.java b/src/main/java/org/tron/core/config/Parameter.java index faf4064dc16..7b0cdfc7a95 100644 --- a/src/main/java/org/tron/core/config/Parameter.java +++ b/src/main/java/org/tron/core/config/Parameter.java @@ -23,7 +23,7 @@ interface ChainConstant { int BLOCK_FILLED_SLOTS_NUMBER = 128; int MAX_VOTE_NUMBER = 30; int MAX_FROZEN_NUMBER = 1; - + int version = 1; } interface NodeConstant { diff --git a/src/main/java/org/tron/core/db/DynamicPropertiesStore.java b/src/main/java/org/tron/core/db/DynamicPropertiesStore.java index f4a13e25232..3d273c66b46 100755 --- a/src/main/java/org/tron/core/db/DynamicPropertiesStore.java +++ b/src/main/java/org/tron/core/db/DynamicPropertiesStore.java @@ -112,11 +112,15 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] STORAGE_EXCHANGE_TAX_RATE = "STORAGE_EXCHANGE_TAX_RATE".getBytes(); + private static final byte[] FORK_CONTROLLER = "FORK_CONTROLLER".getBytes(); + //This value is only allowed to be 0, 1, -1 private static final byte[] REMOVE_THE_POWER_OF_THE_GR = "REMOVE_THE_POWER_OF_THE_GR".getBytes(); //If the parameter is larger than 0, the contract is allowed to be created. - private static final byte[] ALLOW_CREATION_OF_CONTRACTS = "ALLOW_CREATION_OF_CONTRACTS".getBytes(); + private static final byte[] ALLOW_CREATION_OF_CONTRACTS = "ALLOW_CREATION_OF_CONTRACTS" + .getBytes(); + @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { @@ -918,7 +922,7 @@ public long getAllowCreationOfContracts() { } public boolean supportVM() { - return getAllowCreationOfContracts() == 1L; + return getAllowCreationOfContracts() == 1L; } public void saveBlockFilledSlots(int[] blockFilledSlots) { @@ -1121,4 +1125,13 @@ public void addTotalTransactionCost(long fee) { long newValue = getTotalTransactionCost() + fee; saveTotalTransactionCost(newValue); } + + public void forked() { + put(FORK_CONTROLLER, new BytesCapsule(Boolean.toString(true).getBytes())); + } + + public boolean getForked() { + byte[] value = revokingDB.getUnchecked(FORK_CONTROLLER); + return value == null ? Boolean.FALSE : Boolean.valueOf(new String(value)); + } } diff --git a/src/main/java/org/tron/core/db/Manager.java b/src/main/java/org/tron/core/db/Manager.java index 50d0499d747..3d4429d9b65 100644 --- a/src/main/java/org/tron/core/db/Manager.java +++ b/src/main/java/org/tron/core/db/Manager.java @@ -16,7 +16,15 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; -import java.util.concurrent.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javafx.util.Pair; import javax.annotation.PostConstruct; @@ -33,6 +41,7 @@ import org.tron.common.runtime.vm.program.invoke.ProgramInvokeFactoryImpl; import org.tron.common.storage.DepositImpl; import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ForkController; import org.tron.common.utils.SessionOptional; import org.tron.common.utils.Sha256Hash; import org.tron.common.utils.StringUtil; @@ -172,6 +181,10 @@ public class Manager { private Cache transactionIdCache = CacheBuilder .newBuilder().maximumSize(100_000).recordStats().build(); + @Getter + @Autowired + private ForkController forkController; + public WitnessStore getWitnessStore() { return this.witnessStore; } @@ -364,6 +377,7 @@ public void init() { Args.getInstance().getOutputDirectory()); System.exit(1); } + forkController.init(this); revokingStore.enable(); // this.codeStore = CodeStore.create("code"); @@ -1100,11 +1114,13 @@ public synchronized BlockCapsule generateBlock( } // apply transaction try (ISession tmpSeesion = revokingStore.buildSession()) { - processTransaction(trx, null); - // trx.resetResult(); - tmpSeesion.merge(); - // push into block - blockCapsule.addTransaction(trx); + if (forkController.forkOrNot(trx)) { + processTransaction(trx, null); +// trx.resetResult(); + tmpSeesion.merge(); + // push into block + blockCapsule.addTransaction(trx); + } iterator.remove(); } catch (ContractExeException e) { logger.info("contract not processed during execute"); @@ -1301,6 +1317,12 @@ public void updateLatestSolidifiedBlock() { } getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(latestSolidifiedBlockNum); logger.info("update solid block, num = {}", latestSolidifiedBlockNum); + try { + BlockCapsule solidifiedBlock = getBlockByNum(latestSolidifiedBlockNum); + forkController.update(solidifiedBlock); + } catch (ItemNotFoundException | BadItemException e) { + logger.error("solidified block not found"); + } } public long getSyncBeginNumber() { @@ -1335,6 +1357,7 @@ private void processMaintenance(BlockCapsule block) { proposalController.processProposals(); witnessController.updateWitness(); this.dynamicPropertiesStore.updateNextMaintenanceTime(block.getTimeStamp()); + forkController.reset(); } /** diff --git a/src/main/java/org/tron/core/net/node/NodeDelegate.java b/src/main/java/org/tron/core/net/node/NodeDelegate.java index 2453c7dbe43..f485e13317c 100644 --- a/src/main/java/org/tron/core/net/node/NodeDelegate.java +++ b/src/main/java/org/tron/core/net/node/NodeDelegate.java @@ -49,4 +49,6 @@ Deque getBlockChainSummary(BlockId beginBLockId, Deque blockId BlockCapsule getGenesisBlock(); boolean canChainRevoke(long num); + + boolean forkOrNot(TransactionCapsule transactionCapsule); } diff --git a/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java b/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java index d88167bd973..c12c38df432 100755 --- a/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java +++ b/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java @@ -389,4 +389,9 @@ public BlockCapsule getGenesisBlock() { public boolean canChainRevoke(long num) { return num >= dbManager.getSyncBeginNumber(); } + + @Override + public boolean forkOrNot(TransactionCapsule transactionCapsule) { + return dbManager.getForkController().forkOrNot(transactionCapsule); + } } diff --git a/src/main/java/org/tron/core/net/node/NodeImpl.java b/src/main/java/org/tron/core/net/node/NodeImpl.java index 162609760f6..1c2eab5b107 100644 --- a/src/main/java/org/tron/core/net/node/NodeImpl.java +++ b/src/main/java/org/tron/core/net/node/NodeImpl.java @@ -855,7 +855,8 @@ private void onHandleTransactionMessage(PeerConnection peer, TransactionMessage peer.getNode().getHost()); return; } - if(del.handleTransaction(trxMsg.getTransactionCapsule())){ + if (del.forkOrNot(trxMsg.getTransactionCapsule()) + && del.handleTransaction(trxMsg.getTransactionCapsule())) { broadcast(trxMsg); } } catch (TraitorPeerException e) { diff --git a/src/main/protos/core/Tron.proto b/src/main/protos/core/Tron.proto index b33576f4954..d568183f911 100644 --- a/src/main/protos/core/Tron.proto +++ b/src/main/protos/core/Tron.proto @@ -315,6 +315,7 @@ message BlockHeader { int64 number = 7; int64 witness_id = 8; bytes witness_address = 9; + int32 version = 10; } raw raw_data = 1; bytes witness_signature = 2;