diff --git a/README.md b/README.md index 1dff63db4d4..27c8c209127 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ This guide walks the user through the TRON Quickstart (v2.0.0) image setup. # Deploy * [Build](./build.md) Please build java-tron after cloning the project * [Run](./run.md) Run java-tron - +* [Build & Run by shell script](./shell.md) # Deployment [Deployment Guide](https://tronprotocol.github.io/documentation-en/developers/deployment/) walks the user through how to deploy a FullNode and an SR node. diff --git a/actuator/src/main/java/org/tron/core/actuator/TransferActuator.java b/actuator/src/main/java/org/tron/core/actuator/TransferActuator.java index 3b9c2ecc3aa..12536a7f92f 100755 --- a/actuator/src/main/java/org/tron/core/actuator/TransferActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/TransferActuator.java @@ -10,6 +10,7 @@ import org.tron.common.utils.Commons; import org.tron.common.utils.DecodeUtil; import org.tron.core.capsule.AccountCapsule; +import org.tron.core.capsule.ContractCapsule; import org.tron.core.capsule.TransactionResultCapsule; import org.tron.core.exception.BalanceInsufficientException; import org.tron.core.exception.ContractExeException; @@ -137,6 +138,23 @@ public boolean validate() throws ContractValidateException { } + // after AllowTvmCompatibleEvm proposal, send trx to smartContract which version is one + // by actuator is not allowed. + if (dynamicStore.getAllowTvmCompatibleEvm() == 1 + && toAccount != null + && toAccount.getType() == AccountType.Contract) { + + ContractCapsule contractCapsule = chainBaseManager.getContractStore().get(toAddress); + if (contractCapsule == null) { // this can not happen + throw new ContractValidateException( + "Account type is Contract, but it is not exist in contract store."); + } else if (contractCapsule.getContractVersion() == 1) { + throw new ContractValidateException( + "Cannot transfer TRX to a smartContract which version is one. " + + "Instead please use TriggerSmartContract "); + } + } + if (balance < Math.addExact(amount, fee)) { throw new ContractValidateException( "Validate TransferContract error, balance is not sufficient."); diff --git a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java index f8738ccd3ca..299c9f1dc99 100644 --- a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java @@ -177,24 +177,14 @@ public void execute(Object object) throws ContractExeException { vm.play(program); result = program.getResult(); - if (isConstantCall) { - long callValue = TransactionCapsule.getCallValue(trx.getRawData().getContract(0)); - long callTokenValue = TransactionUtil - .getCallTokenValue(trx.getRawData().getContract(0)); - if (callValue > 0 || callTokenValue > 0) { - result.setRuntimeError("constant cannot set call value or call token value."); - result.rejectInternalTransactions(); - } - if (result.getException() != null) { - result.setRuntimeError(result.getException().getMessage()); - result.rejectInternalTransactions(); - } - context.setProgramResult(result); - return; - } - if (TrxType.TRX_CONTRACT_CREATION_TYPE == trxType && !result.isRevert()) { byte[] code = program.getResult().getHReturn(); + if (code.length != 0 && vmConfig.allowTvmLondon() && code[0] == (byte) 0xEF) { + if (null == result.getException()) { + result.setException(Program.Exception + .invalidCodeException()); + } + } long saveCodeEnergy = (long) getLength(code) * EnergyCost.getInstance().getCREATE_DATA(); long afterSpend = program.getEnergyLimitLeft().longValue() - saveCodeEnergy; if (afterSpend < 0) { @@ -211,6 +201,15 @@ public void execute(Object object) throws ContractExeException { } } + if (isConstantCall) { + if (result.getException() != null) { + result.setRuntimeError(result.getException().getMessage()); + result.rejectInternalTransactions(); + } + context.setProgramResult(result); + return; + } + if (result.getException() != null || result.isRevert()) { result.getDeleteAccounts().clear(); result.getLogInfoList().clear(); @@ -297,7 +296,12 @@ private void create() if (contract == null) { throw new ContractValidateException("Cannot get CreateSmartContract from transaction"); } - SmartContract newSmartContract = contract.getNewContract(); + SmartContract newSmartContract; + if (VMConfig.allowTvmCompatibleEvm()) { + newSmartContract = contract.getNewContract().toBuilder().setVersion(1).build(); + } else { + newSmartContract = contract.getNewContract().toBuilder().clearVersion().build(); + } if (!contract.getOwnerAddress().equals(newSmartContract.getOriginAddress())) { logger.info("OwnerAddress not equals OriginAddress"); throw new ContractValidateException("OwnerAddress is not equals OriginAddress"); @@ -346,19 +350,23 @@ private void create() long energyLimit; // according to version - if (StorageUtils.getEnergyLimitHardFork()) { - if (callValue < 0) { - throw new ContractValidateException("callValue must be >= 0"); - } - if (tokenValue < 0) { - throw new ContractValidateException("tokenValue must be >= 0"); - } - if (newSmartContract.getOriginEnergyLimit() <= 0) { - throw new ContractValidateException("The originEnergyLimit must be > 0"); - } - energyLimit = getAccountEnergyLimitWithFixRatio(creator, feeLimit, callValue); + if (isConstantCall) { + energyLimit = CommonParameter.getInstance().maxEnergyLimitForConstant; } else { - energyLimit = getAccountEnergyLimitWithFloatRatio(creator, feeLimit, callValue); + if (StorageUtils.getEnergyLimitHardFork()) { + if (callValue < 0) { + throw new ContractValidateException("callValue must be >= 0"); + } + if (tokenValue < 0) { + throw new ContractValidateException("tokenValue must be >= 0"); + } + if (newSmartContract.getOriginEnergyLimit() <= 0) { + throw new ContractValidateException("The originEnergyLimit must be > 0"); + } + energyLimit = getAccountEnergyLimitWithFixRatio(creator, feeLimit, callValue); + } else { + energyLimit = getAccountEnergyLimitWithFloatRatio(creator, feeLimit, callValue); + } } checkTokenValueAndId(tokenValue, tokenId); @@ -377,6 +385,9 @@ private void create() vmShouldEndInUs, energyLimit); this.vm = new VM(); this.program = new Program(ops, programInvoke, rootInternalTransaction, vmConfig); + if (VMConfig.allowTvmCompatibleEvm()) { + this.program.setContractVersion(1); + } byte[] txId = TransactionUtil.getTransactionId(trx).getBytes(); this.program.setRootTransactionId(txId); if (enableEventListener && isCheckTransaction()) { @@ -459,7 +470,6 @@ private void call() byte[] code = repository.getCode(contractAddress); if (isNotEmpty(code)) { - long feeLimit = trx.getRawData().getFeeLimit(); if (feeLimit < 0 || feeLimit > repository.getDynamicPropertiesStore().getMaxFeeLimit()) { logger.info("invalid feeLimit {}", feeLimit); @@ -469,7 +479,7 @@ private void call() AccountCapsule caller = repository.getAccount(callerAddress); long energyLimit; if (isConstantCall) { - energyLimit = VMConstant.ENERGY_LIMIT_IN_CONSTANT_TX; + energyLimit = CommonParameter.getInstance().maxEnergyLimitForConstant; } else { AccountCapsule creator = repository .getAccount(deployedContract.getInstance().getOriginAddress().toByteArray()); @@ -492,6 +502,9 @@ private void call() this.vm = new VM(); rootInternalTransaction = new InternalTransaction(trx, trxType); this.program = new Program(code, programInvoke, rootInternalTransaction, vmConfig); + if (VMConfig.allowTvmCompatibleEvm()) { + this.program.setContractVersion(deployedContract.getContractVersion()); + } byte[] txId = TransactionUtil.getTransactionId(trx).getBytes(); this.program.setRootTransactionId(txId); diff --git a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java index a8e59966e81..8ce040702c5 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -383,9 +383,17 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_1_2)) { throw new ContractValidateException("Bad chain parameter id [MAX_FEE_LIMIT]"); } - if (value < 0 || value > 10_000_000_000L) { + if (value < 0) { throw new ContractValidateException( - "Bad MAX_FEE_LIMIT parameter value, valid range is [0,10_000_000_000L]"); + "Bad MAX_FEE_LIMIT parameter value, value must not be negative"); + } else if (value > 10_000_000_000L) { + if (dynamicPropertiesStore.getAllowTvmLondon() == 0) { + throw new ContractValidateException( + "Bad MAX_FEE_LIMIT parameter value, valid range is [0,10_000_000_000L]"); + } + if (value > LONG_VALUE) { + throw new ContractValidateException(LONG_VALUE_ERROR); + } } break; } @@ -469,7 +477,6 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, } break; } - case FREE_NET_LIMIT: { if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_3)) { throw new ContractValidateException("Bad chain parameter id [FREE_NET_LIMIT]"); @@ -502,6 +509,28 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, } break; } + case ALLOW_TVM_LONDON: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_4)) { + throw new ContractValidateException( + "Bad chain parameter id [ALLOW_TVM_LONDON]"); + } + if (value != 1) { + throw new ContractValidateException( + "This value[ALLOW_TVM_LONDON] is only allowed to be 1"); + } + break; + } + case ALLOW_TVM_COMPATIBLE_EVM: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_4)) { + throw new ContractValidateException( + "Bad chain parameter id [ALLOW_TVM_COMPATIBLE_EVM]"); + } + if (value != 1) { + throw new ContractValidateException( + "This value[ALLOW_TVM_COMPATIBLE_EVM] is only allowed to be 1"); + } + break; + } default: break; } @@ -552,7 +581,7 @@ public enum ProposalType { // current value, value range ALLOW_MARKET_TRANSACTION(44), // {0, 1} MARKET_SELL_FEE(45), // 0 [0,10_000_000_000] MARKET_CANCEL_FEE(46), // 0 [0,10_000_000_000] - MAX_FEE_LIMIT(47), // [0, 10_000_000_000] + MAX_FEE_LIMIT(47), // [0, 100_000_000_000] TRX ALLOW_TRANSACTION_FEE_POOL(48), // 0, 1 ALLOW_BLACKHOLE_OPTIMIZATION(49),// 0,1 ALLOW_NEW_RESOURCE_MODEL(51),// 0,1 @@ -560,8 +589,10 @@ public enum ProposalType { // current value, value range ALLOW_ACCOUNT_ASSET_OPTIMIZATION(53), // 1 // ALLOW_NEW_REWARD_ALGORITHM(58), // 0, 1 ALLOW_TVM_VOTE(59), // 0, 1 + ALLOW_TVM_COMPATIBLE_EVM(60), // 0, 1 FREE_NET_LIMIT(61), // 5000, [0, 100_000] - TOTAL_NET_LIMIT(62); // 43_200_000_000L, [0, 1000_000_000_000L] + TOTAL_NET_LIMIT(62), // 43_200_000_000L, [0, 1000_000_000_000L] + ALLOW_TVM_LONDON(63); // 0, 1 private long code; diff --git a/actuator/src/main/java/org/tron/core/vm/OpCode.java b/actuator/src/main/java/org/tron/core/vm/OpCode.java index 5a0a41ac95c..31dc72fab28 100644 --- a/actuator/src/main/java/org/tron/core/vm/OpCode.java +++ b/actuator/src/main/java/org/tron/core/vm/OpCode.java @@ -244,6 +244,10 @@ public enum OpCode { * (0x47) Get current account balance */ SELFBALANCE(0x47, 0, 1, Tier.LowTier), + /** + * (0x48) Get block's basefee + */ + BASEFEE(0x48, 0, 1, Tier.BaseTier), /* Memory, Storage and Flow Operations */ diff --git a/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java b/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java index 01f5a414ab3..7043bf6663d 100644 --- a/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java +++ b/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java @@ -24,8 +24,10 @@ import static org.tron.common.utils.BIUtil.isZero; import static org.tron.common.utils.ByteUtil.*; import static org.tron.core.db.TransactionTrace.convertToTronAddress; +import static java.util.Arrays.copyOfRange; import java.math.BigInteger; +import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -45,6 +47,8 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.Pair; +import org.tron.common.crypto.Blake2bfMessageDigest; +import org.tron.common.crypto.Hash; import org.tron.common.crypto.SignUtils; import org.tron.common.crypto.SignatureInterface; import org.tron.common.crypto.zksnark.BN128; @@ -107,6 +111,9 @@ public class PrecompiledContracts { private static final ReceivedVoteCount receivedVoteCount = new ReceivedVoteCount(); private static final TotalVoteCount totalVoteCount = new TotalVoteCount(); + private static final EthRipemd160 ethRipemd160 = new EthRipemd160(); + private static final Blake2F blake2F = new Blake2F(); + private static final DataWord ecRecoverAddr = new DataWord( "0000000000000000000000000000000000000000000000000000000000000001"); private static final DataWord sha256Addr = new DataWord( @@ -147,6 +154,11 @@ public class PrecompiledContracts { "0000000000000000000000000000000000000000000000000000000001000009"); private static final DataWord totalVoteCountAddr = new DataWord( "000000000000000000000000000000000000000000000000000000000100000a"); + private static final DataWord ethRipemd160Addr = new DataWord( + "0000000000000000000000000000000000000000000000000000000000020003"); + private static final DataWord blake2FAddr = new DataWord( + "0000000000000000000000000000000000000000000000000000000000020009"); + public static PrecompiledContract getContractForAddress(DataWord address) { @@ -214,6 +226,12 @@ public static PrecompiledContract getContractForAddress(DataWord address) { if (VMConfig.allowTvmVote() && address.equals(totalVoteCountAddr)) { return totalVoteCount; } + if (VMConfig.allowTvmCompatibleEvm() && address.equals(ethRipemd160Addr)) { + return ethRipemd160; + } + if (VMConfig.allowTvmCompatibleEvm() && address.equals(blake2FAddr)) { + return blake2F; + } return null; } @@ -1721,4 +1739,66 @@ public Pair execute(byte[] data) { } } + public static class EthRipemd160 extends PrecompiledContract { + + + @Override + public long getEnergyForData(byte[] data) { + + if (data == null) { + return 600; + } + return 600L + (data.length + 31) / 32 * 120; + } + + @Override + public Pair execute(byte[] data) { + + byte[] result; + if (data == null) { + result = Hash.ripemd160(EMPTY_BYTE_ARRAY); + } else { + result = Hash.ripemd160(data); + } + return Pair.of(true, new DataWord(result).getData()); + } + } + + public static class Blake2F extends PrecompiledContract { + + + @Override + public long getEnergyForData(byte[] data) { + + if (data.length != 213 || (data[212] & 0xFE) != 0) { + return 0; + } + final byte[] roundsBytes = copyOfRange(data, 0, 4); + final BigInteger rounds = new BigInteger(1, roundsBytes); + return rounds.longValue(); + } + + @Override + public Pair execute(byte[] data) { + + if (data.length != 213) { + logger.info("Incorrect input length. Expected {} and got {}", 213, data.length); + return Pair.of(false, DataWord.ZERO().getData()); + } + if ((data[212] & 0xFE) != 0) { + logger.info("Incorrect finalization flag, expected 0 or 1 and got {}", data[212]); + return Pair.of(false, DataWord.ZERO().getData()); + } + final MessageDigest digest = new Blake2bfMessageDigest(); + byte[] result; + try { + digest.update(data); + result = digest.digest(); + } catch (Exception e) { + return Pair.of(true, EMPTY_BYTE_ARRAY); + } + return Pair.of(true, result); + } + } + } diff --git a/actuator/src/main/java/org/tron/core/vm/VM.java b/actuator/src/main/java/org/tron/core/vm/VM.java index 4df2b97d3d1..b3b7e1c40da 100644 --- a/actuator/src/main/java/org/tron/core/vm/VM.java +++ b/actuator/src/main/java/org/tron/core/vm/VM.java @@ -23,6 +23,7 @@ import static org.tron.core.vm.OpCode.UNFREEZE; import static org.tron.core.vm.OpCode.VOTEWITNESS; import static org.tron.core.vm.OpCode.WITHDRAWREWARD; +import static org.tron.core.vm.OpCode.BASEFEE; import java.math.BigInteger; import java.util.ArrayList; @@ -119,6 +120,7 @@ public void step(Program program) { && (op == FREEZE || op == UNFREEZE || op == FREEZEEXPIRETIME)) || (!VMConfig.allowTvmVote() && (op == VOTEWITNESS || op == WITHDRAWREWARD)) + || (!VMConfig.allowTvmLondon() && (op == BASEFEE)) ) { throw Program.Exception.invalidOpCode(program.getCurrentOp()); } @@ -829,7 +831,10 @@ && isDeadAccount(program, callAddressWord) break; case GASPRICE: { DataWord energyPrice = new DataWord(0); - + if (VMConfig.allowTvmCompatibleEvm() && program.getContractVersion() == 1) { + energyPrice = new DataWord(program.getContractState() + .getDynamicPropertiesStore().getEnergyFee()); + } program.stackPush(energyPrice); program.step(); } @@ -867,18 +872,19 @@ && isDeadAccount(program, callAddressWord) program.step(); } break; - case DIFFICULTY: { - DataWord difficulty = program.getDifficulty(); + case DIFFICULTY: + case GASLIMIT: { + DataWord result = new DataWord(0); - program.stackPush(difficulty); + program.stackPush(result); program.step(); } break; - case GASLIMIT: { - // todo: this energylimit is the block's energy limit - DataWord energyLimit = new DataWord(0); + case BASEFEE: { + DataWord energyFee = + new DataWord(program.getContractState().getDynamicPropertiesStore().getEnergyFee()); - program.stackPush(energyLimit); + program.stackPush(energyFee); program.step(); } break; diff --git a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java index dd0be2ad5d0..00f2bacedfc 100644 --- a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java +++ b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java @@ -28,6 +28,8 @@ public static void load(StoreFactory storeFactory) { VMConfig.initAllowTvmIstanbul(ds.getAllowTvmIstanbul()); VMConfig.initAllowTvmFreeze(ds.getAllowTvmFreeze()); VMConfig.initAllowTvmVote(ds.getAllowTvmVote()); + VMConfig.initAllowTvmLondon(ds.getAllowTvmLondon()); + VMConfig.initAllowTvmCompatibleEvm(ds.getAllowTvmCompatibleEvm()); } } } diff --git a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java index b34986e6ba3..9d4b9ab27c9 100644 --- a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java +++ b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java @@ -51,6 +51,10 @@ public class VMConfig { private static boolean ALLOW_TVM_VOTE = false; + private static boolean ALLOW_TVM_LONDON = false; + + private static boolean ALLOW_TVM_COMPATIBLE_EVM = false; + private VMConfig() { } @@ -102,6 +106,14 @@ public static void initAllowTvmVote(long allow) { ALLOW_TVM_VOTE = allow == 1; } + public static void initAllowTvmLondon(long allow) { + ALLOW_TVM_LONDON = allow == 1; + } + + public static void initAllowTvmCompatibleEvm(long allow) { + ALLOW_TVM_COMPATIBLE_EVM = allow == 1; + } + public static boolean getEnergyLimitHardFork() { return ENERGY_LIMIT_HARD_FORK; } @@ -126,7 +138,9 @@ public static boolean allowShieldedTRC20Transaction() { return ALLOW_SHIELDED_TRC20_TRANSACTION; } - public static boolean allowTvmIstanbul() {return ALLOW_TVM_ISTANBUL; } + public static boolean allowTvmIstanbul() { + return ALLOW_TVM_ISTANBUL; + } public static boolean allowTvmFreeze() { return ALLOW_TVM_FREEZE; @@ -136,6 +150,14 @@ public static boolean allowTvmVote() { return ALLOW_TVM_VOTE; } + public static boolean allowTvmLondon() { + return ALLOW_TVM_LONDON; + } + + public static boolean allowTvmCompatibleEvm() { + return ALLOW_TVM_COMPATIBLE_EVM; + } + private static class SystemPropertiesInstance { private static final VMConfig INSTANCE = new VMConfig(); diff --git a/actuator/src/main/java/org/tron/core/vm/program/Program.java b/actuator/src/main/java/org/tron/core/vm/program/Program.java index fd89c55bcb7..fc22f708e5f 100644 --- a/actuator/src/main/java/org/tron/core/vm/program/Program.java +++ b/actuator/src/main/java/org/tron/core/vm/program/Program.java @@ -134,6 +134,8 @@ public class Program { private byte previouslyExecutedOp; private boolean stopped; private ProgramPrecompile programPrecompile; + private int contractVersion; + public Program(byte[] ops, ProgramInvoke programInvoke) { this(ops, programInvoke, null); @@ -158,6 +160,8 @@ public Program(byte[] ops, ProgramInvoke programInvoke, InternalTransaction inte this.nonce = internalTransaction.getNonce(); } + + static String formatBinData(byte[] binData, int startPC) { StringBuilder ret = new StringBuilder(); for (int i = 0; i < binData.length; i += 16) { @@ -304,6 +308,14 @@ public void setRootTransactionId(byte[] rootTransactionId) { this.rootTransactionId = rootTransactionId.clone(); } + public void setContractVersion(int version) { + this.contractVersion = version; + } + + public int getContractVersion() { + return this.contractVersion; + } + public long getNonce() { return nonce; } @@ -715,6 +727,9 @@ private void createContractImpl(DataWord value, byte[] programCode, byte[] newAd if (!contractAlreadyExists) { Builder builder = SmartContract.newBuilder(); + if (VMConfig.allowTvmCompatibleEvm()) { + builder.setVersion(getContractVersion()); + } builder.setContractAddress(ByteString.copyFrom(newAddress)) .setConsumeUserResourcePercent(100) .setOriginAddress(ByteString.copyFrom(senderAddress)); @@ -727,8 +742,12 @@ private void createContractImpl(DataWord value, byte[] programCode, byte[] newAd } else { deposit.createAccount(newAddress, "CreatedByContract", Protocol.AccountType.Contract); - SmartContract newSmartContract = SmartContract.newBuilder() - .setContractAddress(ByteString.copyFrom(newAddress)).setConsumeUserResourcePercent(100) + Builder builder = SmartContract.newBuilder(); + if (VMConfig.allowTvmCompatibleEvm()) { + builder.setVersion(getContractVersion()); + } + SmartContract newSmartContract = builder.setContractAddress(ByteString.copyFrom(newAddress)) + .setConsumeUserResourcePercent(100) .setOriginAddress(ByteString.copyFrom(senderAddress)).build(); deposit.createContract(newAddress, new ContractCapsule(newSmartContract)); // In case of hashing collisions, check for any balance before createAccount() @@ -776,6 +795,9 @@ this, new DataWord(newAddress), getContractAddress(), value, new DataWord(0), VM vm = new VM(config); Program program = new Program(programCode, programInvoke, internalTx, config); program.setRootTransactionId(this.rootTransactionId); + if (VMConfig.allowTvmCompatibleEvm()) { + program.setContractVersion(getContractVersion()); + } vm.play(program); createResult = program.getResult(); getTrace().merge(program.getTrace()); @@ -787,6 +809,11 @@ this, new DataWord(newAddress), getContractAddress(), value, new DataWord(0), // 4. CREATE THE CONTRACT OUT OF RETURN byte[] code = createResult.getHReturn(); + if (code.length != 0 && config.allowTvmLondon() && code[0] == (byte) 0xEF) { + createResult.setException(Program.Exception + .invalidCodeException()); + } + long saveCodeEnergy = (long) getLength(code) * EnergyCost.getInstance().getCREATE_DATA(); long afterSpend = @@ -993,6 +1020,10 @@ this, new DataWord(contextAddress), VM vm = new VM(config); Program program = new Program(programCode, programInvoke, internalTx, config); program.setRootTransactionId(this.rootTransactionId); + if (VMConfig.allowTvmCompatibleEvm()) { + program.setContractVersion( + invoke.getDeposit().getContract(codeAddress).getContractVersion()); + } vm.play(program); callResult = program.getResult(); @@ -1214,8 +1245,11 @@ public DataWord getCallerAddress() { } public DataWord getChainId() { - return new DataWord(Hex.toHexString(getContractState() - .getBlockByNum(0).getBlockId().getBytes())); + byte[] chainId = getContractState().getBlockByNum(0).getBlockId().getBytes(); + if (VMConfig.allowTvmCompatibleEvm()) { + chainId = Arrays.copyOfRange(chainId, chainId.length - 4, chainId.length); + } + return new DataWord(chainId); } public DataWord getDropPrice() { return new DataWord(1); @@ -1446,6 +1480,10 @@ public ProgramTrace getTrace() { public void createContract2(DataWord value, DataWord memStart, DataWord memSize, DataWord salt) { byte[] senderAddress; + if (VMConfig.allowTvmCompatibleEvm() && getCallDeep() == MAX_DEPTH) { + stackPushZero(); + return; + } if(VMConfig.allowTvmIstanbul()) { senderAddress = TransactionTrace .convertToTronAddress(this.getContractAddress().getLast20Bytes()); @@ -1650,10 +1688,20 @@ public void checkTokenIdInTokenBalance(DataWord tokenIdDataWord) { } public DataWord getCallEnergy(OpCode op, DataWord requestedEnergy, DataWord availableEnergy) { + if (VMConfig.allowTvmCompatibleEvm() && getContractVersion() == 1) { + DataWord availableEnergyReduce = availableEnergy.clone(); + availableEnergyReduce.div(new DataWord(64)); + availableEnergy.sub(availableEnergyReduce); + } return requestedEnergy.compareTo(availableEnergy) > 0 ? availableEnergy : requestedEnergy; } public DataWord getCreateEnergy(DataWord availableEnergy) { + if (VMConfig.allowTvmCompatibleEvm() && getContractVersion() == 1) { + DataWord availableEnergyReduce = availableEnergy.clone(); + availableEnergyReduce.div(new DataWord(64)); + availableEnergy.sub(availableEnergyReduce); + } return availableEnergy; } @@ -2029,6 +2077,14 @@ public IllegalOperationException(String message, Object... args) { } } + @SuppressWarnings("serial") + public static class InvalidCodeException extends BytecodeExecutionException { + + public InvalidCodeException(String message) { + super(message); + } + } + @SuppressWarnings("serial") public static class BadJumpDestinationException extends BytecodeExecutionException { @@ -2135,6 +2191,10 @@ public static IllegalOperationException invalidOpCode(byte... opCode) { Hex.toHexString(opCode, 0, 1)); } + public static InvalidCodeException invalidCodeException() { + return new InvalidCodeException("invalid code: must not begin with 0xef"); + } + public static BadJumpDestinationException badJumpDestination(int pc) { return new BadJumpDestinationException("Operation with pc isn't 'JUMPDEST': PC[%d];", pc); } diff --git a/actuator/src/main/java/org/tron/core/vm/program/Storage.java b/actuator/src/main/java/org/tron/core/vm/program/Storage.java index 694917491fc..61eef46f4bd 100644 --- a/actuator/src/main/java/org/tron/core/vm/program/Storage.java +++ b/actuator/src/main/java/org/tron/core/vm/program/Storage.java @@ -5,11 +5,13 @@ import java.util.HashMap; import java.util.Map; import lombok.Getter; +import lombok.Setter; import org.tron.common.crypto.Hash; import org.tron.common.runtime.vm.DataWord; import org.tron.common.utils.ByteUtil; import org.tron.core.capsule.StorageRowCapsule; import org.tron.core.store.StorageRowStore; +import org.tron.core.vm.config.VMConfig; public class Storage { @@ -22,6 +24,8 @@ public class Storage { private StorageRowStore store; @Getter private byte[] address; + @Setter + private int contractVersion; public Storage(byte[] address, StorageRowStore store) { addrHash = addrHash(address); @@ -33,13 +37,17 @@ public Storage(Storage storage) { this.addrHash = storage.addrHash.clone(); this.address = storage.getAddress().clone(); this.store = storage.store; + this.contractVersion = storage.contractVersion; storage.getRowCache().forEach((DataWord rowKey, StorageRowCapsule row) -> { StorageRowCapsule newRow = new StorageRowCapsule(row); this.rowCache.put(rowKey.clone(), newRow); }); } - private static byte[] compose(byte[] key, byte[] addrHash) { + private byte[] compose(byte[] key, byte[] addrHash) { + if (VMConfig.allowTvmCompatibleEvm() && contractVersion == 1) { + return Hash.sha3(ByteUtil.merge(addrHash, key)); + } byte[] result = new byte[key.length]; arraycopy(addrHash, 0, result, 0, PREFIX_BYTES); arraycopy(key, PREFIX_BYTES, result, PREFIX_BYTES, PREFIX_BYTES); diff --git a/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java b/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java index 75f1ee2c382..e3712594ff5 100644 --- a/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java +++ b/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java @@ -524,8 +524,11 @@ public Storage getStorage(byte[] address) { storage = new Storage(address, getStorageRowStore()); } ContractCapsule contract = getContract(address); - if (contract != null && !ByteUtil.isNullOrZeroArray(contract.getTrxHash())) { - storage.generateAddrHash(contract.getTrxHash()); + if (contract != null) { + storage.setContractVersion(contract.getContractVersion()); + if (!ByteUtil.isNullOrZeroArray(contract.getTrxHash())) { + storage.generateAddrHash(contract.getTrxHash()); + } } return storage; } diff --git a/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java b/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java index acf627fde2e..f62e65a621b 100644 --- a/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java +++ b/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java @@ -56,6 +56,15 @@ public static Options getOptionsByDbName(String dbName) { if (hasProperty(dbName)) { return getProperty(dbName).getDbOptions(); } - return createDefaultDbOptions(); + Options options = createDefaultDbOptions(); + switch (dbName) { + case "block": + case "transactionHistoryStore": + case "transactionRetStore": + case "trans": options.writeBufferSize(256 * 1024 * 1024); + break; + default: + } + return options; } } diff --git a/chainbase/src/main/java/org/tron/core/capsule/AccountCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/AccountCapsule.java index 74ac8287d37..1888724bb5c 100644 --- a/chainbase/src/main/java/org/tron/core/capsule/AccountCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/AccountCapsule.java @@ -19,10 +19,8 @@ import com.google.common.collect.Maps; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; - import java.util.List; import java.util.Map; - import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -1110,17 +1108,22 @@ public Permission getPermissionById(int id) { public void updatePermissions(Permission owner, Permission witness, List actives) { Builder builder = this.account.toBuilder(); + owner = owner.toBuilder().setId(0).build(); builder.setOwnerPermission(owner); - if (builder.getIsWitness()) { + if (witness != null && builder.getIsWitness()) { witness = witness.toBuilder().setId(1).build(); builder.setWitnessPermission(witness); } + builder.clearActivePermission(); - for (int i = 0; i < actives.size(); i++) { - Permission permission = actives.get(i).toBuilder().setId(i + 2).build(); - builder.addActivePermission(permission); + if (actives != null) { + for (int i = 0; i < actives.size(); i++) { + Permission permission = actives.get(i).toBuilder().setId(i + 2).build(); + builder.addActivePermission(permission); + } } + this.account = builder.build(); } @@ -1151,4 +1154,4 @@ public void importAsset() { } } -} \ No newline at end of file +} diff --git a/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java index 54bdbe9e5b0..df498c43407 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java @@ -260,6 +260,10 @@ public ByteString getWitnessAddress() { return this.block.getBlockHeader().getRawData().getWitnessAddress(); } + public boolean isMerkleRootEmpty() { + return this.block.getBlockHeader().getRawData().getTxTrieRoot().toByteArray().length == 0; + } + @Override public byte[] getData() { return this.block.toByteArray(); diff --git a/chainbase/src/main/java/org/tron/core/capsule/ContractCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/ContractCapsule.java index 669e8c44dfb..2204b6446a3 100644 --- a/chainbase/src/main/java/org/tron/core/capsule/ContractCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/ContractCapsule.java @@ -129,4 +129,8 @@ public void clearABI() { public byte[] getTrxHash() { return this.smartContract.getTrxHash().toByteArray(); } + + public int getContractVersion() { + return this.smartContract.getVersion(); + } } diff --git a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java index a97e70e63a7..cd35bf4a253 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java @@ -535,8 +535,6 @@ private Sha256Hash getRawHash() { public void sign(byte[] privateKey) { SignInterface cryptoEngine = SignUtils .fromPrivate(privateKey, CommonParameter.getInstance().isECKeyCryptoEngine()); - // String signature = cryptoEngine.signHash(getRawHash().getBytes()); - // ByteString sig = ByteString.copyFrom(signature.getBytes()); ByteString sig = ByteString.copyFrom(cryptoEngine.Base64toBytes(cryptoEngine .signHash(getRawHash().getBytes()))); this.transaction = this.transaction.toBuilder().addSignature(sig).build(); @@ -574,7 +572,6 @@ public void addSign(byte[] privateKey, AccountStore accountStore) ByteArray.toHexString(privateKey) + "'s address is " + encode58Check(address) + " but it is not contained of permission."); } - // String signature = cryptoEngine.signHash(getRawHash().getBytes()); ByteString sig = ByteString.copyFrom(cryptoEngine.Base64toBytes(cryptoEngine .signHash(getRawHash().getBytes()))); this.transaction = this.transaction.toBuilder().addSignature(sig).build(); diff --git a/chainbase/src/main/java/org/tron/core/capsule/utils/TransactionUtil.java b/chainbase/src/main/java/org/tron/core/capsule/utils/TransactionUtil.java index 52f1889b83e..a2c3facd565 100644 --- a/chainbase/src/main/java/org/tron/core/capsule/utils/TransactionUtil.java +++ b/chainbase/src/main/java/org/tron/core/capsule/utils/TransactionUtil.java @@ -122,42 +122,44 @@ public static TransactionInfoCapsule buildTransactionInfoInstance(TransactionCap builder.setReceipt(traceReceipt.getReceipt()); - if (CommonParameter.getInstance().isSaveInternalTx() && null != programResult - .getInternalTransactions()) { - for (InternalTransaction internalTransaction : programResult - .getInternalTransactions()) { - Protocol.InternalTransaction.Builder internalTrxBuilder = Protocol.InternalTransaction - .newBuilder(); - // set hash - internalTrxBuilder.setHash(ByteString.copyFrom(internalTransaction.getHash())); - // set caller - internalTrxBuilder.setCallerAddress(ByteString.copyFrom(internalTransaction.getSender())); - // set TransferTo - internalTrxBuilder - .setTransferToAddress(ByteString.copyFrom(internalTransaction.getTransferToAddress())); - //TODO: "for loop" below in future for multiple token case, we only have one for now. - Protocol.InternalTransaction.CallValueInfo.Builder callValueInfoBuilder = - Protocol.InternalTransaction.CallValueInfo.newBuilder(); - // trx will not be set token name - callValueInfoBuilder.setCallValue(internalTransaction.getValue()); - // Just one transferBuilder for now. - internalTrxBuilder.addCallValueInfo(callValueInfoBuilder); - internalTransaction.getTokenInfo().forEach((tokenId, amount) -> { - internalTrxBuilder.addCallValueInfo( - Protocol.InternalTransaction.CallValueInfo.newBuilder().setTokenId(tokenId) - .setCallValue(amount)); - }); - // Token for loop end here - internalTrxBuilder.setNote(ByteString.copyFrom(internalTransaction.getNote().getBytes())); - internalTrxBuilder.setRejected(internalTransaction.isRejected()); - internalTrxBuilder.setExtra(internalTransaction.getExtra()); - builder.addInternalTransactions(internalTrxBuilder); - } + if (CommonParameter.getInstance().isSaveInternalTx()) { + programResult.getInternalTransactions().forEach(it -> + builder.addInternalTransactions(buildInternalTransaction(it))); } return new TransactionInfoCapsule(builder.build()); } + public static Protocol.InternalTransaction buildInternalTransaction(InternalTransaction it) { + Protocol.InternalTransaction.Builder itBuilder = Protocol.InternalTransaction + .newBuilder(); + // set hash + itBuilder.setHash(ByteString.copyFrom(it.getHash())); + // set caller + itBuilder.setCallerAddress(ByteString.copyFrom(it.getSender())); + // set TransferTo + itBuilder.setTransferToAddress(ByteString.copyFrom(it.getTransferToAddress())); + //TODO: "for loop" below in future for multiple token case, we only have one for now. + Protocol.InternalTransaction.CallValueInfo.Builder callValueInfoBuilder = + Protocol.InternalTransaction.CallValueInfo.newBuilder(); + // trx will not be set token name + callValueInfoBuilder.setCallValue(it.getValue()); + // Just one transferBuilder for now. + itBuilder.addCallValueInfo(callValueInfoBuilder); + it.getTokenInfo().forEach((tokenId, amount) -> + itBuilder.addCallValueInfo( + Protocol.InternalTransaction.CallValueInfo.newBuilder() + .setTokenId(tokenId) + .setCallValue(amount) + ) + ); + // Token for loop end here + itBuilder.setNote(ByteString.copyFrom(it.getNote().getBytes())); + itBuilder.setRejected(it.isRejected()); + itBuilder.setExtra(it.getExtra()); + return itBuilder.build(); + } + public static boolean isNumber(byte[] id) { if (ArrayUtils.isEmpty(id)) { return false; diff --git a/chainbase/src/main/java/org/tron/core/db/TransactionStore.java b/chainbase/src/main/java/org/tron/core/db/TransactionStore.java index 38d0d9c3a84..342550ecb4a 100644 --- a/chainbase/src/main/java/org/tron/core/db/TransactionStore.java +++ b/chainbase/src/main/java/org/tron/core/db/TransactionStore.java @@ -81,16 +81,24 @@ public TransactionCapsule get(byte[] key) throws BadItemException { if (ArrayUtils.isEmpty(value)) { return null; } + TransactionCapsule transactionCapsule = null; + long blockHigh = -1; + if (value.length == 8) { - long blockHigh = ByteArray.toLong(value); + blockHigh = ByteArray.toLong(value); transactionCapsule = getTransactionFromBlockStore(key, blockHigh); if (transactionCapsule == null) { transactionCapsule = getTransactionFromKhaosDatabase(key, blockHigh); } } - return transactionCapsule == null ? new TransactionCapsule(value) : transactionCapsule; + if (transactionCapsule == null) { + return new TransactionCapsule(value); + } else { + transactionCapsule.setBlockNum(blockHigh); + return transactionCapsule; + } } @Override diff --git a/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java b/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java index c39d0782720..445972417df 100644 --- a/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java +++ b/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java @@ -27,6 +27,8 @@ public interface IRevokingDB extends Iterable> { void setCursor(Chainbase.Cursor cursor, long offset); + Chainbase.Cursor getCursor(); + // for blockstore Set getlatestValues(long limit); diff --git a/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java b/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java index 496a0fd09ac..ba6c77d43a2 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java @@ -15,6 +15,8 @@ public abstract class AbstractSnapshot implements Snapshot { protected WeakReference next; + protected boolean isOptimized; + @Override public Snapshot advance() { return new SnapshotImpl(this); @@ -34,4 +36,9 @@ public void setNext(Snapshot next) { public String getDbName() { return db.getDbName(); } + + @Override + public boolean isOptimized(){ + return isOptimized; + } } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java b/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java index c625a0f18a5..ee77c6cbc1b 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java @@ -56,6 +56,15 @@ public void setCursor(Cursor cursor, long offset) { this.offset.set(offset); } + @Override + public Cursor getCursor() { + if (cursor.get() == null) { + return Cursor.HEAD; + } else { + return cursor.get(); + } + } + private Snapshot head() { if (cursor.get() == null) { return head; diff --git a/chainbase/src/main/java/org/tron/core/db2/core/RevokingDBWithCachingOldValue.java b/chainbase/src/main/java/org/tron/core/db2/core/RevokingDBWithCachingOldValue.java index d8242f75e57..89dd75597af 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/RevokingDBWithCachingOldValue.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/RevokingDBWithCachingOldValue.java @@ -16,6 +16,7 @@ import org.tron.core.db.AbstractRevokingStore; import org.tron.core.db.RevokingStore; import org.tron.core.db2.common.IRevokingDB; +import org.tron.core.db2.core.Chainbase.Cursor; import org.tron.core.exception.ItemNotFoundException; @Slf4j @@ -116,7 +117,15 @@ public void setCursor(Chainbase.Cursor cursor) { @Override public void setCursor(Chainbase.Cursor cursor, long offset) { + } + /** + * This should be never called + */ + @Override + public Chainbase.Cursor getCursor() { + logger.error("RevokingDBWithCachingOldValue getCursor is called, this should not be happened"); + return Cursor.HEAD; } /** diff --git a/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java b/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java index e1ca149b207..db59713f34d 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java @@ -46,4 +46,6 @@ static boolean isImpl(Snapshot snapshot) { void updateSolidity(); String getDbName(); + + boolean isOptimized(); } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java index fb3d028a6be..d71c97ccf73 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java @@ -7,7 +7,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Set; import lombok.Getter; @@ -23,13 +22,22 @@ public class SnapshotImpl extends AbstractSnapshot { protected Snapshot root; SnapshotImpl(Snapshot snapshot) { + root = snapshot.getRoot(); synchronized (this) { - db = new HashDB(SnapshotImpl.class.getSimpleName()); + db = new HashDB(SnapshotImpl.class.getSimpleName() + ":" + root.getDbName()); } - - root = snapshot.getRoot(); previous = snapshot; snapshot.setNext(this); + // inherit + isOptimized = snapshot.isOptimized(); + // merge for DynamicPropertiesStore,about 100 keys + if (isOptimized) { + if (root == previous ){ + Streams.stream(root.iterator()).forEach( e -> put(e.getKey(),e.getValue())); + }else { + merge(previous); + } + } } @Override @@ -40,6 +48,10 @@ public byte[] get(byte[] key) { private byte[] get(Snapshot head, byte[] key) { Snapshot snapshot = head; Value value; + if (isOptimized) { + value = db.get(Key.of(key)); + return value == null ? null: value.getBytes(); + } while (Snapshot.isImpl(snapshot)) { if ((value = ((SnapshotImpl) snapshot).db.get(Key.of(key))) != null) { return value.getBytes(); diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java index 0be14f0a482..b69d55098c8 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java @@ -20,6 +20,7 @@ public class SnapshotRoot extends AbstractSnapshot { public SnapshotRoot(DB db) { this.db = db; solidity = this; + isOptimized = "properties".equalsIgnoreCase(db.getDbName()); } @Override diff --git a/chainbase/src/main/java/org/tron/core/store/ContractStore.java b/chainbase/src/main/java/org/tron/core/store/ContractStore.java index bdb35ff7aca..169d2b9c67e 100644 --- a/chainbase/src/main/java/org/tron/core/store/ContractStore.java +++ b/chainbase/src/main/java/org/tron/core/store/ContractStore.java @@ -17,9 +17,6 @@ @Component public class ContractStore extends TronStoreWithRevoking { - @Autowired - private AbiStore abiStore; - @Autowired private ContractStore(@Value("contract") String dbName) { super(dbName); diff --git a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java index c67e2938987..907d44a85aa 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -64,6 +64,8 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] WITNESS_STANDBY_ALLOWANCE = "WITNESS_STANDBY_ALLOWANCE".getBytes(); private static final byte[] ENERGY_FEE = "ENERGY_FEE".getBytes(); + private static final long DEFAULT_ENERGY_FEE = 100L; + public static final String DEFAULT_ENERGY_PRICE_HISTORY = "0:" + DEFAULT_ENERGY_FEE; private static final byte[] MAX_CPU_TIME_OF_ONE_TX = "MAX_CPU_TIME_OF_ONE_TX".getBytes(); //abandon private static final byte[] CREATE_ACCOUNT_FEE = "CREATE_ACCOUNT_FEE".getBytes(); @@ -156,10 +158,17 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] ALLOW_NEW_RESOURCE_MODEL = "ALLOW_NEW_RESOURCE_MODEL".getBytes(); private static final byte[] ALLOW_TVM_FREEZE = "ALLOW_TVM_FREEZE".getBytes(); private static final byte[] ALLOW_TVM_VOTE = "ALLOW_TVM_VOTE".getBytes(); + private static final byte[] ALLOW_TVM_LONDON = "ALLOW_TVM_LONDON".getBytes(); + private static final byte[] ALLOW_TVM_COMPATIBLE_EVM = "ALLOW_TVM_COMPATIBLE_EVM".getBytes(); private static final byte[] NEW_REWARD_ALGORITHM_EFFECTIVE_CYCLE = "NEW_REWARD_ALGORITHM_EFFECTIVE_CYCLE".getBytes(); //This value is only allowed to be 1 - private static final byte[] ALLOW_ACCOUNT_ASSET_OPTIMIZATION = "ALLOW_ACCOUNT_ASSET_OPTIMIZATION".getBytes(); + private static final byte[] ALLOW_ACCOUNT_ASSET_OPTIMIZATION = + "ALLOW_ACCOUNT_ASSET_OPTIMIZATION".getBytes(); + private static final byte[] ENERGY_PRICE_HISTORY = "ENERGY_PRICE_HISTORY".getBytes(); + private static final byte[] ENERGY_PRICE_HISTORY_DONE = "ENERGY_PRICE_HISTORY_DONE".getBytes(); + private static final byte[] SET_BLACKHOLE_ACCOUNT_PERMISSION = + "SET_BLACKHOLE_ACCOUNT_PERMISSION".getBytes(); @Autowired @@ -383,7 +392,7 @@ private DynamicPropertiesStore(@Value("properties") String dbName) { try { this.getEnergyFee(); } catch (IllegalArgumentException e) { - this.saveEnergyFee(100L);// 100 sun per energy + this.saveEnergyFee(DEFAULT_ENERGY_FEE); // 100 sun per energy } try { @@ -758,12 +767,42 @@ private DynamicPropertiesStore(@Value("properties") String dbName) { } } + try { + this.getAllowTvmLondon(); + } catch (IllegalArgumentException e) { + this.saveAllowTvmLondon(CommonParameter.getInstance().getAllowTvmLondon()); + } + + try { + this.getAllowTvmCompatibleEvm(); + } catch (IllegalArgumentException e) { + this.saveAllowTvmCompatibleEvm(CommonParameter.getInstance().getAllowTvmCompatibleEvm()); + } + try { this.getAllowAccountAssetOptimization(); } catch (IllegalArgumentException e) { this.setAllowAccountAssetOptimization(CommonParameter .getInstance().getAllowAccountAssetOptimization()); } + + try { + this.getEnergyPriceHistoryDone(); + } catch (IllegalArgumentException e) { + this.saveEnergyPriceHistoryDone(0); + } + + try { + this.getEnergyPriceHistory(); + } catch (IllegalArgumentException e) { + this.saveEnergyPriceHistory(DEFAULT_ENERGY_PRICE_HISTORY); + } + + try { + this.getSetBlackholeAccountPermission(); + } catch (IllegalArgumentException e) { + this.saveSetBlackholePermission(0); + } } public String intArrayToString(int[] a) { @@ -2255,6 +2294,34 @@ public long getAllowTvmVote() { () -> new IllegalArgumentException(msg)); } + public void saveAllowTvmLondon(long allowTvmLondon) { + this.put(DynamicPropertiesStore.ALLOW_TVM_LONDON, + new BytesCapsule(ByteArray.fromLong(allowTvmLondon))); + } + + public long getAllowTvmLondon() { + String msg = "not found ALLOW_TVM_LONDON"; + return Optional.ofNullable(getUnchecked(ALLOW_TVM_LONDON)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElseThrow( + () -> new IllegalArgumentException(msg)); + } + + public void saveAllowTvmCompatibleEvm(long allowTvmCompatibleEvm) { + this.put(DynamicPropertiesStore.ALLOW_TVM_COMPATIBLE_EVM, + new BytesCapsule(ByteArray.fromLong(allowTvmCompatibleEvm))); + } + + public long getAllowTvmCompatibleEvm() { + String msg = "not found ALLOW_TVM_COMPATIBLE_EVM"; + return Optional.ofNullable(getUnchecked(ALLOW_TVM_COMPATIBLE_EVM)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElseThrow( + () -> new IllegalArgumentException(msg)); + } + public boolean useNewRewardAlgorithm() { return getAllowTvmVote() == 1; } @@ -2286,6 +2353,42 @@ public void setAllowAccountAssetOptimization(long value) { this.put(ALLOW_ACCOUNT_ASSET_OPTIMIZATION, new BytesCapsule(ByteArray.fromLong(value))); } + public void saveEnergyPriceHistoryDone(long value) { + this.put(ENERGY_PRICE_HISTORY_DONE, + new BytesCapsule(ByteArray.fromLong(value))); + } + + public long getEnergyPriceHistoryDone() { + return Optional.ofNullable(getUnchecked(ENERGY_PRICE_HISTORY_DONE)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElseThrow( + () -> new IllegalArgumentException("not found ENERGY_PRICE_HISTORY_DONE")); + } + + public String getEnergyPriceHistory() { + return Optional.ofNullable(getUnchecked(ENERGY_PRICE_HISTORY)) + .map(BytesCapsule::getData) + .map(ByteArray::toStr) + .orElseThrow(() -> new IllegalArgumentException("not found ENERGY_PRICE_HISTORY")); + } + + public void saveEnergyPriceHistory(String value) { + this.put(ENERGY_PRICE_HISTORY, new BytesCapsule(ByteArray.fromString(value))); + } + + public long getSetBlackholeAccountPermission() { + return Optional.of(getUnchecked(SET_BLACKHOLE_ACCOUNT_PERMISSION)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElseThrow( + () -> new IllegalArgumentException("not found SET_BLACKHOLE_ACCOUNT_PERMISSION")); + } + + public void saveSetBlackholePermission(long value) { + this.put(SET_BLACKHOLE_ACCOUNT_PERMISSION, new BytesCapsule(ByteArray.fromLong(value))); + } + private static class DynamicResourceProperties { private static final byte[] ONE_DAY_NET_LIMIT = "ONE_DAY_NET_LIMIT".getBytes(); @@ -2314,6 +2417,7 @@ private static class DynamicResourceProperties { private static final byte[] ADAPTIVE_RESOURCE_LIMIT_TARGET_RATIO = "ADAPTIVE_RESOURCE_LIMIT_TARGET_RATIO" .getBytes(); + } } diff --git a/chainbase/src/main/java/org/tron/core/store/ProposalStore.java b/chainbase/src/main/java/org/tron/core/store/ProposalStore.java index ebdee87b3ac..3d39b717cfc 100644 --- a/chainbase/src/main/java/org/tron/core/store/ProposalStore.java +++ b/chainbase/src/main/java/org/tron/core/store/ProposalStore.java @@ -10,6 +10,7 @@ import org.tron.core.capsule.ProposalCapsule; import org.tron.core.db.TronStoreWithRevoking; import org.tron.core.exception.ItemNotFoundException; +import org.tron.protos.Protocol.Proposal.State; @Component public class ProposalStore extends TronStoreWithRevoking { @@ -36,4 +37,18 @@ public List getAllProposals() { : -1) .collect(Collectors.toList()); } + + /** + * note: return in asc order by expired time + */ + public List getSpecifiedProposals(State state, long code) { + return Streams.stream(iterator()) + .map(Map.Entry::getValue) + .filter(proposalCapsule -> proposalCapsule.getState().equals(state)) + .filter(proposalCapsule -> proposalCapsule.getParameters().containsKey(code)) + .sorted( + (ProposalCapsule a, ProposalCapsule b) -> a.getExpirationTime() > b.getExpirationTime() + ? 1 : -1) + .collect(Collectors.toList()); + } } \ No newline at end of file diff --git a/common/src/main/java/org/tron/common/logsfilter/TriggerConfig.java b/common/src/main/java/org/tron/common/logsfilter/TriggerConfig.java index 3ef6291b028..d76db47c40d 100644 --- a/common/src/main/java/org/tron/common/logsfilter/TriggerConfig.java +++ b/common/src/main/java/org/tron/common/logsfilter/TriggerConfig.java @@ -17,9 +17,24 @@ public class TriggerConfig { @Setter private String topic; + @Getter + @Setter + private boolean redundancy; + + @Getter + @Setter + private boolean ethCompatible; + + @Getter + @Setter + private boolean solidified; + public TriggerConfig() { triggerName = ""; enabled = false; topic = ""; + redundancy = false; // event will also write to log + ethCompatible = false; // add eth compatible fields, just for transaction now + solidified = false; // just write solidified data, just for block and transaction now } } \ No newline at end of file diff --git a/common/src/main/java/org/tron/common/logsfilter/trigger/ContractLogTrigger.java b/common/src/main/java/org/tron/common/logsfilter/trigger/ContractLogTrigger.java index 5f8830bb932..e3b591230f4 100644 --- a/common/src/main/java/org/tron/common/logsfilter/trigger/ContractLogTrigger.java +++ b/common/src/main/java/org/tron/common/logsfilter/trigger/ContractLogTrigger.java @@ -24,4 +24,22 @@ public ContractLogTrigger() { super(); setTriggerName(Trigger.CONTRACTLOG_TRIGGER_NAME); } + + public ContractLogTrigger(ContractEventTrigger eventTrigger) { + super(); + setTriggerName(Trigger.CONTRACTLOG_TRIGGER_NAME); + + setRawData(eventTrigger.getRawData()); + setLatestSolidifiedBlockNumber(eventTrigger.getLatestSolidifiedBlockNumber()); + setRemoved(eventTrigger.isRemoved()); + setUniqueId(eventTrigger.getUniqueId()); + setTransactionId(eventTrigger.getTransactionId()); + setContractAddress(eventTrigger.getContractAddress()); + setOriginAddress(eventTrigger.getOriginAddress()); + setCallerAddress(""); + setCreatorAddress(eventTrigger.getCreatorAddress()); + setBlockNumber(eventTrigger.getBlockNumber()); + setTimeStamp(eventTrigger.getTimeStamp()); + setBlockHash(eventTrigger.getBlockHash()); + } } diff --git a/common/src/main/java/org/tron/common/logsfilter/trigger/ContractTrigger.java b/common/src/main/java/org/tron/common/logsfilter/trigger/ContractTrigger.java index ed783990419..60380e1fa5f 100644 --- a/common/src/main/java/org/tron/common/logsfilter/trigger/ContractTrigger.java +++ b/common/src/main/java/org/tron/common/logsfilter/trigger/ContractTrigger.java @@ -57,6 +57,10 @@ public class ContractTrigger extends Trigger { @Setter private Long blockNumber; + @Getter + @Setter + private String blockHash; + /** * true if the transaction has been revoked */ diff --git a/common/src/main/java/org/tron/common/logsfilter/trigger/LogPojo.java b/common/src/main/java/org/tron/common/logsfilter/trigger/LogPojo.java new file mode 100644 index 00000000000..661c26f0774 --- /dev/null +++ b/common/src/main/java/org/tron/common/logsfilter/trigger/LogPojo.java @@ -0,0 +1,39 @@ +package org.tron.common.logsfilter.trigger; + +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +public class LogPojo { + @Getter + @Setter + private String address; + + @Getter + @Setter + private String blockHash; + + @Getter + @Setter + private long blockNumber; + + @Getter + @Setter + private String data; + + @Getter + @Setter + private long logIndex; + + @Getter + @Setter + private List topicList; + + @Getter + @Setter + private String transactionHash; + + @Getter + @Setter + private long transactionIndex; +} diff --git a/common/src/main/java/org/tron/common/logsfilter/trigger/TransactionLogTrigger.java b/common/src/main/java/org/tron/common/logsfilter/trigger/TransactionLogTrigger.java index 6c4858b5591..dec4170efb8 100644 --- a/common/src/main/java/org/tron/common/logsfilter/trigger/TransactionLogTrigger.java +++ b/common/src/main/java/org/tron/common/logsfilter/trigger/TransactionLogTrigger.java @@ -75,6 +75,21 @@ public class TransactionLogTrigger extends Trigger { @Getter @Setter private String data; + @Getter + @Setter + private int transactionIndex; + @Getter + @Setter + private long cumulativeEnergyUsed; + @Getter + @Setter + private long preCumulativeLogCount; + @Getter + @Setter + private List logList; + @Getter + @Setter + private long energyUnitPrice; public TransactionLogTrigger() { setTriggerName(Trigger.TRANSACTION_TRIGGER_NAME); diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index afdddf306e0..a9d4faafaaf 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -45,6 +45,10 @@ public class CommonParameter { public boolean supportConstant = false; @Getter @Setter + @Parameter(names = {"--max-energy-limit-for-constant"}) + public long maxEnergyLimitForConstant = 100_000_000L; + @Getter + @Setter @Parameter(names = {"--debug"}) public boolean debug = false; @Getter @@ -170,6 +174,15 @@ public class CommonParameter { public int solidityHttpPort; @Getter @Setter + public int jsonRpcHttpFullNodePort; + @Getter + @Setter + public int jsonRpcHttpSolidityPort; + @Getter + @Setter + public int jsonRpcHttpPBFTPort; + @Getter + @Setter @Parameter(names = {"--rpc-thread"}, description = "Num of gRPC thread") public int rpcThreadNum; @Getter @@ -296,7 +309,9 @@ public class CommonParameter { @Getter @Setter public int minEffectiveConnection; - + @Getter + @Setter + public boolean trxCacheEnable; @Getter @Setter public long allowMarketTransaction; //committee parameter @@ -391,6 +406,15 @@ public class CommonParameter { public boolean solidityNodeHttpEnable = true; @Getter @Setter + public boolean jsonRpcHttpFullNodeEnable = false; + @Getter + @Setter + public boolean jsonRpcHttpSolidityNodeEnable = false; + @Getter + @Setter + public boolean jsonRpcHttpPBFTNodeEnable = false; + @Getter + @Setter public int maxTransactionPendingSize; @Getter @Setter @@ -452,6 +476,14 @@ public class CommonParameter { @Setter public long allowTvmVote; + @Getter + @Setter + public long allowTvmLondon; + + @Getter + @Setter + public long allowTvmCompatibleEvm; + @Getter @Setter public boolean openHistoryQueryWhenLiteFN = false; @@ -476,6 +508,10 @@ public class CommonParameter { @Setter public long allowAccountAssetOptimization; + @Getter + @Setter + public List disabledApiList; + private static double calcMaxTimeRatio() { //return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1))); return 5.0; diff --git a/common/src/main/java/org/tron/common/utils/ByteArray.java b/common/src/main/java/org/tron/common/utils/ByteArray.java index 2db726b0346..801c64bd68a 100644 --- a/common/src/main/java/org/tron/common/utils/ByteArray.java +++ b/common/src/main/java/org/tron/common/utils/ByteArray.java @@ -107,6 +107,59 @@ public static byte[] fromObject(Object obj) { return bytes; } + /** + * Stringify byte[] x + * null for null + * null for empty [] + */ + public static String toJsonHex(byte[] x) { + return x == null || x.length == 0 ? "0x" : "0x" + Hex.toHexString(x); + } + + // ignore the 41 + public static String toJsonHexAddress(byte[] x) { + if (x == null || x.length == 0) { + return null; + } else { + String res = Hex.toHexString(x); + if (res.startsWith(DecodeUtil.addressPreFixString)) { + return "0x" + res.substring(DecodeUtil.addressPreFixString.length()); + } else { + return "0x" + res; + } + } + } + + public static String toJsonHex(Long x) { + return x == null ? null : "0x" + Long.toHexString(x); + } + + public static String toJsonHex(int x) { + return toJsonHex((long) x); + } + + public static BigInteger hexToBigInteger(String input) { + if (input.startsWith("0x")) { + return new BigInteger(input.substring(2), 16); + } else { + return new BigInteger(input, 10); + } + } + + public static long jsonHexToLong(String x) throws Exception { + if (!x.startsWith("0x")) + throw new Exception("Incorrect hex syntax"); + x = x.substring(2); + return Long.parseLong(x, 16); + } + + public static int jsonHexToInt(String x) throws Exception { + if (!x.startsWith("0x")) + throw new Exception("Incorrect hex syntax"); + x = x.substring(2); + return Integer.parseInt(x, 16); + } + /** * Generate a subarray of a given byte array. * diff --git a/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java b/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java index b400ae6686f..61af37b1060 100644 --- a/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java +++ b/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java @@ -8,9 +8,9 @@ public class DbOptionalsUtils { public static final CompressionType DEFAULT_COMPRESSION_TYPE = CompressionType.SNAPPY; public static final int DEFAULT_BLOCK_SIZE = 4 * 1024; - public static final int DEFAULT_WRITE_BUFFER_SIZE = 10 * 1024 * 1024; - public static final long DEFAULT_CACHE_SIZE = 10 * 1024 * 1024L; - public static final int DEFAULT_MAX_OPEN_FILES = 100; + public static final int DEFAULT_WRITE_BUFFER_SIZE = 64 * 1024 * 1024; + public static final long DEFAULT_CACHE_SIZE = 32 * 1024 * 1024L; + public static final int DEFAULT_MAX_OPEN_FILES = 5000; public static Options createDefaultDbOptions() { Options dbOptions = new Options(); diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index 890be85e2a0..e542a12491e 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -60,6 +60,7 @@ public class Constant { public static final String LOCAL_WITNESS_ACCOUNT_ADDRESS = "localWitnessAccountAddress"; public static final String LOCAL_WITNESS_KEYSTORE = "localwitnesskeystore"; public static final String VM_SUPPORT_CONSTANT = "vm.supportConstant"; + public static final String VM_MAX_ENERGY_LIMIT_FOR_CONSTANT = "vm.maxEnergyLimitForConstant"; public static final String VM_MIN_TIME_RATIO = "vm.minTimeRatio"; public static final String VM_MAX_TIME_RATIO = "vm.maxTimeRatio"; public static final String VM_LONG_RUNNING_TIME = "vm.longRunningTime"; @@ -95,6 +96,15 @@ public class Constant { public static final String NODE_HTTP_SOLIDITY_ENABLE = "node.http.solidityEnable"; public static final String NODE_HTTP_PBFT_PORT = "node.http.PBFTPort"; + public static final String NODE_JSONRPC_HTTP_FULLNODE_ENABLE = "node.jsonrpc.httpFullNodeEnable"; + public static final String NODE_JSONRPC_HTTP_FULLNODE_PORT = "node.jsonrpc.httpFullNodePort"; + public static final String NODE_JSONRPC_HTTP_SOLIDITY_ENABLE = "node.jsonrpc.httpSolidityEnable"; + public static final String NODE_JSONRPC_HTTP_SOLIDITY_PORT = "node.jsonrpc.httpSolidityPort"; + public static final String NODE_JSONRPC_HTTP_PBFT_ENABLE = "node.jsonrpc.httpPBFTEnable"; + public static final String NODE_JSONRPC_HTTP_PBFT_PORT = "node.jsonrpc.httpPBFTPort"; + + public static final String NODE_DISABLED_API_LIST = "node.disabledApi"; + public static final String NODE_RPC_THREAD = "node.rpc.thread"; public static final String NODE_SOLIDITY_THREADS = "node.solidity.threads"; @@ -169,6 +179,8 @@ public class Constant { public static final String NODE_RPC_MIN_EFFECTIVE_CONNECTION = "node.rpc.minEffectiveConnection"; + public static final String NODE_RPC_TRX_CACHE_ENABLE = "node.rpc.trxCacheEnable"; + public static final String ENERGY_LIMIT_BLOCK_NUM = "enery.limit.block.num"; public static final String VM_TRACE = "vm.vmTrace"; @@ -267,6 +279,9 @@ public class Constant { public static final String COMMITTEE_ALLOW_TVM_FREEZE = "committee.allowTvmFreeze"; public static final String COMMITTEE_ALLOW_TVM_VOTE = "committee.allowTvmVote"; + public static final String COMMITTEE_ALLOW_TVM_LONDON = "committee.allowTvmLondon"; + public static final String COMMITTEE_ALLOW_TVM_COMPATIBLE_EVM = "committee.allowTvmCompatibleEvm"; + public static final String METRICS_STORAGE_ENABLE = "node.metrics.storageEnable"; public static final String METRICS_INFLUXDB_IP = "node.metrics.influxdb.ip"; public static final String METRICS_INFLUXDB_PORT = "node.metrics.influxdb.port"; diff --git a/common/src/main/java/org/tron/core/config/Parameter.java b/common/src/main/java/org/tron/core/config/Parameter.java index b64efb7eb92..386289436f7 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -16,7 +16,8 @@ public enum ForkBlockVersionEnum { VERSION_4_1(19, 1596780000000L, 80),//GMT 2020-08-07 06:00:00,80 means 22 SR upgrade VERSION_4_1_2(20, 1596780000000L, 80), VERSION_4_2(21, 1596780000000L, 80), - VERSION_4_3(22, 1596780000000L, 80); + VERSION_4_3(22, 1596780000000L, 80), + VERSION_4_4(23, 1596780000000L, 80); @Getter private int value; @@ -64,7 +65,7 @@ public class ChainConstant { public static final int SINGLE_REPEAT = 1; public static final int BLOCK_FILLED_SLOTS_NUMBER = 128; public static final int MAX_FROZEN_NUMBER = 1; - public static final int BLOCK_VERSION = 22; + public static final int BLOCK_VERSION = 23; public static final long FROZEN_PERIOD = 86_400_000L; public static final long TRX_PRECISION = 1000_000L; } diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcInternalException.java b/common/src/main/java/org/tron/core/exception/JsonRpcInternalException.java new file mode 100644 index 00000000000..12310e67747 --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/JsonRpcInternalException.java @@ -0,0 +1,16 @@ +package org.tron.core.exception; + +public class JsonRpcInternalException extends TronException { + + public JsonRpcInternalException() { + super(); + } + + public JsonRpcInternalException(String message) { + super(message); + } + + public JsonRpcInternalException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcInvalidParamsException.java b/common/src/main/java/org/tron/core/exception/JsonRpcInvalidParamsException.java new file mode 100644 index 00000000000..adf205a309a --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/JsonRpcInvalidParamsException.java @@ -0,0 +1,16 @@ +package org.tron.core.exception; + +public class JsonRpcInvalidParamsException extends TronException { + + public JsonRpcInvalidParamsException() { + super(); + } + + public JsonRpcInvalidParamsException(String msg) { + super(msg); + } + + public JsonRpcInvalidParamsException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcInvalidRequestException.java b/common/src/main/java/org/tron/core/exception/JsonRpcInvalidRequestException.java new file mode 100644 index 00000000000..2689bff0cd2 --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/JsonRpcInvalidRequestException.java @@ -0,0 +1,16 @@ +package org.tron.core.exception; + +public class JsonRpcInvalidRequestException extends TronException { + + public JsonRpcInvalidRequestException() { + super(); + } + + public JsonRpcInvalidRequestException(String message) { + super(message); + } + + public JsonRpcInvalidRequestException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcMethodNotFoundException.java b/common/src/main/java/org/tron/core/exception/JsonRpcMethodNotFoundException.java new file mode 100644 index 00000000000..d8e18168d9d --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/JsonRpcMethodNotFoundException.java @@ -0,0 +1,16 @@ +package org.tron.core.exception; + +public class JsonRpcMethodNotFoundException extends TronException { + + public JsonRpcMethodNotFoundException() { + super(); + } + + public JsonRpcMethodNotFoundException(String msg) { + super(msg); + } + + public JsonRpcMethodNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/crypto/src/main/java/org/tron/common/crypto/Blake2bfMessageDigest.java b/crypto/src/main/java/org/tron/common/crypto/Blake2bfMessageDigest.java new file mode 100644 index 00000000000..64073210493 --- /dev/null +++ b/crypto/src/main/java/org/tron/common/crypto/Blake2bfMessageDigest.java @@ -0,0 +1,272 @@ +package org.tron.common.crypto; + +import static java.util.Arrays.copyOfRange; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.jcajce.provider.digest.BCMessageDigest; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; + +public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable { + + public Blake2bfMessageDigest() { + super(new Blake2bfDigest()); + } + + /** + * Implementation of the `F` compression function of the Blake2b cryptographic hash function. + * + *

RFC - https://tools.ietf.org/html/rfc7693 + * + *

Adapted from - https://github.com/keep-network/blake2b/blob/master/compression/f.go + * + *

Optimized for 64-bit platforms + */ + public static class Blake2bfDigest implements Digest { + + public static final int MESSAGE_LENGTH_BYTES = 213; + + private static final long[] IV = { + 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL, + 0xa54ff53a5f1d36f1L, 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL, + 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L + }; + + private static final byte[][] PRECOMPUTED = { + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, + {11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4}, + {7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8}, + {9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13}, + {2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9}, + {12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11}, + {13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10}, + {6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5}, + {10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0} + }; + + private static final int DIGEST_LENGTH = 64; + + // buffer which holds serialized input for this compression function + // [ 4 bytes for rounds ][ 64 bytes for h ][ 128 bytes for m ] + // [ 8 bytes for t_0 ][ 8 bytes for t_1 ][ 1 byte for f ] + private final byte[] buffer; + + private int bufferPos; + + // deserialized inputs for f compression + private final long[] h; + private final long[] m; + private final long[] t; + private boolean f; + private long rounds; // unsigned integer represented as long + + private final long[] v; + + Blake2bfDigest() { + buffer = new byte[MESSAGE_LENGTH_BYTES]; + bufferPos = 0; + + h = new long[8]; + m = new long[16]; + t = new long[2]; + f = false; + rounds = 12; + + v = new long[16]; + } + + // for tests + Blake2bfDigest( + final long[] h, final long[] m, final long[] t, final boolean f, final long rounds) { + assert rounds <= 4294967295L; // uint max value + buffer = new byte[MESSAGE_LENGTH_BYTES]; + bufferPos = 0; + + this.h = h; + this.m = m; + this.t = t; + this.f = f; + this.rounds = rounds; + + v = new long[16]; + } + + @Override + public String getAlgorithmName() { + return "BLAKE2f"; + } + + @Override + public int getDigestSize() { + return DIGEST_LENGTH; + } + + /** + * update the message digest with a single byte. + * + * @param in the input byte to be entered. + */ + @Override + public void update(final byte in) { + + if (bufferPos == MESSAGE_LENGTH_BYTES) { // full buffer + throw new IllegalArgumentException(); + } else { + buffer[bufferPos] = in; + bufferPos++; + if (bufferPos == MESSAGE_LENGTH_BYTES) { + initialize(); + } + } + } + + /** + * update the message digest with a block of bytes. + * + * @param in the byte array containing the data. + * @param offset the offset into the byte array where the data starts. + * @param len the length of the data. + */ + @Override + public void update(final byte[] in, final int offset, final int len) { + if (in == null || len == 0) { + return; + } + + if (len > MESSAGE_LENGTH_BYTES - bufferPos) { + throw new IllegalArgumentException( + "Attempting to update buffer with " + + len + + " byte(s) but there is " + + (MESSAGE_LENGTH_BYTES - bufferPos) + + " byte(s) left to fill"); + } + + System.arraycopy(in, offset, buffer, bufferPos, len); + + bufferPos += len; + + if (bufferPos == MESSAGE_LENGTH_BYTES) { + initialize(); + } + } + + /** + * close the digest, producing the final digest value. The doFinal call leaves the digest reset. + * + * @param out the array the digest is to be copied into. + * @param offset the offset into the out array the digest is to start at. + */ + @Override + public int doFinal(final byte[] out, final int offset) { + if (bufferPos != 213) { + throw new IllegalStateException("The buffer must be filled with 213 bytes"); + } + + compress(); + + for (int i = 0; i < h.length; i++) { + System.arraycopy(Pack.longToLittleEndian(h[i]), 0, out, i * 8, 8); + } + + reset(); + + return 0; + } + + /** Reset the digest back to it's initial state. */ + @Override + public void reset() { + bufferPos = 0; + Arrays.fill(buffer, (byte) 0); + Arrays.fill(h, 0); + Arrays.fill(m, (byte) 0); + Arrays.fill(t, 0); + f = false; + rounds = 12; + Arrays.fill(v, 0); + } + + private void initialize() { + rounds = Integer.toUnsignedLong(bytesToInt(copyOfRange(buffer, 0, 4))); + + for (int i = 0; i < h.length; i++) { + final int offset = 4 + i * 8; + h[i] = bytesToLong((copyOfRange(buffer, offset, offset + 8))); + } + + for (int i = 0; i < 16; i++) { + final int offset = 68 + i * 8; + m[i] = bytesToLong(copyOfRange(buffer, offset, offset + 8)); + } + + t[0] = bytesToLong(copyOfRange(buffer, 196, 204)); + t[1] = bytesToLong(copyOfRange(buffer, 204, 212)); + + f = buffer[212] != 0; + } + + private int bytesToInt(final byte[] bytes) { + return Pack.bigEndianToInt(bytes, 0); + } + + private long bytesToLong(final byte[] bytes) { + return Pack.littleEndianToLong(bytes, 0); + } + + /** + * F is a compression function for BLAKE2b. It takes as an argument the state vector `h`, + * message block vector `m`, offset counter `t`, final block indicator flag `f`, and number of + * rounds `rounds`. The state vector provided as the first parameter is modified by the + * function. + */ + private void compress() { + + long t0 = t[0]; + long t1 = t[1]; + + System.arraycopy(h, 0, v, 0, 8); + System.arraycopy(IV, 0, v, 8, 8); + + v[12] ^= t0; + v[13] ^= t1; + + if (f) { + v[14] ^= 0xffffffffffffffffL; + } + + for (long j = 0; j < rounds; ++j) { + byte[] s = PRECOMPUTED[(int) (j % 10)]; + + mix(m[s[0]], m[s[4]], 0, 4, 8, 12); + mix(m[s[1]], m[s[5]], 1, 5, 9, 13); + mix(m[s[2]], m[s[6]], 2, 6, 10, 14); + mix(m[s[3]], m[s[7]], 3, 7, 11, 15); + mix(m[s[8]], m[s[12]], 0, 5, 10, 15); + mix(m[s[9]], m[s[13]], 1, 6, 11, 12); + mix(m[s[10]], m[s[14]], 2, 7, 8, 13); + mix(m[s[11]], m[s[15]], 3, 4, 9, 14); + } + + // update h: + for (int offset = 0; offset < h.length; offset++) { + h[offset] ^= v[offset] ^ v[offset + 8]; + } + } + + private void mix( + final long a, final long b, final int i, final int j, final int k, final int l) { + v[i] += a + v[j]; + v[l] = Long.rotateLeft(v[l] ^ v[i], -32); + v[k] += v[l]; + v[j] = Long.rotateLeft(v[j] ^ v[k], -24); + + v[i] += b + v[j]; + v[l] = Long.rotateLeft(v[l] ^ v[i], -16); + v[k] += v[l]; + v[j] = Long.rotateLeft(v[j] ^ v[k], -63); + } + } +} + diff --git a/crypto/src/main/java/org/tron/common/crypto/Hash.java b/crypto/src/main/java/org/tron/common/crypto/Hash.java index a4cb07ce65d..eca769a8dad 100644 --- a/crypto/src/main/java/org/tron/common/crypto/Hash.java +++ b/crypto/src/main/java/org/tron/common/crypto/Hash.java @@ -32,6 +32,8 @@ import org.bouncycastle.math.ec.ECPoint; import org.tron.common.crypto.jce.TronCastleProvider; import org.tron.common.utils.DecodeUtil; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.RIPEMD160Digest; @Slf4j(topic = "crypto") public class Hash { @@ -195,4 +197,18 @@ public static byte[] sha3omit12(byte[] input) { address[0] = DecodeUtil.addressPreFixByte; return address; } + + /** @param data - message to hash + * + * @return - ripemd160 hash of the message + */ + public static byte[] ripemd160(byte[] data) { + Digest digest = new RIPEMD160Digest(); + + byte[] resBuf = new byte[digest.getDigestSize()]; + digest.update(data, 0, data.length); + digest.doFinal(resBuf, 0); + return resBuf; + } + } diff --git a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java index aeffedc2f7f..c6aebba385a 100644 --- a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java +++ b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java @@ -72,7 +72,7 @@ public class SM2 implements Serializable, SignInterface { static { secureRandom = new SecureRandom(); - curve = new ECCurve.Fp(SM2_P, SM2_A, SM2_B); + curve = new ECCurve.Fp(SM2_P, SM2_A, SM2_B, null, null); ecc_point_g = curve.createPoint(SM2_GX, SM2_GY); ecc_param = new ECDomainParameters(curve, ecc_point_g, SM2_N); ecc_spec = new ECParameterSpec(curve, ecc_point_g, SM2_N); diff --git a/framework/build.gradle b/framework/build.gradle index b113f61f9fe..68f093c4d86 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -78,6 +78,12 @@ dependencies { compile group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.1' // end http + // https://mvnrepository.com/artifact/com.github.briandilley.jsonrpc4j/jsonrpc4j + compile group: 'com.github.briandilley.jsonrpc4j', name: 'jsonrpc4j', version: '1.6' + + // https://mvnrepository.com/artifact/javax.portlet/portlet-api + compileOnly group: 'javax.portlet', name: 'portlet-api', version: '3.0.1' + compile "io.vavr:vavr:0.9.2" compile group: 'org.pf4j', name: 'pf4j', version: '2.5.0' diff --git a/framework/src/main/java/org/tron/common/application/ApplicationImpl.java b/framework/src/main/java/org/tron/common/application/ApplicationImpl.java index edeadb4432b..8e80a568a96 100644 --- a/framework/src/main/java/org/tron/common/application/ApplicationImpl.java +++ b/framework/src/main/java/org/tron/common/application/ApplicationImpl.java @@ -11,6 +11,7 @@ import org.tron.core.db.Manager; import org.tron.core.metrics.MetricsUtil; import org.tron.core.net.TronNetService; +import org.tron.program.FullNode; @Slf4j(topic = "app") @Component @@ -73,6 +74,7 @@ public void shutdown() { dbManager.stopRePushTriggerThread(); EventPluginLoader.getInstance().stopPlugin(); logger.info("******** end to shutdown ********"); + FullNode.shutDownSign = true; } @Override diff --git a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java index 81cb01684fc..c8019dac93a 100644 --- a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java +++ b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java @@ -44,16 +44,26 @@ public class EventPluginLoader { private boolean blockLogTriggerEnable = false; + private boolean blockLogTriggerSolidified = false; + private boolean transactionLogTriggerEnable = false; + private boolean transactionLogTriggerSolidified = false; + + private boolean transactionLogTriggerEthCompatible = false; + private boolean contractEventTriggerEnable = false; private boolean contractLogTriggerEnable = false; + private boolean contractLogTriggerRedundancy = false; + private boolean solidityEventTriggerEnable = false; private boolean solidityLogTriggerEnable = false; + private boolean solidityLogTriggerRedundancy = false; + private boolean solidityTriggerEnable = false; private FilterQuery filterQuery; @@ -241,8 +251,12 @@ private void setSingleTriggerConfig(TriggerConfig triggerConfig) { if (EventPluginConfig.BLOCK_TRIGGER_NAME.equalsIgnoreCase(triggerConfig.getTriggerName())) { if (triggerConfig.isEnabled()) { blockLogTriggerEnable = true; + if (triggerConfig.isSolidified()) { + blockLogTriggerSolidified = true; + } } else { blockLogTriggerEnable = false; + blockLogTriggerSolidified = false; } if (!useNativeQueue) { @@ -253,8 +267,16 @@ private void setSingleTriggerConfig(TriggerConfig triggerConfig) { .equalsIgnoreCase(triggerConfig.getTriggerName())) { if (triggerConfig.isEnabled()) { transactionLogTriggerEnable = true; + if (triggerConfig.isEthCompatible()) { + transactionLogTriggerEthCompatible = true; + } + if (triggerConfig.isSolidified()) { + transactionLogTriggerSolidified = true; + } } else { transactionLogTriggerEnable = false; + transactionLogTriggerEthCompatible = false; + transactionLogTriggerSolidified = false; } if (!useNativeQueue) { @@ -277,8 +299,12 @@ private void setSingleTriggerConfig(TriggerConfig triggerConfig) { .equalsIgnoreCase(triggerConfig.getTriggerName())) { if (triggerConfig.isEnabled()) { contractLogTriggerEnable = true; + if (triggerConfig.isRedundancy()) { + contractLogTriggerRedundancy = true; + } } else { contractLogTriggerEnable = false; + contractLogTriggerRedundancy = false; } if (!useNativeQueue) { @@ -309,8 +335,12 @@ private void setSingleTriggerConfig(TriggerConfig triggerConfig) { .equalsIgnoreCase(triggerConfig.getTriggerName())) { if (triggerConfig.isEnabled()) { solidityLogTriggerEnable = true; + if (triggerConfig.isRedundancy()) { + solidityLogTriggerRedundancy = true; + } } else { solidityLogTriggerEnable = false; + solidityLogTriggerRedundancy = false; } if (!useNativeQueue) { setPluginTopic(Trigger.SOLIDITY_LOG_TRIGGER, triggerConfig.getTopic()); @@ -332,6 +362,10 @@ public synchronized boolean isBlockLogTriggerEnable() { return blockLogTriggerEnable; } + public synchronized boolean isBlockLogTriggerSolidified() { + return blockLogTriggerSolidified; + } + public synchronized boolean isSolidityTriggerEnable() { return solidityTriggerEnable; } @@ -344,10 +378,22 @@ public synchronized boolean isSolidityLogTriggerEnable() { return solidityLogTriggerEnable; } + public synchronized boolean isSolidityLogTriggerRedundancy() { + return solidityLogTriggerRedundancy; + } + public synchronized boolean isTransactionLogTriggerEnable() { return transactionLogTriggerEnable; } + public synchronized boolean isTransactionLogTriggerEthCompatible() { + return transactionLogTriggerEthCompatible; + } + + public synchronized boolean isTransactionLogTriggerSolidified() { + return transactionLogTriggerSolidified; + } + public synchronized boolean isContractEventTriggerEnable() { return contractEventTriggerEnable; } @@ -356,6 +402,10 @@ public synchronized boolean isContractLogTriggerEnable() { return contractLogTriggerEnable; } + public synchronized boolean isContractLogTriggerRedundancy() { + return contractLogTriggerRedundancy; + } + private void setPluginTopic(int eventType, String topic) { eventListeners.forEach(listener -> listener.setTopic(eventType, topic)); } diff --git a/framework/src/main/java/org/tron/common/logsfilter/capsule/ContractTriggerCapsule.java b/framework/src/main/java/org/tron/common/logsfilter/capsule/ContractTriggerCapsule.java index 80e588d9a17..60e15d91d5d 100644 --- a/framework/src/main/java/org/tron/common/logsfilter/capsule/ContractTriggerCapsule.java +++ b/framework/src/main/java/org/tron/common/logsfilter/capsule/ContractTriggerCapsule.java @@ -36,6 +36,10 @@ public void setLatestSolidifiedBlockNumber(long latestSolidifiedBlockNumber) { contractTrigger.setLatestSolidifiedBlockNumber(latestSolidifiedBlockNumber); } + public void setBlockHash(String blockHash) { + contractTrigger.setBlockHash(blockHash); + } + @Override public void processTrigger() { ContractTrigger event; @@ -123,6 +127,7 @@ public void processTrigger() { event.setCreatorAddress(contractTrigger.getCreatorAddress()); event.setBlockNumber(contractTrigger.getBlockNumber()); event.setTimeStamp(contractTrigger.getTimeStamp()); + event.setBlockHash(contractTrigger.getBlockHash()); if (matchFilter(contractTrigger)) { if (isEvent) { @@ -131,20 +136,54 @@ public void processTrigger() { } if (EventPluginLoader.getInstance().isSolidityEventTriggerEnable()) { - Args.getSolidityContractEventTriggerMap().computeIfAbsent(event + boolean result = Args.getSolidityContractEventTriggerMap().computeIfAbsent(event .getBlockNumber(), listBlk -> new LinkedBlockingQueue()) .offer((ContractEventTrigger) event); + + if (!result) { + logger.info("too many triggers, solidity event trigger lost: {}", + event.getUniqueId()); + } } + // enable process contractEvent as contractLog + if ((EventPluginLoader.getInstance().isContractLogTriggerEnable() + && EventPluginLoader.getInstance().isContractLogTriggerRedundancy()) + || (EventPluginLoader.getInstance().isSolidityLogTriggerEnable() + && EventPluginLoader.getInstance().isSolidityLogTriggerRedundancy())) { + ContractLogTrigger logTrigger = new ContractLogTrigger((ContractEventTrigger) event); + logTrigger.setTopicList(logInfo.getHexTopics()); + logTrigger.setData(logInfo.getHexData()); + + if (EventPluginLoader.getInstance().isContractLogTriggerRedundancy()) { + EventPluginLoader.getInstance().postContractLogTrigger(logTrigger); + } + + if (EventPluginLoader.getInstance().isSolidityLogTriggerRedundancy()) { + boolean result = Args.getSolidityContractLogTriggerMap().computeIfAbsent(event + .getBlockNumber(), listBlk -> new LinkedBlockingQueue()) + .offer(logTrigger); + + if (!result) { + logger.info("too many triggers, solidity log trigger lost: {}", + logTrigger.getUniqueId()); + } + } + } } else { if (EventPluginLoader.getInstance().isContractLogTriggerEnable()) { EventPluginLoader.getInstance().postContractLogTrigger((ContractLogTrigger) event); } if (EventPluginLoader.getInstance().isSolidityLogTriggerEnable()) { - Args.getSolidityContractLogTriggerMap().computeIfAbsent(event + boolean result = Args.getSolidityContractLogTriggerMap().computeIfAbsent(event .getBlockNumber(), listBlk -> new LinkedBlockingQueue()) .offer((ContractLogTrigger) event); + + if (!result) { + logger.info("too many triggers, solidity log trigger lost: {}", + event.getUniqueId()); + } } } } diff --git a/framework/src/main/java/org/tron/common/logsfilter/capsule/SolidityTriggerCapsule.java b/framework/src/main/java/org/tron/common/logsfilter/capsule/SolidityTriggerCapsule.java index c4ab8db0d1c..2da7f1f4973 100644 --- a/framework/src/main/java/org/tron/common/logsfilter/capsule/SolidityTriggerCapsule.java +++ b/framework/src/main/java/org/tron/common/logsfilter/capsule/SolidityTriggerCapsule.java @@ -16,6 +16,10 @@ public SolidityTriggerCapsule(long latestSolidifiedBlockNum) { solidityTrigger.setLatestSolidifiedBlockNumber(latestSolidifiedBlockNum); } + public void setTimeStamp(long timeStamp) { + solidityTrigger.setTimeStamp(timeStamp); + } + @Override public void processTrigger() { EventPluginLoader.getInstance().postSolidityTrigger(solidityTrigger); diff --git a/framework/src/main/java/org/tron/common/logsfilter/capsule/TransactionLogTriggerCapsule.java b/framework/src/main/java/org/tron/common/logsfilter/capsule/TransactionLogTriggerCapsule.java index d478ad1898e..8600cb6ef8c 100644 --- a/framework/src/main/java/org/tron/common/logsfilter/capsule/TransactionLogTriggerCapsule.java +++ b/framework/src/main/java/org/tron/common/logsfilter/capsule/TransactionLogTriggerCapsule.java @@ -1,7 +1,6 @@ package org.tron.common.logsfilter.capsule; -import static org.tron.protos.Protocol.Transaction.Contract.ContractType.TransferAssetContract; -import static org.tron.protos.Protocol.Transaction.Contract.ContractType.TransferContract; +import static org.tron.protos.Protocol.Transaction.Contract.ContractType.CreateSmartContract; import com.google.protobuf.Any; import com.google.protobuf.ByteString; @@ -14,6 +13,7 @@ import org.bouncycastle.util.encoders.Hex; import org.tron.common.logsfilter.EventPluginLoader; import org.tron.common.logsfilter.trigger.InternalTransactionPojo; +import org.tron.common.logsfilter.trigger.LogPojo; import org.tron.common.logsfilter.trigger.TransactionLogTrigger; import org.tron.common.runtime.InternalTransaction; import org.tron.common.runtime.ProgramResult; @@ -22,8 +22,13 @@ import org.tron.core.capsule.TransactionCapsule; import org.tron.core.db.TransactionTrace; import org.tron.protos.Protocol; +import org.tron.protos.Protocol.Transaction; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.TransactionInfo; import org.tron.protos.contract.AssetIssueContractOuterClass.TransferAssetContract; import org.tron.protos.contract.BalanceContract.TransferContract; +import org.tron.protos.contract.SmartContractOuterClass.CreateSmartContract; +import org.tron.protos.contract.SmartContractOuterClass.TriggerSmartContract; @Slf4j public class TransactionLogTriggerCapsule extends TriggerCapsule { @@ -33,11 +38,22 @@ public class TransactionLogTriggerCapsule extends TriggerCapsule { private TransactionLogTrigger transactionLogTrigger; public TransactionLogTriggerCapsule(TransactionCapsule trxCapsule, BlockCapsule blockCapsule) { + this(trxCapsule, blockCapsule, 0, 0, 0, null, 0); + } + + public TransactionLogTriggerCapsule(TransactionCapsule trxCapsule, BlockCapsule blockCapsule, + int txIndex, long preCumulativeEnergyUsed, long preCumulativeLogCount, + TransactionInfo transactionInfo, long energyUnitPrice) { transactionLogTrigger = new TransactionLogTrigger(); + + String blockHash = ""; if (Objects.nonNull(blockCapsule)) { - transactionLogTrigger.setBlockHash(blockCapsule.getBlockId().toString()); + blockHash = blockCapsule.getBlockId().toString(); + transactionLogTrigger.setBlockHash(blockHash); } - transactionLogTrigger.setTransactionId(trxCapsule.getTransactionId().toString()); + + String transactionHash = trxCapsule.getTransactionId().toString(); + transactionLogTrigger.setTransactionId(transactionHash); transactionLogTrigger.setTimeStamp(blockCapsule.getTimeStamp()); transactionLogTrigger.setBlockNumber(trxCapsule.getBlockNum()); transactionLogTrigger.setData(Hex.toHexString(trxCapsule @@ -50,15 +66,19 @@ public TransactionLogTriggerCapsule(TransactionCapsule trxCapsule, BlockCapsule transactionLogTrigger.setResult(trxCapsule.getContractRet().toString()); } - if (Objects.nonNull(trxCapsule.getInstance().getRawData())) { + Transaction.raw rawData = trxCapsule.getInstance().getRawData(); + ContractType contractType = null; + + if (Objects.nonNull(rawData)) { // fee limit - transactionLogTrigger.setFeeLimit(trxCapsule.getInstance().getRawData().getFeeLimit()); + transactionLogTrigger.setFeeLimit(rawData.getFeeLimit()); - Protocol.Transaction.Contract contract = trxCapsule.getInstance().getRawData().getContract(0); + Protocol.Transaction.Contract contract = rawData.getContract(0); Any contractParameter = null; + // contract type if (Objects.nonNull(contract)) { - Protocol.Transaction.Contract.ContractType contractType = contract.getType(); + contractType = contract.getType(); if (Objects.nonNull(contractType)) { transactionLogTrigger.setContractType(contractType.toString()); } @@ -70,57 +90,89 @@ public TransactionLogTriggerCapsule(TransactionCapsule trxCapsule, BlockCapsule if (Objects.nonNull(contractParameter) && Objects.nonNull(contract)) { try { - if (contract.getType() == TransferContract) { - TransferContract contractTransfer = contractParameter.unpack(TransferContract.class); + switch (contractType) { + case TransferContract: + TransferContract transferContract = contractParameter.unpack(TransferContract.class); - if (Objects.nonNull(contractTransfer)) { - transactionLogTrigger.setAssetName("trx"); + if (Objects.nonNull(transferContract)) { + transactionLogTrigger.setAssetName("trx"); - if (Objects.nonNull(contractTransfer.getOwnerAddress())) { - transactionLogTrigger.setFromAddress(StringUtil - .encode58Check(contractTransfer.getOwnerAddress().toByteArray())); - } - - if (Objects.nonNull(contractTransfer.getToAddress())) { - transactionLogTrigger.setToAddress( - StringUtil.encode58Check(contractTransfer.getToAddress().toByteArray())); - } + if (Objects.nonNull(transferContract.getOwnerAddress())) { + transactionLogTrigger.setFromAddress(StringUtil + .encode58Check(transferContract.getOwnerAddress().toByteArray())); + } - transactionLogTrigger.setAssetAmount(contractTransfer.getAmount()); - } + if (Objects.nonNull(transferContract.getToAddress())) { + transactionLogTrigger.setToAddress( + StringUtil.encode58Check(transferContract.getToAddress().toByteArray())); + } - } else if (contract.getType() == TransferAssetContract) { - TransferAssetContract contractTransfer = contractParameter - .unpack(TransferAssetContract.class); - - if (Objects.nonNull(contractTransfer)) { - if (Objects.nonNull(contractTransfer.getAssetName())) { - transactionLogTrigger.setAssetName(contractTransfer.getAssetName().toStringUtf8()); + transactionLogTrigger.setAssetAmount(transferContract.getAmount()); + } + break; + case TransferAssetContract: + TransferAssetContract transferAssetContract = contractParameter + .unpack(TransferAssetContract.class); + + if (Objects.nonNull(transferAssetContract)) { + if (Objects.nonNull(transferAssetContract.getAssetName())) { + transactionLogTrigger + .setAssetName(transferAssetContract.getAssetName().toStringUtf8()); + } + + if (Objects.nonNull(transferAssetContract.getOwnerAddress())) { + transactionLogTrigger.setFromAddress( + StringUtil + .encode58Check(transferAssetContract.getOwnerAddress().toByteArray())); + } + + if (Objects.nonNull(transferAssetContract.getToAddress())) { + transactionLogTrigger.setToAddress(StringUtil + .encode58Check(transferAssetContract.getToAddress().toByteArray())); + } + transactionLogTrigger.setAssetAmount(transferAssetContract.getAmount()); } + break; + case TriggerSmartContract: + TriggerSmartContract triggerSmartContract = contractParameter + .unpack(TriggerSmartContract.class); - if (Objects.nonNull(contractTransfer.getOwnerAddress())) { + if (Objects.nonNull(triggerSmartContract.getOwnerAddress())) { transactionLogTrigger.setFromAddress( - StringUtil.encode58Check(contractTransfer.getOwnerAddress().toByteArray())); + StringUtil.encode58Check(triggerSmartContract.getOwnerAddress().toByteArray())); } - if (Objects.nonNull(contractTransfer.getToAddress())) { + if (Objects.nonNull(triggerSmartContract.getContractAddress())) { transactionLogTrigger.setToAddress(StringUtil - .encode58Check(contractTransfer.getToAddress().toByteArray())); + .encode58Check(triggerSmartContract.getContractAddress().toByteArray())); } - transactionLogTrigger.setAssetAmount(contractTransfer.getAmount()); - } + break; + case CreateSmartContract: + CreateSmartContract createSmartContract = contractParameter + .unpack(CreateSmartContract.class); + + if (Objects.nonNull(createSmartContract.getOwnerAddress())) { + transactionLogTrigger.setFromAddress( + StringUtil.encode58Check(createSmartContract.getOwnerAddress().toByteArray())); + } + break; + default: + break; } } catch (Exception e) { - logger.error("failed to load transferAssetContract, error'{}'", e); + logger.error("failed to load transferAssetContract, error '{}'", e.getMessage()); } } } + long energyUsageTotal = 0; // receipt if (Objects.nonNull(trxTrace) && Objects.nonNull(trxTrace.getReceipt())) { + energyUsageTotal = trxTrace.getReceipt().getEnergyUsageTotal(); + transactionLogTrigger.setEnergyFee(trxTrace.getReceipt().getEnergyFee()); transactionLogTrigger.setOriginEnergyUsage(trxTrace.getReceipt().getOriginEnergyUsage()); - transactionLogTrigger.setEnergyUsageTotal(trxTrace.getReceipt().getEnergyUsageTotal()); + transactionLogTrigger.setEnergyUsageTotal(energyUsageTotal); transactionLogTrigger.setNetUsage(trxTrace.getReceipt().getNetUsage()); transactionLogTrigger.setNetFee(trxTrace.getReceipt().getNetFee()); transactionLogTrigger.setEnergyUsage(trxTrace.getReceipt().getEnergyUsage()); @@ -138,14 +190,52 @@ public TransactionLogTriggerCapsule(TransactionCapsule trxCapsule, BlockCapsule } if (Objects.nonNull(contractAddress) && contractAddress.size() > 0) { - transactionLogTrigger - .setContractAddress(StringUtil.encode58Check((contractAddress.toByteArray()))); + if (Objects.nonNull(transactionInfo) + && contractType != null && contractType != CreateSmartContract) { + transactionLogTrigger.setContractAddress(null); + } else { + transactionLogTrigger + .setContractAddress(StringUtil.encode58Check((contractAddress.toByteArray()))); + } } // internal transaction transactionLogTrigger.setInternalTransactionList( getInternalTransactionList(programResult.getInternalTransactions())); } + + // process transactionInfo list, only enabled when ethCompatible is true + if (Objects.nonNull(transactionInfo)) { + transactionLogTrigger.setTransactionIndex(txIndex); + transactionLogTrigger.setCumulativeEnergyUsed(preCumulativeEnergyUsed + energyUsageTotal); + transactionLogTrigger.setPreCumulativeLogCount(preCumulativeLogCount); + transactionLogTrigger.setEnergyUnitPrice(energyUnitPrice); + + List logPojoList = new ArrayList<>(); + for (int index = 0; index < transactionInfo.getLogCount(); index++) { + TransactionInfo.Log log = transactionInfo.getLogList().get(index); + LogPojo logPojo = new LogPojo(); + + logPojo.setAddress((log.getAddress() != null) + ? Hex.toHexString(log.getAddress().toByteArray()) : ""); + logPojo.setBlockHash(blockHash); + logPojo.setBlockNumber(trxCapsule.getBlockNum()); + logPojo.setData(Hex.toHexString(log.getData().toByteArray())); + logPojo.setLogIndex(preCumulativeLogCount + index); + + List topics = new ArrayList<>(); + for (int i = 0; i < log.getTopicsCount(); i++) { + topics.add(Hex.toHexString(log.getTopics(i).toByteArray())); + } + logPojo.setTopicList(topics); + + logPojo.setTransactionHash(transactionHash); + logPojo.setTransactionIndex(txIndex); + + logPojoList.add(logPojo); + } + transactionLogTrigger.setLogList(logPojoList); + } } public void setLatestSolidifiedBlockNumber(long latestSolidifiedBlockNumber) { diff --git a/framework/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java b/framework/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java index 7e14f84c087..60a15f92e62 100644 --- a/framework/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java +++ b/framework/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java @@ -288,6 +288,11 @@ public Node getPublicHomeNode() { return homeNode; } + // just for test + public void clearNodeHandlerMap() { + nodeHandlerMap.clear(); + } + public void close() { try { nodeManagerTasksTimer.cancel(); diff --git a/framework/src/main/java/org/tron/common/overlay/server/Channel.java b/framework/src/main/java/org/tron/common/overlay/server/Channel.java index cc8b638f983..0d3358c3b61 100644 --- a/framework/src/main/java/org/tron/common/overlay/server/Channel.java +++ b/framework/src/main/java/org/tron/common/overlay/server/Channel.java @@ -10,6 +10,8 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.TimeUnit; + +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -62,6 +64,9 @@ public class Channel { private volatile boolean isDisconnect; + @Getter + private volatile long disconnectTime; + private boolean isTrustPeer; private boolean isFastForwardPeer; @@ -124,6 +129,7 @@ public void initNode(byte[] nodeId, int remotePort) { public void disconnect(ReasonCode reason) { this.isDisconnect = true; + this.disconnectTime = System.currentTimeMillis(); channelManager.processDisconnect(this, reason); DisconnectMessage msg = new DisconnectMessage(reason); logger.info("Send to {} online-time {}s, {}", @@ -154,6 +160,7 @@ public void processException(Throwable throwable) { public void close() { this.isDisconnect = true; + this.disconnectTime = System.currentTimeMillis(); p2pHandler.close(); msgQueue.close(); ctx.close(); diff --git a/framework/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java b/framework/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java index d865014fcd7..0858a383304 100644 --- a/framework/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java +++ b/framework/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java @@ -123,6 +123,7 @@ protected void sendHelloMsg(ChannelHandlerContext ctx, long time) { chainBaseManager.getGenesisBlockId(), chainBaseManager.getSolidBlockId(), chainBaseManager.getHeadBlockId()); fastForward.fillHelloMessage(message, channel); + ((PeerConnection) channel).setHelloMessageSend(message); ctx.writeAndFlush(message.getSendData()); channel.getNodeStatistics().messageStatistics.addTcpOutMessage(message); MetricsUtil.meterMark(MetricsKey.NET_TCP_OUT_TRAFFIC, @@ -174,7 +175,7 @@ private void handleHelloMsg(ChannelHandlerContext ctx, HelloMessage msg) { return; } - ((PeerConnection) channel).setHelloMessage(msg); + ((PeerConnection) channel).setHelloMessageReceive(msg); channel.getNodeStatistics().messageStatistics.addTcpInMessage(msg); diff --git a/framework/src/main/java/org/tron/common/overlay/server/SyncPool.java b/framework/src/main/java/org/tron/common/overlay/server/SyncPool.java index 311181c8efa..808481a1983 100644 --- a/framework/src/main/java/org/tron/common/overlay/server/SyncPool.java +++ b/framework/src/main/java/org/tron/common/overlay/server/SyncPool.java @@ -59,6 +59,8 @@ public class SyncPool { private PeerClient peerClient; + private int disconnectTimeout = 60_000; + public void init() { channelManager = ctx.getBean(ChannelManager.class); @@ -67,6 +69,7 @@ public void init() { poolLoopExecutor.scheduleWithFixedDelay(() -> { try { + check(); fillUp(); } catch (Throwable t) { logger.error("Exception in sync worker", t); @@ -82,6 +85,17 @@ public void init() { }, 30, 10, TimeUnit.SECONDS); } + private void check() { + for (PeerConnection peer : new ArrayList<>(activePeers)) { + long now = System.currentTimeMillis(); + long disconnectTime = peer.getDisconnectTime(); + if (disconnectTime != 0 && now - disconnectTime > disconnectTimeout) { + logger.warn("Notify disconnect peer {}.", peer.getInetAddress()); + channelManager.notifyDisconnect(peer); + } + } + } + private void fillUp() { List connectNodes = new ArrayList<>(); Set addressInUse = new HashSet<>(); @@ -125,11 +139,11 @@ synchronized void logActivePeers() { public List getActivePeers() { List peers = Lists.newArrayList(); - activePeers.forEach(peer -> { + for (PeerConnection peer : new ArrayList<>(activePeers)) { if (!peer.isDisconnect()) { peers.add(peer); } - }); + } return peers; } diff --git a/framework/src/main/java/org/tron/common/runtime/RuntimeImpl.java b/framework/src/main/java/org/tron/common/runtime/RuntimeImpl.java index 041d4a5bc7f..4ba53c7dc92 100644 --- a/framework/src/main/java/org/tron/common/runtime/RuntimeImpl.java +++ b/framework/src/main/java/org/tron/common/runtime/RuntimeImpl.java @@ -131,6 +131,10 @@ private void setResultCode(ProgramResult result) { result.setResultCode(contractResult.TRANSFER_FAILED); return; } + if (exception instanceof Program.InvalidCodeException) { + result.setResultCode(contractResult.INVALID_CODE); + return; + } result.setResultCode(contractResult.UNKNOWN); } diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 2d6a2febd93..ce61cdb915e 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -26,6 +26,7 @@ import static org.tron.core.config.Parameter.DatabaseConstants.EXCHANGE_COUNT_LIMIT_MAX; import static org.tron.core.config.Parameter.DatabaseConstants.MARKET_COUNT_LIMIT_MAX; import static org.tron.core.config.Parameter.DatabaseConstants.PROPOSAL_COUNT_LIMIT_MAX; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.parseEnergyFee; import com.google.common.collect.ContiguousSet; import com.google.common.collect.DiscreteDomain; @@ -101,9 +102,9 @@ import org.tron.common.crypto.SignUtils; import org.tron.common.overlay.discover.node.NodeHandler; import org.tron.common.overlay.discover.node.NodeManager; -import org.tron.common.overlay.message.Message; import org.tron.common.parameter.CommonParameter; import org.tron.common.runtime.ProgramResult; +import org.tron.common.runtime.vm.LogInfo; import org.tron.common.utils.ByteArray; import org.tron.common.utils.ByteUtil; import org.tron.common.utils.DecodeUtil; @@ -146,12 +147,14 @@ import org.tron.core.capsule.TransactionRetCapsule; import org.tron.core.capsule.WitnessCapsule; import org.tron.core.capsule.utils.MarketUtils; +import org.tron.core.capsule.utils.TransactionUtil; import org.tron.core.config.args.Args; import org.tron.core.db.BandwidthProcessor; import org.tron.core.db.BlockIndexStore; import org.tron.core.db.EnergyProcessor; import org.tron.core.db.Manager; import org.tron.core.db.TransactionContext; +import org.tron.core.db2.core.Chainbase; import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.BadItemException; import org.tron.core.exception.ContractExeException; @@ -159,6 +162,7 @@ import org.tron.core.exception.DupTransactionException; import org.tron.core.exception.HeaderNotFound; import org.tron.core.exception.ItemNotFoundException; +import org.tron.core.exception.JsonRpcInvalidParamsException; import org.tron.core.exception.NonUniqueObjectException; import org.tron.core.exception.PermissionException; import org.tron.core.exception.SignatureFormatException; @@ -181,7 +185,6 @@ import org.tron.core.store.MarketPairPriceToOrderStore; import org.tron.core.store.MarketPairToPriceStore; import org.tron.core.store.StoreFactory; -import org.tron.core.utils.TransactionUtil; import org.tron.core.zen.ShieldedTRC20ParametersBuilder; import org.tron.core.zen.ShieldedTRC20ParametersBuilder.ShieldedTRC20ParametersType; import org.tron.core.zen.ZenTransactionBuilder; @@ -246,6 +249,7 @@ public class Wallet { private static final byte[] SHIELDED_TRC20_LOG_TOPICS_BURN_TOKEN = Hash.sha3(ByteArray .fromString("TokenBurn(address,uint256,bytes32[3])")); private static final String BROADCAST_TRANS_FAILED = "Broadcast transaction {} failed, {}."; + @Getter private final SignInterface cryptoEngine; @Autowired @@ -263,11 +267,9 @@ public class Wallet { @Autowired private NodeManager nodeManager; private int minEffectiveConnection = Args.getInstance().getMinEffectiveConnection(); + private boolean trxCacheEnable = Args.getInstance().isTrxCacheEnable(); public static final String CONTRACT_VALIDATE_EXCEPTION = "ContractValidateException: {}"; - public static final String CONTRACT_VALIDATE_ERROR = "contract validate error : "; - - @Autowired - private TransactionUtil transactionUtil; + public static final String CONTRACT_VALIDATE_ERROR = "Contract validate error : "; /** * Creates a new Wallet with a random ECKey. @@ -478,14 +480,14 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { GrpcAPI.Return.Builder builder = GrpcAPI.Return.newBuilder(); TransactionCapsule trx = new TransactionCapsule(signedTransaction); trx.setTime(System.currentTimeMillis()); + Sha256Hash txID = trx.getTransactionId(); try { - Message message = new TransactionMessage(signedTransaction.toByteArray()); + TransactionMessage message = new TransactionMessage(signedTransaction.toByteArray()); if (minEffectiveConnection != 0) { if (tronNetDelegate.getActivePeer().isEmpty()) { - logger - .warn("Broadcast transaction {} has failed, no connection.", trx.getTransactionId()); + logger.warn("Broadcast transaction {} has failed, no connection.", txID); return builder.setResult(false).setCode(response_code.NO_CONNECTION) - .setMessage(ByteString.copyFromUtf8("no connection")) + .setMessage(ByteString.copyFromUtf8("No connection.")) .build(); } @@ -494,9 +496,9 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { .count(); if (count < minEffectiveConnection) { - String info = "effective connection:" + count + " lt minEffectiveConnection:" + String info = "Effective connection:" + count + " lt minEffectiveConnection:" + minEffectiveConnection; - logger.warn("Broadcast transaction {} has failed, {}.", trx.getTransactionId(), info); + logger.warn("Broadcast transaction {} has failed. {}.", txID, info); return builder.setResult(false).setCode(response_code.NOT_ENOUGH_EFFECTIVE_CONNECTION) .setMessage(ByteString.copyFromUtf8(info)) .build(); @@ -504,69 +506,77 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { } if (dbManager.isTooManyPending()) { - logger - .warn("Broadcast transaction {} has failed, too many pending.", trx.getTransactionId()); - return builder.setResult(false).setCode(response_code.SERVER_BUSY).build(); + logger.warn("Broadcast transaction {} has failed, too many pending.", txID); + return builder.setResult(false).setCode(response_code.SERVER_BUSY) + .setMessage(ByteString.copyFromUtf8("Server busy.")).build(); } - if (dbManager.getTransactionIdCache().getIfPresent(trx.getTransactionId()) != null) { - logger.warn("Broadcast transaction {} has failed, it already exists.", - trx.getTransactionId()); - return builder.setResult(false).setCode(response_code.DUP_TRANSACTION_ERROR).build(); - } else { - dbManager.getTransactionIdCache().put(trx.getTransactionId(), true); + if (trxCacheEnable) { + if (dbManager.getTransactionIdCache().getIfPresent(txID) != null) { + logger.warn("Broadcast transaction {} has failed, it already exists.", txID); + return builder.setResult(false).setCode(response_code.DUP_TRANSACTION_ERROR) + .setMessage(ByteString.copyFromUtf8("Transaction already exists.")).build(); + } else { + dbManager.getTransactionIdCache().put(txID, true); + } } + if (chainBaseManager.getDynamicPropertiesStore().supportVM()) { trx.resetResult(); } dbManager.pushTransaction(trx); - tronNetService.broadcast(message); - logger.info("Broadcast transaction {} successfully.", trx.getTransactionId()); - return builder.setResult(true).setCode(response_code.SUCCESS).build(); + int num = tronNetService.fastBroadcastTransaction(message); + if (num == 0) { + return builder.setResult(false).setCode(response_code.NOT_ENOUGH_EFFECTIVE_CONNECTION) + .setMessage(ByteString.copyFromUtf8("P2P broadcast failed.")).build(); + } else { + logger.info("Broadcast transaction {} to {} peers successfully.", txID, num); + return builder.setResult(true).setCode(response_code.SUCCESS).build(); + } } catch (ValidateSignatureException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.SIGERROR) - .setMessage(ByteString.copyFromUtf8("validate signature error " + e.getMessage())) + .setMessage(ByteString.copyFromUtf8("Validate signature error: " + e.getMessage())) .build(); } catch (ContractValidateException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.CONTRACT_VALIDATE_ERROR) .setMessage(ByteString.copyFromUtf8(CONTRACT_VALIDATE_ERROR + e.getMessage())) .build(); } catch (ContractExeException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.CONTRACT_EXE_ERROR) - .setMessage(ByteString.copyFromUtf8("contract execute error : " + e.getMessage())) + .setMessage(ByteString.copyFromUtf8("Contract execute error : " + e.getMessage())) .build(); } catch (AccountResourceInsufficientException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.BANDWITH_ERROR) - .setMessage(ByteString.copyFromUtf8("AccountResourceInsufficient error")) + .setMessage(ByteString.copyFromUtf8("Account resource insufficient error.")) .build(); } catch (DupTransactionException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.DUP_TRANSACTION_ERROR) - .setMessage(ByteString.copyFromUtf8("dup transaction")) + .setMessage(ByteString.copyFromUtf8("Dup transaction.")) .build(); } catch (TaposException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.TAPOS_ERROR) - .setMessage(ByteString.copyFromUtf8("Tapos check error")) + .setMessage(ByteString.copyFromUtf8("Tapos check error.")) .build(); } catch (TooBigTransactionException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.TOO_BIG_TRANSACTION_ERROR) - .setMessage(ByteString.copyFromUtf8("transaction size is too big")) + .setMessage(ByteString.copyFromUtf8("Transaction size is too big.")) .build(); } catch (TransactionExpirationException e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.TRANSACTION_EXPIRATION_ERROR) - .setMessage(ByteString.copyFromUtf8("transaction expired")) + .setMessage(ByteString.copyFromUtf8("Transaction expired")) .build(); } catch (Exception e) { - logger.error(BROADCAST_TRANS_FAILED, trx.getTransactionId(), e.getMessage()); + logger.error(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.OTHER_ERROR) - .setMessage(ByteString.copyFromUtf8("other error : " + e.getMessage())) + .setMessage(ByteString.copyFromUtf8("Error: " + e.getMessage())) .build(); } } @@ -652,6 +662,15 @@ public Block getBlockByNum(long blockNum) { } } + public BlockCapsule getBlockCapsuleByNum(long blockNum) { + try { + return chainBaseManager.getBlockByNum(blockNum); + } catch (StoreException e) { + logger.info(e.getMessage()); + return null; + } + } + public long getTransactionCountByBlockNum(long blockNum) { long count = 0; @@ -665,6 +684,35 @@ public long getTransactionCountByBlockNum(long blockNum) { return count; } + public Block getByJsonBlockId(String id) throws JsonRpcInvalidParamsException { + if ("earliest".equalsIgnoreCase(id)) { + return getBlockByNum(0); + } else if ("latest".equalsIgnoreCase(id)) { + return getNowBlock(); + } else if ("pending".equalsIgnoreCase(id)) { + throw new JsonRpcInvalidParamsException("TAG pending not supported"); + } else { + long blockNumber; + try { + blockNumber = ByteArray.hexToBigInteger(id).longValue(); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid block number"); + } + + return getBlockByNum(blockNumber); + } + } + + public List getTransactionsByJsonBlockId(String id) + throws JsonRpcInvalidParamsException { + if ("pending".equalsIgnoreCase(id)) { + throw new JsonRpcInvalidParamsException("TAG pending not supported"); + } else { + Block block = getByJsonBlockId(id); + return block != null ? block.getTransactionsList() : null; + } + } + public WitnessList getWitnessList() { WitnessList.Builder builder = WitnessList.newBuilder(); List witnessCapsuleList = chainBaseManager.getWitnessStore().getAllWitnesses(); @@ -1007,6 +1055,16 @@ public Protocol.ChainParameters getChainParameters() { .setValue(dbManager.getDynamicPropertiesStore().getAllowTvmVote()) .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getAllowTvmLondon") + .setValue(dbManager.getDynamicPropertiesStore().getAllowTvmLondon()) + .build()); + + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getAllowTvmCompatibleEvm") + .setValue(dbManager.getDynamicPropertiesStore().getAllowTvmCompatibleEvm()) + .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() .setKey("getAllowAccountAssetOptimization") .setValue(dbManager.getDynamicPropertiesStore().getAllowAccountAssetOptimization()) @@ -1328,6 +1386,21 @@ public Transaction getTransactionById(ByteString transactionId) { return null; } + public TransactionCapsule getTransactionCapsuleById(ByteString transactionId) { + if (Objects.isNull(transactionId)) { + return null; + } + TransactionCapsule transactionCapsule; + try { + transactionCapsule = chainBaseManager.getTransactionStore() + .get(transactionId.toByteArray()); + } catch (StoreException e) { + return null; + } + + return transactionCapsule; + } + public TransactionInfo getTransactionInfoById(ByteString transactionId) { if (Objects.isNull(transactionId)) { return null; @@ -1335,7 +1408,7 @@ public TransactionInfo getTransactionInfoById(ByteString transactionId) { TransactionInfoCapsule transactionInfoCapsule; try { transactionInfoCapsule = chainBaseManager.getTransactionRetStore() - .getTransactionInfo(transactionId.toByteArray()); + .getTransactionInfo(transactionId.toByteArray()); } catch (StoreException e) { return null; } @@ -1344,7 +1417,7 @@ public TransactionInfo getTransactionInfoById(ByteString transactionId) { } try { transactionInfoCapsule = chainBaseManager.getTransactionHistoryStore() - .get(transactionId.toByteArray()); + .get(transactionId.toByteArray()); } catch (BadItemException e) { return null; } @@ -2508,33 +2581,36 @@ public Transaction triggerContract(TriggerSmartContract } } - public Transaction triggerConstantContract(TriggerSmartContract - triggerSmartContract, - TransactionCapsule trxCap, Builder builder, - Return.Builder retBuilder) + public Transaction triggerConstantContract(TriggerSmartContract triggerSmartContract, + TransactionCapsule trxCap, Builder builder, Return.Builder retBuilder) throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException { - ContractStore contractStore = chainBaseManager.getContractStore(); - byte[] contractAddress = triggerSmartContract.getContractAddress() - .toByteArray(); - byte[] isContractExist = contractStore - .findContractByHash(contractAddress); - - if (ArrayUtils.isEmpty(isContractExist)) { - throw new ContractValidateException( - "No contract or not a smart contract"); - } - - if (!Args.getInstance().isSupportConstant()) { - throw new ContractValidateException("this node does not support constant"); + if (triggerSmartContract.getContractAddress().isEmpty()) { // deploy contract + CreateSmartContract.Builder deployBuilder = CreateSmartContract.newBuilder(); + deployBuilder.setOwnerAddress(triggerSmartContract.getOwnerAddress()); + deployBuilder.setNewContract(SmartContract.newBuilder() + .setOriginAddress(triggerSmartContract.getOwnerAddress()) + .setBytecode(triggerSmartContract.getData()) + .setCallValue(triggerSmartContract.getCallValue()) + .setConsumeUserResourcePercent(100) + .setOriginEnergyLimit(1) + .build() + ); + deployBuilder.setCallTokenValue(triggerSmartContract.getCallTokenValue()); + deployBuilder.setTokenId(triggerSmartContract.getTokenId()); + trxCap = createTransactionCapsule(deployBuilder.build(), ContractType.CreateSmartContract); + } else { // call contract + ContractStore contractStore = chainBaseManager.getContractStore(); + byte[] contractAddress = triggerSmartContract.getContractAddress().toByteArray(); + if (contractStore.get(contractAddress) == null) { + throw new ContractValidateException("Smart contract is not exist."); + } } - return callConstantContract(trxCap, builder, retBuilder); } - public Transaction callConstantContract(TransactionCapsule trxCap, Builder - builder, - Return.Builder retBuilder) + public Transaction callConstantContract(TransactionCapsule trxCap, + Builder builder, Return.Builder retBuilder) throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException { if (!Args.getInstance().isSupportConstant()) { @@ -2551,8 +2627,7 @@ public Transaction callConstantContract(TransactionCapsule trxCap, Builder } TransactionContext context = new TransactionContext(new BlockCapsule(headBlock), trxCap, - StoreFactory.getInstance(), true, - false); + StoreFactory.getInstance(), true, false); VMActuator vmActuator = new VMActuator(true); vmActuator.validate(context); @@ -2568,6 +2643,10 @@ public Transaction callConstantContract(TransactionCapsule trxCap, Builder TransactionResultCapsule ret = new TransactionResultCapsule(); builder.setEnergyUsed(result.getEnergyUsed()); builder.addConstantResult(ByteString.copyFrom(result.getHReturn())); + result.getLogInfoList().forEach(logInfo -> + builder.addLogs(LogInfo.buildLog(logInfo))); + result.getInternalTransactions().forEach(it -> + builder.addInternalTransactions(TransactionUtil.buildInternalTransaction(it))); ret.setStatus(0, code.SUCESS); if (StringUtils.isNoneEmpty(result.getRuntimeError())) { ret.setStatus(0, code.FAILED); @@ -2607,11 +2686,11 @@ public SmartContract getContract(GrpcAPI.BytesMessage bytesMessage) { } /** - * Add a wrapper for smart contract. - * Current additional information including runtime code for a smart contract. + * Add a wrapper for smart contract. Current additional information including runtime code for a + * smart contract. + * * @param bytesMessage the contract address message * @return contract info - * */ public SmartContractDataWrapper getContractInfo(GrpcAPI.BytesMessage bytesMessage) { byte[] address = bytesMessage.getValue().toByteArray(); @@ -3785,5 +3864,103 @@ public void checkAccountIdentifier(BalanceContract.AccountIdentifier accountIden throw new IllegalArgumentException("account_identifier address is null"); } } + + public long getEnergyFee() { + return chainBaseManager.getDynamicPropertiesStore().getEnergyFee(); + } + + // this function should be called after EnergyPriceHistoryLoader done + public long getEnergyFee(long timestamp) { + try { + String energyPriceHistory = + chainBaseManager.getDynamicPropertiesStore().getEnergyPriceHistory(); + long energyFee = parseEnergyFee(timestamp, energyPriceHistory); + + if (energyFee == -1) { + energyFee = getEnergyFee(); + } + + return energyFee; + } catch (Exception e) { + logger.error("getEnergyFee timestamp={} failed, error is {}", timestamp, e.getMessage()); + return getEnergyFee(); + } + } + + public String getEnergyPrices() { + try { + return chainBaseManager.getDynamicPropertiesStore().getEnergyPriceHistory(); + } catch (Exception e) { + logger.error("getEnergyPrices failed, error is {}", e.getMessage()); + } + + return null; + } + + public String getCoinbase() { + if (!CommonParameter.getInstance().isWitness()) { + return null; + } + + // get local witnesses + List localPrivateKeys = Args.getLocalWitnesses().getPrivateKeys(); + List localWitnessAddresses = new ArrayList<>(); + for (String privateKey : localPrivateKeys) { + localWitnessAddresses.add(Hex.toHexString(SignUtils + .fromPrivate(ByteArray.fromHexString(privateKey), + CommonParameter.getInstance().isECKeyCryptoEngine()).getAddress())); + } + + // get all witnesses + List witnesses = consensusDelegate.getAllWitnesses(); + List witnessAddresses = new ArrayList<>(); + for (WitnessCapsule witnessCapsule : witnesses) { + witnessAddresses.add(Hex.toHexString(witnessCapsule.getAddress().toByteArray())); + } + + // check if witnesses contains local witness + for (String localWitnessAddress : localWitnessAddresses) { + if (witnessAddresses.contains(localWitnessAddress)) { + return "0x" + localWitnessAddress; + } + } + + return null; + } + + public boolean isMining() { + if (!CommonParameter.getInstance().isWitness()) { + return false; + } + + // get local witnesses + List localPrivateKeys = Args.getLocalWitnesses().getPrivateKeys(); + List localWitnessAddresses = new ArrayList<>(); + for (String privateKey : localPrivateKeys) { + localWitnessAddresses.add(Hex.toHexString(SignUtils + .fromPrivate(ByteArray.fromHexString(privateKey), + CommonParameter.getInstance().isECKeyCryptoEngine()).getAddress())); + } + + // get active witnesses + List activeWitnesses = consensusDelegate.getActiveWitnesses(); + List activeWitnessAddresses = new ArrayList<>(); + for (ByteString activeWitness : activeWitnesses) { + activeWitnessAddresses.add(Hex.toHexString(activeWitness.toByteArray())); + } + + // check if active witnesses contains local witness + for (String localWitnessAddress : localWitnessAddresses) { + if (activeWitnessAddresses.contains(localWitnessAddress)) { + return true; + } + } + + return false; + } + + public Chainbase.Cursor getCursor() { + return chainBaseManager.getBlockStore().getRevokingDB().getCursor(); + } } diff --git a/framework/src/main/java/org/tron/core/config/TronLogShutdownHook.java b/framework/src/main/java/org/tron/core/config/TronLogShutdownHook.java new file mode 100644 index 00000000000..880aa7e3090 --- /dev/null +++ b/framework/src/main/java/org/tron/core/config/TronLogShutdownHook.java @@ -0,0 +1,43 @@ +package org.tron.core.config; + +import ch.qos.logback.core.hook.ShutdownHookBase; +import ch.qos.logback.core.util.Duration; +import org.tron.program.FullNode; + +/** + * @author kiven + * tron log shutdown hock + */ +public class TronLogShutdownHook extends ShutdownHookBase { + + /** + * The default shutdown delay check unit. + */ + private static final Duration CHECK_SHUTDOWN_DELAY = Duration.buildByMilliseconds(100); + + /** + * The check times before shutdown. default is 50 + */ + private Integer check_times = 50; + + public TronLogShutdownHook() { + } + + @Override + public void run() { + try { + for (int i = 0; i < check_times; i++) { + if (FullNode.shutDownSign) { + break; + } + addInfo("Sleeping for " + CHECK_SHUTDOWN_DELAY); + Thread.sleep(CHECK_SHUTDOWN_DELAY.getMilliseconds()); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + addInfo("TronLogShutdownHook run error :" + e.getMessage()); + } + super.stop(); + } + +} diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index d159f1ad243..d8ae045f908 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -132,6 +132,9 @@ public static void clearParam() { PARAMETER.fullNodeHttpPort = 0; PARAMETER.solidityHttpPort = 0; PARAMETER.pBFTHttpPort = 0; + PARAMETER.jsonRpcHttpFullNodePort = 0; + PARAMETER.jsonRpcHttpSolidityPort = 0; + PARAMETER.jsonRpcHttpPBFTPort = 0; PARAMETER.maintenanceTimeInterval = 0; PARAMETER.proposalExpireTime = 0; PARAMETER.checkFrozenTime = 1; @@ -173,6 +176,9 @@ public static void clearParam() { PARAMETER.changedDelegation = 0; PARAMETER.fullNodeHttpEnable = true; PARAMETER.solidityNodeHttpEnable = true; + PARAMETER.jsonRpcHttpFullNodeEnable = false; + PARAMETER.jsonRpcHttpSolidityNodeEnable = false; + PARAMETER.jsonRpcHttpPBFTNodeEnable = false; PARAMETER.nodeMetricsEnable = false; PARAMETER.metricsStorageEnable = false; PARAMETER.agreeNodeCount = MAX_ACTIVE_WITNESS_NUM * 2 / 3 + 1; @@ -185,10 +191,13 @@ public static void clearParam() { PARAMETER.allowTvmIstanbul = 0; PARAMETER.allowTvmFreeze = 0; PARAMETER.allowTvmVote = 0; + PARAMETER.allowTvmLondon = 0; + PARAMETER.allowTvmCompatibleEvm = 0; PARAMETER.historyBalanceLookup = false; PARAMETER.openPrintLog = true; PARAMETER.openTransactionSort = false; PARAMETER.allowAccountAssetOptimization = 0; + PARAMETER.disabledApiList = Collections.emptyList(); } /** @@ -282,6 +291,11 @@ public static void setParam(final String[] args, final String confFileName) { PARAMETER.supportConstant = config.getBoolean(Constant.VM_SUPPORT_CONSTANT); } + if (config.hasPath(Constant.VM_MAX_ENERGY_LIMIT_FOR_CONSTANT)) { + long configLimit = config.getLong(Constant.VM_MAX_ENERGY_LIMIT_FOR_CONSTANT); + PARAMETER.maxEnergyLimitForConstant = max(3_000_000L, configLimit); + } + if (config.hasPath(Constant.NODE_HTTP_FULLNODE_ENABLE)) { PARAMETER.fullNodeHttpEnable = config.getBoolean(Constant.NODE_HTTP_FULLNODE_ENABLE); } @@ -290,6 +304,21 @@ public static void setParam(final String[] args, final String confFileName) { PARAMETER.solidityNodeHttpEnable = config.getBoolean(Constant.NODE_HTTP_SOLIDITY_ENABLE); } + if (config.hasPath(Constant.NODE_JSONRPC_HTTP_FULLNODE_ENABLE)) { + PARAMETER.jsonRpcHttpFullNodeEnable = + config.getBoolean(Constant.NODE_JSONRPC_HTTP_FULLNODE_ENABLE); + } + + if (config.hasPath(Constant.NODE_JSONRPC_HTTP_SOLIDITY_ENABLE)) { + PARAMETER.jsonRpcHttpSolidityNodeEnable = + config.getBoolean(Constant.NODE_JSONRPC_HTTP_SOLIDITY_ENABLE); + } + + if (config.hasPath(Constant.NODE_JSONRPC_HTTP_PBFT_ENABLE)) { + PARAMETER.jsonRpcHttpPBFTNodeEnable = + config.getBoolean(Constant.NODE_JSONRPC_HTTP_PBFT_ENABLE); + } + if (config.hasPath(Constant.VM_MIN_TIME_RATIO)) { PARAMETER.minTimeRatio = config.getDouble(Constant.VM_MIN_TIME_RATIO); } @@ -451,6 +480,18 @@ public static void setParam(final String[] args, final String confFileName) { config.hasPath(Constant.NODE_HTTP_PBFT_PORT) ? config.getInt(Constant.NODE_HTTP_PBFT_PORT) : 8092; + PARAMETER.jsonRpcHttpFullNodePort = + config.hasPath(Constant.NODE_JSONRPC_HTTP_FULLNODE_PORT) + ? config.getInt(Constant.NODE_JSONRPC_HTTP_FULLNODE_PORT) : 8545; + + PARAMETER.jsonRpcHttpSolidityPort = + config.hasPath(Constant.NODE_JSONRPC_HTTP_SOLIDITY_PORT) + ? config.getInt(Constant.NODE_JSONRPC_HTTP_SOLIDITY_PORT) : 8555; + + PARAMETER.jsonRpcHttpPBFTPort = + config.hasPath(Constant.NODE_JSONRPC_HTTP_PBFT_PORT) + ? config.getInt(Constant.NODE_JSONRPC_HTTP_PBFT_PORT) : 8565; + PARAMETER.rpcThreadNum = config.hasPath(Constant.NODE_RPC_THREAD) ? config.getInt(Constant.NODE_RPC_THREAD) : (Runtime.getRuntime().availableProcessors() + 1) / 2; @@ -610,6 +651,9 @@ public static void setParam(final String[] args, final String confFileName) { PARAMETER.minEffectiveConnection = config.hasPath(Constant.NODE_RPC_MIN_EFFECTIVE_CONNECTION) ? config.getInt(Constant.NODE_RPC_MIN_EFFECTIVE_CONNECTION) : 1; + PARAMETER.trxCacheEnable = config.hasPath(Constant.NODE_RPC_TRX_CACHE_ENABLE) + && config.getBoolean(Constant.NODE_RPC_TRX_CACHE_ENABLE); + PARAMETER.blockNumForEnergyLimit = config.hasPath(Constant.ENERGY_LIMIT_BLOCK_NUM) ? config.getInt(Constant.ENERGY_LIMIT_BLOCK_NUM) : 4727890L; @@ -717,6 +761,14 @@ public static void setParam(final String[] args, final String confFileName) { config.hasPath(Constant.COMMITTEE_ALLOW_TVM_VOTE) ? config .getInt(Constant.COMMITTEE_ALLOW_TVM_VOTE) : 0; + PARAMETER.allowTvmLondon = + config.hasPath(Constant.COMMITTEE_ALLOW_TVM_LONDON) ? config + .getInt(Constant.COMMITTEE_ALLOW_TVM_LONDON) : 0; + + PARAMETER.allowTvmCompatibleEvm = + config.hasPath(Constant.COMMITTEE_ALLOW_TVM_COMPATIBLE_EVM) ? config + .getInt(Constant.COMMITTEE_ALLOW_TVM_COMPATIBLE_EVM) : 0; + initBackupProperty(config); if (Constant.ROCKSDB.equals(CommonParameter .getInstance().getStorage().getDbEngine().toUpperCase())) { @@ -762,6 +814,12 @@ public static void setParam(final String[] args, final String confFileName) { .hasPath(Constant.ALLOW_ACCOUNT_ASSET_OPTIMIZATION) ? config .getInt(Constant.ALLOW_ACCOUNT_ASSET_OPTIMIZATION) : 0; + PARAMETER.disabledApiList = + config.hasPath(Constant.NODE_DISABLED_API_LIST) + ? config.getStringList(Constant.NODE_DISABLED_API_LIST) + .stream().map(String::toLowerCase).collect(Collectors.toList()) + : Collections.emptyList(); + logConfig(); } @@ -906,6 +964,21 @@ private static TriggerConfig createTriggerConfig(ConfigObject triggerObject) { String topic = triggerObject.get("topic").unwrapped().toString(); triggerConfig.setTopic(topic); + if (triggerObject.containsKey("redundancy")) { + String redundancy = triggerObject.get("redundancy").unwrapped().toString(); + triggerConfig.setRedundancy("true".equalsIgnoreCase(redundancy)); + } + + if (triggerObject.containsKey("ethCompatible")) { + String ethCompatible = triggerObject.get("ethCompatible").unwrapped().toString(); + triggerConfig.setEthCompatible("true".equalsIgnoreCase(ethCompatible)); + } + + if (triggerObject.containsKey("solidified")) { + String solidified = triggerObject.get("solidified").unwrapped().toString(); + triggerConfig.setSolidified("true".equalsIgnoreCase(solidified)); + } + return triggerConfig; } diff --git a/framework/src/main/java/org/tron/core/consensus/BlockHandleImpl.java b/framework/src/main/java/org/tron/core/consensus/BlockHandleImpl.java index aafafd845d5..53e029cbab6 100644 --- a/framework/src/main/java/org/tron/core/consensus/BlockHandleImpl.java +++ b/framework/src/main/java/org/tron/core/consensus/BlockHandleImpl.java @@ -51,8 +51,8 @@ public BlockCapsule produce(Miner miner, long blockTime, long timeout) { consensus.receiveBlock(blockCapsule); BlockMessage blockMessage = new BlockMessage(blockCapsule); tronNetService.fastForward(blockMessage); - manager.pushBlock(blockCapsule); tronNetService.broadcast(blockMessage); + manager.pushBlock(blockCapsule); } catch (Exception e) { logger.error("Handle block {} failed.", blockCapsule.getBlockId().getString(), e); return null; diff --git a/framework/src/main/java/org/tron/core/consensus/ProposalController.java b/framework/src/main/java/org/tron/core/consensus/ProposalController.java index 88a1b3d3187..9370291da7f 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalController.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalController.java @@ -40,6 +40,7 @@ public void processProposals() { .get(ProposalCapsule.calculateDbKey(proposalNum)); } catch (Exception ex) { logger.error("", ex); + proposalNum--; continue; } diff --git a/framework/src/main/java/org/tron/core/consensus/ProposalService.java b/framework/src/main/java/org/tron/core/consensus/ProposalService.java index 4f40473a3c0..ad41472eacd 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java @@ -75,6 +75,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) } case ENERGY_FEE: { manager.getDynamicPropertiesStore().saveEnergyFee(entry.getValue()); + // update energy price history + manager.getDynamicPropertiesStore().saveEnergyPriceHistory( + manager.getDynamicPropertiesStore().getEnergyPriceHistory() + + "," + proposalCapsule.getExpirationTime() + ":" + entry.getValue()); break; } case EXCHANGE_CREATE_FEE: { @@ -247,6 +251,14 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) manager.getDynamicPropertiesStore().saveNewRewardAlgorithmEffectiveCycle(); break; } + case ALLOW_TVM_LONDON: { + manager.getDynamicPropertiesStore().saveAllowTvmLondon(entry.getValue()); + break; + } + case ALLOW_TVM_COMPATIBLE_EVM: { + manager.getDynamicPropertiesStore().saveAllowTvmCompatibleEvm(entry.getValue()); + break; + } case FREE_NET_LIMIT: { manager.getDynamicPropertiesStore().saveFreeNetLimit(entry.getValue()); break; 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 41397818a63..3baf5568741 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -7,12 +7,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.common.primitives.Longs; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Arrays; @@ -36,10 +31,8 @@ import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import java.util.stream.LongStream; import javax.annotation.PostConstruct; import lombok.Getter; import lombok.Setter; @@ -48,6 +41,7 @@ import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.tron.api.GrpcAPI.TransactionInfoList; import org.tron.common.args.GenesisBlock; import org.tron.common.logsfilter.EventPluginLoader; import org.tron.common.logsfilter.FilterQuery; @@ -72,6 +66,7 @@ import org.tron.consensus.base.Param.Miner; import org.tron.core.ChainBaseManager; import org.tron.core.Constant; +import org.tron.core.Wallet; import org.tron.core.actuator.ActuatorCreator; import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.BlockBalanceTraceCapsule; @@ -90,6 +85,7 @@ import org.tron.core.db.accountstate.TrieService; import org.tron.core.db.accountstate.callback.AccountStateCallBack; import org.tron.core.db.api.AssetUpdateHelper; +import org.tron.core.db.api.EnergyPriceHistoryLoader; import org.tron.core.db.api.MoveAbiHelper; import org.tron.core.db2.ISession; import org.tron.core.db2.core.Chainbase; @@ -145,6 +141,7 @@ import org.tron.core.store.WitnessStore; import org.tron.core.utils.TransactionRegister; import org.tron.protos.Protocol.AccountType; +import org.tron.protos.Protocol.Permission; import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract; import org.tron.protos.Protocol.TransactionInfo; @@ -195,7 +192,8 @@ public class Manager { private BlockingQueue pushTransactionQueue = new LinkedBlockingQueue<>(); @Getter private Cache transactionIdCache = CacheBuilder - .newBuilder().maximumSize(TX_ID_CACHE_SIZE).recordStats().build(); + .newBuilder().maximumSize(TX_ID_CACHE_SIZE) + .expireAfterWrite(1, TimeUnit.HOURS).recordStats().build(); @Autowired private AccountStateCallBack accountStateCallBack; @Autowired @@ -275,6 +273,27 @@ public boolean needToMoveAbi() { return getDynamicPropertiesStore().getAbiMoveDone() == 0L; } + public boolean needToLoadEnergyPriceHistory() { + return getDynamicPropertiesStore().getEnergyPriceHistoryDone() == 0L; + } + + public boolean needToSetBlackholePermission() { + return getDynamicPropertiesStore().getSetBlackholeAccountPermission() == 0L; + } + + private void resetBlackholeAccountPermission() { + AccountCapsule blackholeAccount = getAccountStore().getBlackhole(); + + byte[] zeroAddress = new byte[21]; + zeroAddress[0] = Wallet.getAddressPreFixByte(); + Permission owner = AccountCapsule + .createDefaultOwnerPermission(ByteString.copyFrom(zeroAddress)); + blackholeAccount.updatePermissions(owner, null, null); + getAccountStore().put(blackholeAccount.getAddress().toByteArray(), blackholeAccount); + + getDynamicPropertiesStore().saveSetBlackholePermission(1); + } + public DynamicPropertiesStore getDynamicPropertiesStore() { return chainBaseManager.getDynamicPropertiesStore(); } @@ -409,11 +428,19 @@ public void init() { new MoveAbiHelper(chainBaseManager).doWork(); } + if (needToLoadEnergyPriceHistory()) { + new EnergyPriceHistoryLoader(chainBaseManager).doWork(); + } + + if (needToSetBlackholePermission()) { + resetBlackholeAccountPermission(); + } //for test only chainBaseManager.getDynamicPropertiesStore().updateDynamicStoreByConfig(); - // initCacheTxs(); + long headNum = chainBaseManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(); + logger.info("current headNum is: {}", headNum); revokingStore.enable(); validateSignService = Executors .newFixedThreadPool(Args.getInstance().getValidateSignThreadNum()); @@ -555,62 +582,6 @@ private void initWitness() { }); } - public void initCacheTxs() { - logger.info("begin to init txs cache."); - int dbVersion = Args.getInstance().getStorage().getDbVersion(); - if (dbVersion != 2) { - return; - } - long start = System.currentTimeMillis(); - long headNum = chainBaseManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(); - logger.info("current headNum is: {}", headNum); - long recentBlockCount = chainBaseManager.getRecentBlockStore().size(); - ListeningExecutorService service = MoreExecutors - .listeningDecorator(Executors.newFixedThreadPool(50)); - List> futures = new ArrayList<>(); - AtomicLong blockCount = new AtomicLong(0); - AtomicLong emptyBlockCount = new AtomicLong(0); - LongStream.rangeClosed(headNum - recentBlockCount + 1, headNum).forEach( - blockNum -> futures.add(service.submit(() -> { - try { - blockCount.incrementAndGet(); - if (chainBaseManager.getBlockByNum(blockNum).getTransactions().isEmpty()) { - emptyBlockCount.incrementAndGet(); - // transactions is null, return - return; - } - chainBaseManager.getBlockByNum(blockNum).getTransactions().stream() - .map(tc -> tc.getTransactionId().getBytes()) - .map(bytes -> Maps.immutableEntry(bytes, Longs.toByteArray(blockNum))) - .forEach(e -> transactionCache - .put(e.getKey(), new BytesCapsule(e.getValue()))); - } catch (ItemNotFoundException e) { - if (!CommonParameter.getInstance().isLiteFullNode) { - logger.warn("block not found. num: {}", blockNum); - } - } catch (BadItemException e) { - throw new IllegalStateException("init txs cache error.", e); - } - }))); - - ListenableFuture future = Futures.allAsList(futures); - try { - future.get(); - service.shutdown(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - logger.info(e.getMessage()); - } - - logger.info("end to init txs cache. trx ids:{}, block count:{}, empty block count:{}, cost:{}", - transactionCache.size(), - blockCount.get(), - emptyBlockCount.get(), - System.currentTimeMillis() - start - ); - } - public AccountStore getAccountStore() { return chainBaseManager.getAccountStore(); } @@ -998,12 +969,6 @@ public synchronized void pushBlock(final BlockCapsule block) try (PendingManager pm = new PendingManager(this)) { if (!block.generatedByMyself) { - if (!block.validateSignature(chainBaseManager.getDynamicPropertiesStore(), - chainBaseManager.getAccountStore())) { - logger.warn("The signature is not validated."); - throw new BadBlockException("The signature is not validated"); - } - if (!block.calcMerkleRoot().equals(block.getMerkleRoot())) { logger.warn( "The merkle root doesn't match, Calc result is " @@ -1097,10 +1062,10 @@ public synchronized void pushBlock(final BlockCapsule block) applyBlock(newBlock, txs); tmpSession.commit(); - // if event subscribe is enabled, post solidity trigger to queue - postSolidityTrigger(getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); // if event subscribe is enabled, post block trigger to queue postBlockTrigger(newBlock); + // if event subscribe is enabled, post solidity trigger to queue + postSolidityTrigger(getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); } catch (Throwable throwable) { logger.error(throwable.getMessage(), throwable); khaosDb.removeBlk(block.getBlockId()); @@ -1249,7 +1214,12 @@ public TransactionInfo processTransaction(final TransactionCapsule trxCap, Block .buildTransactionInfoInstance(trxCap, blockCap, trace); // if event subscribe is enabled, post contract triggers to queue - postContractTrigger(trace, false); + // only trigger when process block + if (Objects.nonNull(blockCap) && !blockCap.isMerkleRootEmpty()) { + String blockHash = blockCap.getBlockId().toString(); + postContractTrigger(trace, false, blockHash); + } + Contract contract = trxCap.getInstance().getRawData().getContract(0); if (isMultiSignTransaction(trxCap.getInstance())) { ownerAddressSet.add(ByteArray.toHexString(TransactionCapsule.getOwner(contract))); @@ -1371,14 +1341,16 @@ public synchronized BlockCapsule generateBlock(Miner miner, long blockTime, long session.reset(); - logger.info("Generate block success, pendingCount: {}, rePushCount: {}, postponedCount: {}", + logger.info("Generate block {} success, pendingCount: {}, rePushCount: {}, postponedCount: {}", + blockCapsule.getNum(), pendingTransactions.size(), rePushTransactions.size(), postponedTrxCount); blockCapsule.setMerkleRoot(); blockCapsule.sign(miner.getPrivateKey()); - return blockCapsule; - + BlockCapsule capsule = new BlockCapsule(blockCapsule.getInstance()); + capsule.generatedByMyself = true; + return capsule; } private void filterOwnerAddress(TransactionCapsule transactionCapsule, Set result) { @@ -1561,6 +1533,9 @@ private void postSolidityLogContractTrigger(Long blockNum, Long lastSolidityNum) .getTransactionId()))) { triggerCapsule.setTriggerName(Trigger.SOLIDITYLOG_TRIGGER_NAME); EventPluginLoader.getInstance().postSolidityLogTrigger(triggerCapsule); + } else { + logger.error("postSolidityLogContractTrigger txId={} not contains transaction", + triggerCapsule.getTransactionId()); } } Args.getSolidityContractLogTriggerMap().remove(blockNum); @@ -1749,15 +1724,6 @@ private void startEventSubscribing() { } private void postSolidityTrigger(final long latestSolidifiedBlockNumber) { - if (eventPluginLoaded && EventPluginLoader.getInstance().isSolidityTriggerEnable()) { - SolidityTriggerCapsule solidityTriggerCapsule - = new SolidityTriggerCapsule(latestSolidifiedBlockNumber); - boolean result = triggerCapsuleQueue.offer(solidityTriggerCapsule); - if (!result) { - logger.info("too many trigger, lost solidified trigger, " - + "block number: {}", latestSolidifiedBlockNumber); - } - } if (eventPluginLoaded && EventPluginLoader.getInstance().isSolidityLogTriggerEnable()) { for (Long i : Args.getSolidityContractLogTriggerMap().keySet()) { postSolidityLogContractTrigger(i, latestSolidifiedBlockNumber); @@ -1768,10 +1734,43 @@ private void postSolidityTrigger(final long latestSolidifiedBlockNumber) { postSolidityEventContractTrigger(i, latestSolidifiedBlockNumber); } } + if (eventPluginLoaded && EventPluginLoader.getInstance().isSolidityTriggerEnable()) { + SolidityTriggerCapsule solidityTriggerCapsule + = new SolidityTriggerCapsule(latestSolidifiedBlockNumber); + + BlockCapsule blockCapsule; + try { + blockCapsule = chainBaseManager.getBlockByNum(latestSolidifiedBlockNumber); + solidityTriggerCapsule.setTimeStamp(blockCapsule.getTimeStamp()); + } catch (Exception e) { + logger.error("postSolidityTrigger getBlockByNum={} except, {}", + latestSolidifiedBlockNumber, e.getMessage()); + } + + boolean result = triggerCapsuleQueue.offer(solidityTriggerCapsule); + if (!result) { + logger.info("too many trigger, lost solidified trigger, " + + "block number: {}", latestSolidifiedBlockNumber); + } + } } - private void postBlockTrigger(final BlockCapsule newBlock) { + private void postBlockTrigger(final BlockCapsule blockCapsule) { + BlockCapsule newBlock = blockCapsule; + + // process block trigger if (eventPluginLoaded && EventPluginLoader.getInstance().isBlockLogTriggerEnable()) { + if (EventPluginLoader.getInstance().isBlockLogTriggerSolidified()) { + long solidityBlkNum = getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); + try { + newBlock = chainBaseManager + .getBlockByNum(solidityBlkNum); + } catch (Exception e) { + logger.error("postBlockTrigger getBlockByNum blkNum={} except, error is {}", + solidityBlkNum, e.getMessage()); + } + } + BlockLogTriggerCapsule blockLogTriggerCapsule = new BlockLogTriggerCapsule(newBlock); blockLogTriggerCapsule.setLatestSolidifiedBlockNumber(getDynamicPropertiesStore() .getLatestSolidifiedBlockNum()); @@ -1780,20 +1779,101 @@ private void postBlockTrigger(final BlockCapsule newBlock) { } } - for (TransactionCapsule e : newBlock.getTransactions()) { - postTransactionTrigger(e, newBlock); + // process transaction trigger + if (eventPluginLoaded && EventPluginLoader.getInstance().isTransactionLogTriggerEnable()) { + if (EventPluginLoader.getInstance().isTransactionLogTriggerSolidified()) { + long solidityBlkNum = getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); + try { + newBlock = chainBaseManager + .getBlockByNum(solidityBlkNum); + } catch (Exception e) { + logger.error("postBlockTrigger getBlockByNum blkNum={} except, error is {}", + solidityBlkNum, e.getMessage()); + } + } else { + // need to reset block + newBlock = blockCapsule; + } + + List transactionCapsuleList = newBlock.getTransactions(); + + // get transactionInfoList + if (EventPluginLoader.getInstance().isTransactionLogTriggerEthCompatible()) { + TransactionInfoList transactionInfoList = TransactionInfoList.newBuilder().build(); + TransactionInfoList.Builder transactionInfoListBuilder = TransactionInfoList.newBuilder(); + + try { + TransactionRetCapsule result = chainBaseManager.getTransactionRetStore() + .getTransactionInfoByBlockNum(ByteArray.fromLong(newBlock.getNum())); + + if (!Objects.isNull(result) && !Objects.isNull(result.getInstance())) { + result.getInstance().getTransactioninfoList().forEach( + transactionInfoListBuilder::addTransactionInfo + ); + + transactionInfoList = transactionInfoListBuilder.build(); + } + } catch (BadItemException e) { + logger.error("postBlockTrigger getTransactionInfoList blockNum={}, error is {}", + newBlock.getNum(), e.getMessage()); + } + + if (transactionCapsuleList.size() == transactionInfoList.getTransactionInfoCount()) { + long cumulativeEnergyUsed = 0; + long cumulativeLogCount = 0; + long energyUnitPrice = chainBaseManager.getDynamicPropertiesStore().getEnergyFee(); + + for (int i = 0; i < transactionCapsuleList.size(); i++) { + TransactionInfo transactionInfo = transactionInfoList.getTransactionInfo(i); + TransactionCapsule transactionCapsule = transactionCapsuleList.get(i); + // reset block num to ignore value is -1 + transactionCapsule.setBlockNum(newBlock.getNum()); + + cumulativeEnergyUsed += postTransactionTrigger(transactionCapsule, newBlock, i, + cumulativeEnergyUsed, cumulativeLogCount, transactionInfo, energyUnitPrice); + + cumulativeLogCount += transactionInfo.getLogCount(); + } + } else { + logger.error("postBlockTrigger blockNum={} has no transactions or " + + "the sizes of transactionInfoList and transactionCapsuleList are not equal", + newBlock.getNum()); + for (TransactionCapsule e : newBlock.getTransactions()) { + postTransactionTrigger(e, newBlock); + } + } + } else { + for (TransactionCapsule e : newBlock.getTransactions()) { + postTransactionTrigger(e, newBlock); + } + } + } + } + + // return energyUsageTotal of the current transaction + // cumulativeEnergyUsed is the total of energy used before the current transaction + private long postTransactionTrigger(final TransactionCapsule trxCap, + final BlockCapsule blockCap, int index, long preCumulativeEnergyUsed, + long cumulativeLogCount, final TransactionInfo transactionInfo, long energyUnitPrice) { + TransactionLogTriggerCapsule trx = new TransactionLogTriggerCapsule(trxCap, blockCap, + index, preCumulativeEnergyUsed, cumulativeLogCount, transactionInfo, energyUnitPrice); + trx.setLatestSolidifiedBlockNumber(getDynamicPropertiesStore() + .getLatestSolidifiedBlockNum()); + if (!triggerCapsuleQueue.offer(trx)) { + logger.info("too many triggers, transaction trigger lost: {}", trxCap.getTransactionId()); } + + return trx.getTransactionLogTrigger().getEnergyUsageTotal(); } + private void postTransactionTrigger(final TransactionCapsule trxCap, final BlockCapsule blockCap) { - if (eventPluginLoaded && EventPluginLoader.getInstance().isTransactionLogTriggerEnable()) { - TransactionLogTriggerCapsule trx = new TransactionLogTriggerCapsule(trxCap, blockCap); - trx.setLatestSolidifiedBlockNumber(getDynamicPropertiesStore() - .getLatestSolidifiedBlockNum()); - if (!triggerCapsuleQueue.offer(trx)) { - logger.info("too many triggers, transaction trigger lost: {}", trxCap.getTransactionId()); - } + TransactionLogTriggerCapsule trx = new TransactionLogTriggerCapsule(trxCap, blockCap); + trx.setLatestSolidifiedBlockNumber(getDynamicPropertiesStore() + .getLatestSolidifiedBlockNum()); + if (!triggerCapsuleQueue.offer(trx)) { + logger.info("too many triggers, transaction trigger lost: {}", trxCap.getTransactionId()); } } @@ -1806,7 +1886,7 @@ private void reOrgContractTrigger() { BlockCapsule oldHeadBlock = chainBaseManager.getBlockById( getDynamicPropertiesStore().getLatestBlockHeaderHash()); for (TransactionCapsule trx : oldHeadBlock.getTransactions()) { - postContractTrigger(trx.getTrxTrace(), true); + postContractTrigger(trx.getTrxTrace(), true, oldHeadBlock.getBlockId().toString()); } } catch (BadItemException | ItemNotFoundException e) { logger.error("block header hash does not exist or is bad: {}", @@ -1815,7 +1895,7 @@ private void reOrgContractTrigger() { } } - private void postContractTrigger(final TransactionTrace trace, boolean remove) { + private void postContractTrigger(final TransactionTrace trace, boolean remove, String blockHash) { boolean isContractTriggerEnable = EventPluginLoader.getInstance() .isContractEventTriggerEnable() || EventPluginLoader .getInstance().isContractLogTriggerEnable(); @@ -1830,6 +1910,8 @@ private void postContractTrigger(final TransactionTrace trace, boolean remove) { contractTriggerCapsule.getContractTrigger().setRemoved(remove); contractTriggerCapsule.setLatestSolidifiedBlockNumber(getDynamicPropertiesStore() .getLatestSolidifiedBlockNum()); + contractTriggerCapsule.setBlockHash(blockHash); + if (!triggerCapsuleQueue.offer(contractTriggerCapsule)) { logger .info("too many triggers, contract log trigger lost: {}", trigger.getTransactionId()); diff --git a/framework/src/main/java/org/tron/core/db/PendingManager.java b/framework/src/main/java/org/tron/core/db/PendingManager.java index e7ef3ec077e..9048925dda3 100644 --- a/framework/src/main/java/org/tron/core/db/PendingManager.java +++ b/framework/src/main/java/org/tron/core/db/PendingManager.java @@ -1,5 +1,6 @@ package org.tron.core.db; +import java.util.Iterator; import lombok.extern.slf4j.Slf4j; import org.tron.core.capsule.TransactionCapsule; import org.tron.core.config.args.Args; @@ -19,9 +20,18 @@ public PendingManager(Manager db) { @Override public void close() { + long now = System.currentTimeMillis(); + Iterator iterator = dbManager.getRePushTransactions().iterator(); + while (iterator.hasNext()) { + if (now - iterator.next().getTime() > timeout) { + iterator.remove(); + } + } + for (TransactionCapsule tx : dbManager.getPendingTransactions()) { txIteration(tx); } + dbManager.getPendingTransactions().clear(); for (TransactionCapsule tx : dbManager.getPoppedTransactions()) { tx.setTime(System.currentTimeMillis()); diff --git a/framework/src/main/java/org/tron/core/db/api/EnergyPriceHistoryLoader.java b/framework/src/main/java/org/tron/core/db/api/EnergyPriceHistoryLoader.java new file mode 100644 index 00000000000..05b5edef8b0 --- /dev/null +++ b/framework/src/main/java/org/tron/core/db/api/EnergyPriceHistoryLoader.java @@ -0,0 +1,61 @@ +package org.tron.core.db.api; + +import java.util.ArrayList; +import java.util.List; + +import lombok.extern.slf4j.Slf4j; +import org.tron.core.ChainBaseManager; +import org.tron.core.capsule.ProposalCapsule; +import org.tron.core.store.DynamicPropertiesStore; +import org.tron.core.utils.ProposalUtil.ProposalType; +import org.tron.protos.Protocol.Proposal.State; + +@Slf4j(topic = "DB") +public class EnergyPriceHistoryLoader { + + private final ChainBaseManager chainBaseManager; + private List proposalCapsuleList = new ArrayList<>(); + + public EnergyPriceHistoryLoader(ChainBaseManager chainBaseManager) { + this.chainBaseManager = chainBaseManager; + } + + public void doWork() { + long start = System.currentTimeMillis(); + logger.info("Start to load energy price"); + + getEnergyProposals(); + if (!proposalCapsuleList.isEmpty()) { + String energyPriceHistory = parseProposalsToStr(); + chainBaseManager.getDynamicPropertiesStore().saveEnergyPriceHistory(energyPriceHistory); + } + finish(); + + logger.info( + "Complete energy price load, total time: {} milliseconds, total proposal count: {}", + System.currentTimeMillis() - start, proposalCapsuleList.size()); + } + + public void getEnergyProposals() { + proposalCapsuleList = chainBaseManager.getProposalStore() + .getSpecifiedProposals(State.APPROVED, ProposalType.ENERGY_FEE.getCode()); + } + + public String parseProposalsToStr() { + StringBuilder builder = new StringBuilder(DynamicPropertiesStore.DEFAULT_ENERGY_PRICE_HISTORY); + + for (ProposalCapsule proposalCapsule : proposalCapsuleList) { + builder.append(",") + .append(proposalCapsule.getExpirationTime()) + .append(":") + .append(proposalCapsule.getParameters().get(ProposalType.ENERGY_FEE.getCode())); + } + + return builder.toString(); + } + + public void finish() { + chainBaseManager.getDynamicPropertiesStore().saveEnergyPriceHistoryDone(1); + } + +} diff --git a/framework/src/main/java/org/tron/core/db/api/MoveAbiHelper.java b/framework/src/main/java/org/tron/core/db/api/MoveAbiHelper.java index dad48d117b3..830114b9e40 100644 --- a/framework/src/main/java/org/tron/core/db/api/MoveAbiHelper.java +++ b/framework/src/main/java/org/tron/core/db/api/MoveAbiHelper.java @@ -5,7 +5,6 @@ import lombok.extern.slf4j.Slf4j; import org.tron.core.ChainBaseManager; -import org.tron.core.capsule.AbiCapsule; import org.tron.core.capsule.ContractCapsule; import org.tron.core.store.AbiStore; import org.tron.core.store.ContractStore; diff --git a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java index 06b831712f5..0787981893d 100644 --- a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java +++ b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java @@ -85,6 +85,8 @@ public class TronNetDelegate { private int blockIdCacheSize = 100; + private long timeout = 1000; + private Queue freshBlockId = new ConcurrentLinkedQueue() { @Override public boolean offer(BlockId blockId) { @@ -261,16 +263,27 @@ public void pushTransaction(TransactionCapsule trx) throws P2pException { } } - public boolean validBlock(BlockCapsule block) throws P2pException { + public void validSignature(BlockCapsule block) throws P2pException { try { - return witnessScheduleStore.getActiveWitnesses().contains(block.getWitnessAddress()) - && block - .validateSignature(dbManager.getDynamicPropertiesStore(), dbManager.getAccountStore()); + if (!block.validateSignature(dbManager.getDynamicPropertiesStore(), + dbManager.getAccountStore())) { + throw new P2pException(TypeEnum.BAD_BLOCK, "valid signature failed."); + } } catch (ValidateSignatureException e) { throw new P2pException(TypeEnum.BAD_BLOCK, e); } } + public boolean validBlock(BlockCapsule block) throws P2pException { + long time = System.currentTimeMillis(); + if (block.getTimeStamp() - time > timeout) { + throw new P2pException(TypeEnum.BAD_BLOCK, + "time:" + time + ",block time:" + block.getTimeStamp()); + } + validSignature(block); + return witnessScheduleStore.getActiveWitnesses().contains(block.getWitnessAddress()); + } + public PbftSignCapsule getBlockPbftCommitData(long blockNum) { return chainBaseManager.getPbftSignDataStore().getBlockSignData(blockNum); } diff --git a/framework/src/main/java/org/tron/core/net/TronNetService.java b/framework/src/main/java/org/tron/core/net/TronNetService.java index 094e452f444..15d5173774a 100644 --- a/framework/src/main/java/org/tron/core/net/TronNetService.java +++ b/framework/src/main/java/org/tron/core/net/TronNetService.java @@ -8,6 +8,7 @@ import org.tron.core.exception.P2pException; import org.tron.core.exception.P2pException.TypeEnum; import org.tron.core.net.message.BlockMessage; +import org.tron.core.net.message.TransactionMessage; import org.tron.core.net.message.TronMessage; import org.tron.core.net.messagehandler.BlockMsgHandler; import org.tron.core.net.messagehandler.ChainInventoryMsgHandler; @@ -78,6 +79,10 @@ public void stop() { logger.info("TronNetService closed successfully."); } + public int fastBroadcastTransaction(TransactionMessage msg) { + return advService.fastBroadcastTransaction(msg); + } + public void broadcast(Message msg) { advService.broadcast(msg); } diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java index b47918e12cb..19f30358660 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java @@ -106,28 +106,42 @@ private void processBlock(PeerConnection peer, BlockCapsule block) throws P2pExc advService.addInvToCache(item); } - if (fastForward) { - if (block.getNum() < tronNetDelegate.getHeadBlockId().getNum()) { - logger.warn("Receive a low block {}, head {}", - blockId.getString(), tronNetDelegate.getHeadBlockId().getString()); - return; - } - if (tronNetDelegate.validBlock(block)) { + long headNum = tronNetDelegate.getHeadBlockId().getNum(); + if (block.getNum() < headNum) { + logger.warn("Receive a low block {}, head {}", blockId.getString(), headNum); + return; + } + + boolean flag = tronNetDelegate.validBlock(block); + if (flag) { + if (fastForward) { advService.fastForward(new BlockMessage(block)); tronNetDelegate.trustNode(peer); + } else { + advService.broadcast(new BlockMessage(block)); } } - tronNetDelegate.processBlock(block, false); - witnessProductBlockService.validWitnessProductTwoBlock(block); - tronNetDelegate.getActivePeer().forEach(p -> { - if (p.getAdvInvReceive().getIfPresent(blockId) != null) { - p.setBlockBothHave(blockId); + try { + tronNetDelegate.processBlock(block, false); + if (!flag) { + if (fastForward) { + advService.fastForward(new BlockMessage(block)); + } else { + advService.broadcast(new BlockMessage(block)); + } } - }); - if (!fastForward) { - advService.broadcast(new BlockMessage(block)); + witnessProductBlockService.validWitnessProductTwoBlock(block); + + tronNetDelegate.getActivePeer().forEach(p -> { + if (p.getAdvInvReceive().getIfPresent(blockId) != null) { + p.setBlockBothHave(blockId); + } + }); + } catch (Exception e) { + logger.warn("Process adv block {} from peer {} failed. reason: {}", + blockId, peer.getInetAddress(), e.getMessage()); } } diff --git a/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java b/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java index 01f9e0b6f66..2b1e52e5da9 100644 --- a/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java +++ b/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java @@ -43,7 +43,11 @@ public class PeerConnection extends Channel { @Setter @Getter - private HelloMessage helloMessage; + private HelloMessage helloMessageReceive; + + @Setter + @Getter + private HelloMessage helloMessageSend; private int invCacheSize = 100_000; @@ -114,12 +118,11 @@ public void fastSend(Message message) { } public void onConnect() { - long headBlockNum = tronNetDelegate.getHeadBlockId().getNum(); - long peerHeadBlockNum = getHelloMessage().getHeadBlockId().getNum(); + long headBlockNum = helloMessageSend.getHeadBlockId().getNum(); + long peerHeadBlockNum = helloMessageReceive.getHeadBlockId().getNum(); if (peerHeadBlockNum > headBlockNum) { needSyncFromUs = false; - setTronState(TronState.SYNCING); syncService.startSync(this); } else { needSyncFromPeer = false; diff --git a/framework/src/main/java/org/tron/core/net/service/AdvService.java b/framework/src/main/java/org/tron/core/net/service/AdvService.java index 46c0f4c883a..64c9ec79e99 100644 --- a/framework/src/main/java/org/tron/core/net/service/AdvService.java +++ b/framework/src/main/java/org/tron/core/net/service/AdvService.java @@ -6,6 +6,8 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; + +import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; @@ -141,6 +143,40 @@ public Message getMessage(Item item) { } } + public int fastBroadcastTransaction(TransactionMessage msg) { + + List peers = tronNetDelegate.getActivePeer().stream() + .filter(peer -> !peer.isNeedSyncFromPeer() && !peer.isNeedSyncFromUs()) + .collect(Collectors.toList()); + + if (peers.size() == 0) { + logger.warn("Broadcast transaction {} failed, no connection.", msg.getMessageId()); + return 0; + } + + Item item = new Item(msg.getMessageId(), InventoryType.TRX); + trxCount.add(); + trxCache.put(item, new TransactionMessage(msg.getTransactionCapsule().getInstance())); + + List list = new ArrayList<>(); + list.add(msg.getMessageId()); + InventoryMessage inventoryMessage = new InventoryMessage(list, InventoryType.TRX); + + int peersCount = 0; + for (PeerConnection peer: peers) { + if (peer.getAdvInvReceive().getIfPresent(item) == null + && peer.getAdvInvSpread().getIfPresent(item) == null) { + peersCount++; + peer.getAdvInvSpread().put(item, Time.getCurrentMillis()); + peer.fastSend(inventoryMessage); + } + } + if (peersCount == 0) { + logger.warn("Broadcast transaction {} failed, no peers.", msg.getMessageId()); + } + return peersCount; + } + public void broadcast(Message msg) { if (fastForward) { diff --git a/framework/src/main/java/org/tron/core/net/service/SyncService.java b/framework/src/main/java/org/tron/core/net/service/SyncService.java index a438d29a809..64a721bf014 100644 --- a/framework/src/main/java/org/tron/core/net/service/SyncService.java +++ b/framework/src/main/java/org/tron/core/net/service/SyncService.java @@ -263,6 +263,7 @@ private void processSyncBlock(BlockCapsule block) { boolean flag = true; BlockId blockId = block.getBlockId(); try { + tronNetDelegate.validSignature(block); tronNetDelegate.processBlock(block, true); pbftDataSyncHandler.processPBFTCommitData(block); } catch (Exception e) { diff --git a/framework/src/main/java/org/tron/core/services/RpcApiService.java b/framework/src/main/java/org/tron/core/services/RpcApiService.java index 241539c2e62..9c7fe772679 100755 --- a/framework/src/main/java/org/tron/core/services/RpcApiService.java +++ b/framework/src/main/java/org/tron/core/services/RpcApiService.java @@ -113,6 +113,7 @@ import org.tron.core.metrics.MetricsApiService; import org.tron.core.services.filter.LiteFnQueryGrpcInterceptor; import org.tron.core.services.ratelimiter.RateLimiterInterceptor; +import org.tron.core.services.ratelimiter.RpcApiAccessInterceptor; import org.tron.core.utils.TransactionUtil; import org.tron.core.zen.address.DiversifierT; import org.tron.core.zen.address.IncomingViewingKey; @@ -201,6 +202,8 @@ public class RpcApiService implements Service { private RateLimiterInterceptor rateLimiterInterceptor; @Autowired private LiteFnQueryGrpcInterceptor liteFnQueryGrpcInterceptor; + @Autowired + private RpcApiAccessInterceptor apiAccessInterceptor; @Autowired private MetricsApiService metricsApiService; @@ -252,12 +255,15 @@ public void start() { .flowControlWindow(parameter.getFlowControlWindow()) .maxConnectionIdle(parameter.getMaxConnectionIdleInMillis(), TimeUnit.MILLISECONDS) .maxConnectionAge(parameter.getMaxConnectionAgeInMillis(), TimeUnit.MILLISECONDS) - .maxMessageSize(parameter.getMaxMessageSize()) + .maxInboundMessageSize(parameter.getMaxMessageSize()) .maxHeaderListSize(parameter.getMaxHeaderListSize()); // add a rate limiter interceptor serverBuilder.intercept(rateLimiterInterceptor); + // add api access interceptor + serverBuilder.intercept(apiAccessInterceptor); + // add lite fullnode query interceptor serverBuilder.intercept(liteFnQueryGrpcInterceptor); diff --git a/framework/src/main/java/org/tron/core/services/filter/HttpApiAccessFilter.java b/framework/src/main/java/org/tron/core/services/filter/HttpApiAccessFilter.java new file mode 100644 index 00000000000..35ebd9d6d6d --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/filter/HttpApiAccessFilter.java @@ -0,0 +1,75 @@ +package org.tron.core.services.filter; + +import com.alibaba.fastjson.JSONObject; +import java.util.List; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.tron.common.parameter.CommonParameter; + +@Component +@Slf4j(topic = "httpApiAccessFilter") +public class HttpApiAccessFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { + try { + if (request instanceof HttpServletRequest) { + String endpoint = ((HttpServletRequest) request).getRequestURI(); + HttpServletResponse resp = (HttpServletResponse) response; + + if (isDisabled(endpoint)) { + resp.setStatus(HttpServletResponse.SC_NOT_FOUND); + resp.setContentType("application/json; charset=utf-8"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("Error", "this API is unavailable due to config"); + resp.getWriter().println(jsonObject.toJSONString()); + return; + } + + CharResponseWrapper responseWrapper = new CharResponseWrapper(resp); + chain.doFilter(request, responseWrapper); + + } else { + chain.doFilter(request, response); + } + + } catch (Exception e) { + logger.error("http api access filter exception: {}", e.getMessage()); + } + } + + @Override + public void destroy() { + + } + + private boolean isDisabled(String endpoint) { + boolean disabled = false; + + try { + List disabledApiList = CommonParameter.getInstance().getDisabledApiList(); + if (!disabledApiList.isEmpty()) { + disabled = disabledApiList.contains(endpoint.split("/")[2].toLowerCase()); + } + } catch (Exception e) { + logger.error("check isDisabled except, endpoint={}, error is {}", endpoint, e.getMessage()); + } + + return disabled; + } + +} + + + diff --git a/framework/src/main/java/org/tron/core/services/filter/LiteFnQueryHttpFilter.java b/framework/src/main/java/org/tron/core/services/filter/LiteFnQueryHttpFilter.java index e80ce4ec549..b7afdbb4258 100644 --- a/framework/src/main/java/org/tron/core/services/filter/LiteFnQueryHttpFilter.java +++ b/framework/src/main/java/org/tron/core/services/filter/LiteFnQueryHttpFilter.java @@ -113,6 +113,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo shouldBeFiltered = true; } if (shouldBeFiltered) { + servletResponse.setContentType("application/json; charset=utf-8"); servletResponse.getWriter().write("this API is closed because this node is a lite fullnode"); } else { filterChain.doFilter(servletRequest, servletResponse); diff --git a/framework/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java b/framework/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java index 1c219f35bbf..40890fc7c79 100644 --- a/framework/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java +++ b/framework/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java @@ -22,6 +22,7 @@ import org.tron.common.zksnark.LibrustzcashParam.InitZksnarkParams; import org.tron.core.config.args.Args; import org.tron.core.exception.ZksnarkException; +import org.tron.core.services.filter.HttpApiAccessFilter; import org.tron.core.services.filter.HttpInterceptor; import org.tron.core.services.filter.LiteFnQueryHttpFilter; @@ -279,11 +280,15 @@ public class FullNodeHttpApiService implements Service { @Autowired private LiteFnQueryHttpFilter liteFnQueryHttpFilter; @Autowired + private HttpApiAccessFilter httpApiAccessFilter; + @Autowired private GetTransactionFromPendingServlet getTransactionFromPendingServlet; @Autowired private GetTransactionListFromPendingServlet getTransactionListFromPendingServlet; @Autowired private GetPendingSizeServlet getPendingSizeServlet; + @Autowired + private GetEnergyPricesServlet getEnergyPricesServlet; private static String getParamsFile(String fileName) { InputStream in = Thread.currentThread().getContextClassLoader() @@ -529,6 +534,7 @@ public void start() { context.addServlet(new ServletHolder(getTransactionListFromPendingServlet), "/wallet/gettransactionlistfrompending"); context.addServlet(new ServletHolder(getPendingSizeServlet), "/wallet/getpendingsize"); + context.addServlet(new ServletHolder(getEnergyPricesServlet), "/wallet/getenergyprices"); int maxHttpConnectNumber = Args.getInstance().getMaxHttpConnectNumber(); if (maxHttpConnectNumber > 0) { @@ -540,7 +546,17 @@ public void start() { context.addFilter(new FilterHolder(liteFnQueryHttpFilter), "/*", EnumSet.allOf(DispatcherType.class)); - // filter + // http access filter, it should have higher priority than HttpInterceptor + context.addFilter(new FilterHolder(httpApiAccessFilter), "/*", + EnumSet.allOf(DispatcherType.class)); + // note: if the pathSpec of servlet is not started with wallet, it should be included here + context.getServletHandler().getFilterMappings()[1] + .setPathSpecs(new String[] {"/wallet/*", + "/net/listnodes", + "/monitor/getstatsinfo", + "/monitor/getnodeinfo"}); + + // metrics filter ServletHandler handler = new ServletHandler(); FilterHolder fh = handler .addFilterWithMapping((Class) HttpInterceptor.class, "/*", diff --git a/framework/src/main/java/org/tron/core/services/http/GetContractInfoServlet.java b/framework/src/main/java/org/tron/core/services/http/GetContractInfoServlet.java index 32aabca5eb8..86ed7f6d9b6 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetContractInfoServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetContractInfoServlet.java @@ -35,9 +35,14 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { BytesMessage.Builder build = BytesMessage.newBuilder(); JsonFormat.merge(jsonObject.toJSONString(), build, visible); SmartContractDataWrapper smartContract = wallet.getContractInfo(build.build()); - JSONObject jsonSmartContract = JSONObject - .parseObject(JsonFormat.printToString(smartContract, visible)); - response.getWriter().println(jsonSmartContract.toJSONString()); + + if (smartContract == null) { + response.getWriter().println("{}"); + } else { + JSONObject jsonSmartContract = JSONObject + .parseObject(JsonFormat.printToString(smartContract, visible)); + response.getWriter().println(jsonSmartContract.toJSONString()); + } } catch (Exception e) { Util.processError(e, response); } @@ -58,9 +63,14 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) BytesMessage.Builder build = BytesMessage.newBuilder(); JsonFormat.merge(input, build, visible); SmartContractDataWrapper smartContract = wallet.getContractInfo(build.build()); - JSONObject jsonSmartContract = JSONObject - .parseObject(JsonFormat.printToString(smartContract, visible)); - response.getWriter().println(jsonSmartContract.toJSONString()); + + if (smartContract == null) { + response.getWriter().println("{}"); + } else { + JSONObject jsonSmartContract = JSONObject + .parseObject(JsonFormat.printToString(smartContract, visible)); + response.getWriter().println(jsonSmartContract.toJSONString()); + } } catch (Exception e) { Util.processError(e, response); } diff --git a/framework/src/main/java/org/tron/core/services/http/GetContractServlet.java b/framework/src/main/java/org/tron/core/services/http/GetContractServlet.java index d848a762622..b9efd6c1520 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetContractServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetContractServlet.java @@ -33,9 +33,14 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { BytesMessage.Builder build = BytesMessage.newBuilder(); JsonFormat.merge(jsonObject.toJSONString(), build, visible); SmartContract smartContract = wallet.getContract(build.build()); - JSONObject jsonSmartContract = JSONObject - .parseObject(JsonFormat.printToString(smartContract, visible)); - response.getWriter().println(jsonSmartContract.toJSONString()); + + if (smartContract == null) { + response.getWriter().println("{}"); + } else { + JSONObject jsonSmartContract = JSONObject + .parseObject(JsonFormat.printToString(smartContract, visible)); + response.getWriter().println(jsonSmartContract.toJSONString()); + } } catch (Exception e) { Util.processError(e, response); } @@ -56,9 +61,14 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) BytesMessage.Builder build = BytesMessage.newBuilder(); JsonFormat.merge(input, build, visible); SmartContract smartContract = wallet.getContract(build.build()); - JSONObject jsonSmartContract = JSONObject - .parseObject(JsonFormat.printToString(smartContract, visible)); - response.getWriter().println(jsonSmartContract.toJSONString()); + + if (smartContract == null) { + response.getWriter().println("{}"); + } else { + JSONObject jsonSmartContract = JSONObject + .parseObject(JsonFormat.printToString(smartContract, visible)); + response.getWriter().println(jsonSmartContract.toJSONString()); + } } catch (Exception e) { Util.processError(e, response); } diff --git a/framework/src/main/java/org/tron/core/services/http/GetEnergyPricesServlet.java b/framework/src/main/java/org/tron/core/services/http/GetEnergyPricesServlet.java new file mode 100644 index 00000000000..36129d8ffdb --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/http/GetEnergyPricesServlet.java @@ -0,0 +1,37 @@ +package org.tron.core.services.http; + +import com.alibaba.fastjson.JSONObject; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.core.Wallet; + + +@Component +@Slf4j(topic = "API") +public class GetEnergyPricesServlet extends RateLimiterServlet { + + @Autowired + private Wallet wallet; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) { + try { + String reply = wallet.getEnergyPrices(); + if (reply != null) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("prices", reply); + response.getWriter().println(jsonObject); + } else { + response.getWriter().println("{}"); + } + } catch (Exception e) { + Util.processError(e, response); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) { + doGet(request, response); + } +} diff --git a/framework/src/main/java/org/tron/core/services/http/RateLimiterServlet.java b/framework/src/main/java/org/tron/core/services/http/RateLimiterServlet.java index 8fa47fd60eb..e0f65fa09ba 100644 --- a/framework/src/main/java/org/tron/core/services/http/RateLimiterServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/RateLimiterServlet.java @@ -95,6 +95,8 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) } try { + resp.setContentType("application/json; charset=utf-8"); + if (acquireResource) { super.service(req, resp); } else { diff --git a/framework/src/main/java/org/tron/core/services/http/Util.java b/framework/src/main/java/org/tron/core/services/http/Util.java index 314d80d767f..1a7e111dc59 100644 --- a/framework/src/main/java/org/tron/core/services/http/Util.java +++ b/framework/src/main/java/org/tron/core/services/http/Util.java @@ -348,15 +348,22 @@ public static Transaction setTransactionPermissionId(JSONObject jsonObject, Transaction transaction) { if (jsonObject.containsKey(PERMISSION_ID)) { int permissionId = jsonObject.getInteger(PERMISSION_ID); - if (permissionId > 0) { - Transaction.raw.Builder raw = transaction.getRawData().toBuilder(); - Transaction.Contract.Builder contract = raw.getContract(0).toBuilder() - .setPermissionId(permissionId); - raw.clearContract(); - raw.addContract(contract); - return transaction.toBuilder().setRawData(raw).build(); - } + return setTransactionPermissionId(permissionId, transaction); + } + + return transaction; + } + + public static Transaction setTransactionPermissionId(int permissionId, Transaction transaction) { + if (permissionId > 0) { + Transaction.raw.Builder raw = transaction.getRawData().toBuilder(); + Transaction.Contract.Builder contract = raw.getContract(0).toBuilder() + .setPermissionId(permissionId); + raw.clearContract(); + raw.addContract(contract); + return transaction.toBuilder().setRawData(raw).build(); } + return transaction; } @@ -364,16 +371,24 @@ public static Transaction setTransactionExtraData(JSONObject jsonObject, Transaction transaction, boolean visible) { if (jsonObject.containsKey(EXTRA_DATA)) { String data = jsonObject.getString(EXTRA_DATA); - if (data.length() > 0) { - Transaction.raw.Builder raw = transaction.getRawData().toBuilder(); - if (visible) { - raw.setData(ByteString.copyFrom(data.getBytes())); - } else { - raw.setData(ByteString.copyFrom(ByteArray.fromHexString(data))); - } - return transaction.toBuilder().setRawData(raw).build(); + return setTransactionExtraData(data, transaction, visible); + } + + return transaction; + } + + public static Transaction setTransactionExtraData(String data, Transaction transaction, + boolean visible) { + if (data.length() > 0) { + Transaction.raw.Builder raw = transaction.getRawData().toBuilder(); + if (visible) { + raw.setData(ByteString.copyFrom(data.getBytes())); + } else { + raw.setData(ByteString.copyFrom(ByteArray.fromHexString(data))); } + return transaction.toBuilder().setRawData(raw).build(); } + return transaction; } diff --git a/framework/src/main/java/org/tron/core/services/http/solidity/SolidityNodeHttpApiService.java b/framework/src/main/java/org/tron/core/services/http/solidity/SolidityNodeHttpApiService.java index 0a3ff9eef4f..6210f542370 100644 --- a/framework/src/main/java/org/tron/core/services/http/solidity/SolidityNodeHttpApiService.java +++ b/framework/src/main/java/org/tron/core/services/http/solidity/SolidityNodeHttpApiService.java @@ -1,15 +1,21 @@ package org.tron.core.services.http.solidity; +import java.util.EnumSet; +import javax.servlet.DispatcherType; +import javax.servlet.Filter; import lombok.extern.slf4j.Slf4j; import org.eclipse.jetty.server.ConnectionLimit; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.tron.common.application.Service; import org.tron.common.parameter.CommonParameter; import org.tron.core.config.args.Args; +import org.tron.core.services.filter.HttpApiAccessFilter; import org.tron.core.services.http.FullNodeHttpApiService; import org.tron.core.services.http.GetAccountByIdServlet; import org.tron.core.services.http.GetAccountServlet; @@ -140,6 +146,9 @@ public class SolidityNodeHttpApiService implements Service { @Autowired private GetTransactionInfoByBlockNumServlet getTransactionInfoByBlockNumServlet; + @Autowired + private HttpApiAccessFilter httpApiAccessFilter; + @Override public void init() { } @@ -237,10 +246,18 @@ public void start() { "/walletsolidity/triggerconstantcontract"); context.addServlet(new ServletHolder(getNodeInfoServlet), "/wallet/getnodeinfo"); + context.addServlet(new ServletHolder(getNodeInfoServlet), "/walletsolidity/getnodeinfo"); context.addServlet(new ServletHolder(getBrokerageServlet), "/walletsolidity/getBrokerage"); context.addServlet(new ServletHolder(getRewardServlet), "/walletsolidity/getReward"); context.addServlet(new ServletHolder(getBurnTrxServlet), "/walletsolidity/getburntrx"); + // http access filter + context.addFilter(new FilterHolder(httpApiAccessFilter), "/walletsolidity/*", + EnumSet.allOf(DispatcherType.class)); + context.getServletHandler().getFilterMappings()[0] + .setPathSpecs(new String[] {"/walletsolidity/*", + "/wallet/getnodeinfo"}); + int maxHttpConnectNumber = Args.getInstance().getMaxHttpConnectNumber(); if (maxHttpConnectNumber > 0) { server.addBean(new ConnectionLimit(maxHttpConnectNumber, server)); diff --git a/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnPBFT/JsonRpcOnPBFTServlet.java b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnPBFT/JsonRpcOnPBFTServlet.java new file mode 100644 index 00000000000..bcc383e55db --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnPBFT/JsonRpcOnPBFTServlet.java @@ -0,0 +1,29 @@ +package org.tron.core.services.interfaceJsonRpcOnPBFT; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.core.services.interfaceOnPBFT.WalletOnPBFT; +import org.tron.core.services.jsonrpc.JsonRpcServlet; + +@Component +@Slf4j(topic = "API") +public class JsonRpcOnPBFTServlet extends JsonRpcServlet { + + @Autowired + private WalletOnPBFT walletOnPBFT; + + protected void doPost(HttpServletRequest request, HttpServletResponse response) { + walletOnPBFT.futureGet(() -> { + try { + super.doPost(request, response); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + }); + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnPBFT/JsonRpcServiceOnPBFT.java b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnPBFT/JsonRpcServiceOnPBFT.java new file mode 100644 index 00000000000..96da1515610 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnPBFT/JsonRpcServiceOnPBFT.java @@ -0,0 +1,62 @@ +package org.tron.core.services.interfaceJsonRpcOnPBFT; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.jetty.server.ConnectionLimit; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.common.application.Service; +import org.tron.common.parameter.CommonParameter; + +@Component +@Slf4j(topic = "API") +public class JsonRpcServiceOnPBFT implements Service { + + private int port = CommonParameter.getInstance().getJsonRpcHttpPBFTPort(); + + private Server server; + + @Autowired + private JsonRpcOnPBFTServlet jsonRpcOnPBFTServlet; + + @Override + public void init() { + } + + @Override + public void init(CommonParameter args) { + } + + @Override + public void start() { + try { + server = new Server(port); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + server.setHandler(context); + + context.addServlet(new ServletHolder(jsonRpcOnPBFTServlet), "/jsonrpc"); + + int maxHttpConnectNumber = CommonParameter.getInstance().getMaxHttpConnectNumber(); + if (maxHttpConnectNumber > 0) { + server.addBean(new ConnectionLimit(maxHttpConnectNumber, server)); + } + + server.start(); + + } catch (Exception e) { + logger.debug("IOException: {}", e.getMessage()); + } + } + + @Override + public void stop() { + try { + server.stop(); + } catch (Exception e) { + logger.debug("IOException: {}", e.getMessage()); + } + } +} diff --git a/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnSolidity/JsonRpcOnSolidityServlet.java b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnSolidity/JsonRpcOnSolidityServlet.java new file mode 100644 index 00000000000..a20c7906ad0 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnSolidity/JsonRpcOnSolidityServlet.java @@ -0,0 +1,29 @@ +package org.tron.core.services.interfaceJsonRpcOnSolidity; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.core.services.interfaceOnSolidity.WalletOnSolidity; +import org.tron.core.services.jsonrpc.JsonRpcServlet; + +@Component +@Slf4j(topic = "API") +public class JsonRpcOnSolidityServlet extends JsonRpcServlet { + + @Autowired + private WalletOnSolidity walletOnSolidity; + + protected void doPost(HttpServletRequest request, HttpServletResponse response) { + walletOnSolidity.futureGet(() -> { + try { + super.doPost(request, response); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + }); + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnSolidity/JsonRpcServiceOnSolidity.java b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnSolidity/JsonRpcServiceOnSolidity.java new file mode 100644 index 00000000000..41357c13dc2 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/interfaceJsonRpcOnSolidity/JsonRpcServiceOnSolidity.java @@ -0,0 +1,62 @@ +package org.tron.core.services.interfaceJsonRpcOnSolidity; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.jetty.server.ConnectionLimit; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.common.application.Service; +import org.tron.common.parameter.CommonParameter; + +@Component +@Slf4j(topic = "API") +public class JsonRpcServiceOnSolidity implements Service { + + private int port = CommonParameter.getInstance().getJsonRpcHttpSolidityPort(); + + private Server server; + + @Autowired + private JsonRpcOnSolidityServlet jsonRpcOnSolidityServlet; + + @Override + public void init() { + } + + @Override + public void init(CommonParameter args) { + } + + @Override + public void start() { + try { + server = new Server(port); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + server.setHandler(context); + + context.addServlet(new ServletHolder(jsonRpcOnSolidityServlet), "/jsonrpc"); + + int maxHttpConnectNumber = CommonParameter.getInstance().getMaxHttpConnectNumber(); + if (maxHttpConnectNumber > 0) { + server.addBean(new ConnectionLimit(maxHttpConnectNumber, server)); + } + + server.start(); + + } catch (Exception e) { + logger.debug("IOException: {}", e.getMessage()); + } + } + + @Override + public void stop() { + try { + server.stop(); + } catch (Exception e) { + logger.debug("IOException: {}", e.getMessage()); + } + } +} diff --git a/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/RpcApiServiceOnPBFT.java b/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/RpcApiServiceOnPBFT.java index 669414fca35..01a06b4eb34 100755 --- a/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/RpcApiServiceOnPBFT.java +++ b/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/RpcApiServiceOnPBFT.java @@ -41,6 +41,7 @@ import org.tron.core.services.RpcApiService; import org.tron.core.services.filter.LiteFnQueryGrpcInterceptor; import org.tron.core.services.ratelimiter.RateLimiterInterceptor; +import org.tron.core.services.ratelimiter.RpcApiAccessInterceptor; import org.tron.protos.Protocol.Account; import org.tron.protos.Protocol.Block; import org.tron.protos.Protocol.DynamicProperties; @@ -75,6 +76,9 @@ public class RpcApiServiceOnPBFT implements Service { @Autowired private LiteFnQueryGrpcInterceptor liteFnQueryGrpcInterceptor; + @Autowired + private RpcApiAccessInterceptor apiAccessInterceptor; + @Override public void init() { } @@ -105,12 +109,15 @@ public void start() { .flowControlWindow(args.getFlowControlWindow()) .maxConnectionIdle(args.getMaxConnectionIdleInMillis(), TimeUnit.MILLISECONDS) .maxConnectionAge(args.getMaxConnectionAgeInMillis(), TimeUnit.MILLISECONDS) - .maxMessageSize(args.getMaxMessageSize()) + .maxInboundMessageSize(args.getMaxMessageSize()) .maxHeaderListSize(args.getMaxHeaderListSize()); // add a ratelimiter interceptor serverBuilder.intercept(rateLimiterInterceptor); + // add api access interceptor + serverBuilder.intercept(apiAccessInterceptor); + // add lite fullnode query interceptor serverBuilder.intercept(liteFnQueryGrpcInterceptor); diff --git a/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/http/GetEnergyPricesOnPBFTServlet.java b/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/http/GetEnergyPricesOnPBFTServlet.java new file mode 100644 index 00000000000..4cf8ad06b27 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/http/GetEnergyPricesOnPBFTServlet.java @@ -0,0 +1,26 @@ +package org.tron.core.services.interfaceOnPBFT.http; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.core.services.http.GetEnergyPricesServlet; +import org.tron.core.services.interfaceOnPBFT.WalletOnPBFT; + + +@Component +@Slf4j(topic = "API") +public class GetEnergyPricesOnPBFTServlet extends GetEnergyPricesServlet { + + @Autowired + private WalletOnPBFT walletOnPBFT; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) { + walletOnPBFT.futureGet(() -> super.doGet(request, response)); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) { + walletOnPBFT.futureGet(() -> super.doPost(request, response)); + } +} diff --git a/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/http/PBFT/HttpApiOnPBFTService.java b/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/http/PBFT/HttpApiOnPBFTService.java index ad6d498e38e..9a953a2adb2 100644 --- a/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/http/PBFT/HttpApiOnPBFTService.java +++ b/framework/src/main/java/org/tron/core/services/interfaceOnPBFT/http/PBFT/HttpApiOnPBFTService.java @@ -12,6 +12,7 @@ import org.tron.common.application.Service; import org.tron.common.parameter.CommonParameter; import org.tron.core.config.args.Args; +import org.tron.core.services.filter.HttpApiAccessFilter; import org.tron.core.services.filter.LiteFnQueryHttpFilter; import org.tron.core.services.interfaceOnPBFT.http.GetAccountByIdOnPBFTServlet; import org.tron.core.services.interfaceOnPBFT.http.GetAccountOnPBFTServlet; @@ -27,6 +28,7 @@ import org.tron.core.services.interfaceOnPBFT.http.GetBurnTrxOnPBFTServlet; import org.tron.core.services.interfaceOnPBFT.http.GetDelegatedResourceAccountIndexOnPBFTServlet; import org.tron.core.services.interfaceOnPBFT.http.GetDelegatedResourceOnPBFTServlet; +import org.tron.core.services.interfaceOnPBFT.http.GetEnergyPricesOnPBFTServlet; import org.tron.core.services.interfaceOnPBFT.http.GetExchangeByIdOnPBFTServlet; import org.tron.core.services.interfaceOnPBFT.http.GetMarketOrderByAccountOnPBFTServlet; import org.tron.core.services.interfaceOnPBFT.http.GetMarketOrderByIdOnPBFTServlet; @@ -123,6 +125,8 @@ public class HttpApiOnPBFTService implements Service { @Autowired private LiteFnQueryHttpFilter liteFnQueryHttpFilter; + @Autowired + private HttpApiAccessFilter httpApiAccessFilter; @Autowired private GetMarketOrderByAccountOnPBFTServlet getMarketOrderByAccountOnPBFTServlet; @@ -144,6 +148,8 @@ public class HttpApiOnPBFTService implements Service { isShieldedTRC20ContractNoteSpentOnPBFTServlet; @Autowired private GetBurnTrxOnPBFTServlet getBurnTrxOnPBFTServlet; + @Autowired + private GetEnergyPricesOnPBFTServlet getEnergyPricesOnPBFTServlet; @Override public void init() { @@ -229,6 +235,8 @@ public void start() { "/isshieldedtrc20contractnotespent"); context.addServlet(new ServletHolder(getBurnTrxOnPBFTServlet), "/getburntrx"); + context.addServlet(new ServletHolder(getEnergyPricesOnPBFTServlet), + "/getenergyprices"); int maxHttpConnectNumber = Args.getInstance().getMaxHttpConnectNumber(); if (maxHttpConnectNumber > 0) { @@ -240,6 +248,10 @@ public void start() { context.addFilter(new FilterHolder(liteFnQueryHttpFilter), "/*", EnumSet.allOf(DispatcherType.class)); + // api access filter + context.addFilter(new FilterHolder(httpApiAccessFilter), "/*", + EnumSet.allOf(DispatcherType.class)); + server.start(); } catch (Exception e) { logger.debug("IOException: {}", e.getMessage()); diff --git a/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/RpcApiServiceOnSolidity.java b/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/RpcApiServiceOnSolidity.java index 05f5bc2bbed..71438de0670 100755 --- a/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/RpcApiServiceOnSolidity.java +++ b/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/RpcApiServiceOnSolidity.java @@ -43,6 +43,7 @@ import org.tron.core.services.RpcApiService; import org.tron.core.services.filter.LiteFnQueryGrpcInterceptor; import org.tron.core.services.ratelimiter.RateLimiterInterceptor; +import org.tron.core.services.ratelimiter.RpcApiAccessInterceptor; import org.tron.protos.Protocol.Account; import org.tron.protos.Protocol.Block; import org.tron.protos.Protocol.DynamicProperties; @@ -77,6 +78,9 @@ public class RpcApiServiceOnSolidity implements Service { @Autowired private LiteFnQueryGrpcInterceptor liteFnQueryGrpcInterceptor; + @Autowired + private RpcApiAccessInterceptor apiAccessInterceptor; + @Override public void init() { } @@ -105,12 +109,15 @@ public void start() { .flowControlWindow(parameter.getFlowControlWindow()) .maxConnectionIdle(parameter.getMaxConnectionIdleInMillis(), TimeUnit.MILLISECONDS) .maxConnectionAge(parameter.getMaxConnectionAgeInMillis(), TimeUnit.MILLISECONDS) - .maxMessageSize(parameter.getMaxMessageSize()) + .maxInboundMessageSize(parameter.getMaxMessageSize()) .maxHeaderListSize(parameter.getMaxHeaderListSize()); // add a ratelimiter interceptor serverBuilder.intercept(rateLimiterInterceptor); + // add api access interceptor + serverBuilder.intercept(apiAccessInterceptor); + // add lite fullnode query interceptor serverBuilder.intercept(liteFnQueryGrpcInterceptor); diff --git a/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/http/GetEnergyPricesOnSolidityServlet.java b/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/http/GetEnergyPricesOnSolidityServlet.java new file mode 100644 index 00000000000..b9d4fb765f6 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/http/GetEnergyPricesOnSolidityServlet.java @@ -0,0 +1,27 @@ +package org.tron.core.services.interfaceOnSolidity.http; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.core.services.http.GetEnergyPricesServlet; +import org.tron.core.services.interfaceOnSolidity.WalletOnSolidity; + + +@Component +@Slf4j(topic = "API") +public class GetEnergyPricesOnSolidityServlet extends GetEnergyPricesServlet { + + @Autowired + private WalletOnSolidity walletOnSolidity; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) { + walletOnSolidity.futureGet(() -> super.doGet(request, response)); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) { + walletOnSolidity.futureGet(() -> super.doPost(request, response)); + } +} + diff --git a/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/http/solidity/HttpApiOnSolidityService.java b/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/http/solidity/HttpApiOnSolidityService.java index 8165abbb275..2541773876a 100644 --- a/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/http/solidity/HttpApiOnSolidityService.java +++ b/framework/src/main/java/org/tron/core/services/interfaceOnSolidity/http/solidity/HttpApiOnSolidityService.java @@ -2,16 +2,19 @@ import java.util.EnumSet; import javax.servlet.DispatcherType; +import javax.servlet.Filter; import lombok.extern.slf4j.Slf4j; import org.eclipse.jetty.server.ConnectionLimit; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.springframework.beans.factory.annotation.Autowired; import org.tron.common.application.Service; import org.tron.common.parameter.CommonParameter; import org.tron.core.config.args.Args; +import org.tron.core.services.filter.HttpApiAccessFilter; import org.tron.core.services.filter.LiteFnQueryHttpFilter; import org.tron.core.services.interfaceOnSolidity.http.GetAccountByIdOnSolidityServlet; import org.tron.core.services.interfaceOnSolidity.http.GetAccountOnSolidityServlet; @@ -27,6 +30,7 @@ import org.tron.core.services.interfaceOnSolidity.http.GetBurnTrxOnSolidityServlet; import org.tron.core.services.interfaceOnSolidity.http.GetDelegatedResourceAccountIndexOnSolidityServlet; import org.tron.core.services.interfaceOnSolidity.http.GetDelegatedResourceOnSolidityServlet; +import org.tron.core.services.interfaceOnSolidity.http.GetEnergyPricesOnSolidityServlet; import org.tron.core.services.interfaceOnSolidity.http.GetExchangeByIdOnSolidityServlet; import org.tron.core.services.interfaceOnSolidity.http.GetMarketOrderByAccountOnSolidityServlet; import org.tron.core.services.interfaceOnSolidity.http.GetMarketOrderByIdOnSolidityServlet; @@ -143,10 +147,15 @@ public class HttpApiOnSolidityService implements Service { private GetMarketOrderListByPairOnSolidityServlet getMarketOrderListByPairOnSolidityServlet; @Autowired private GetMarketPairListOnSolidityServlet getMarketPairListOnSolidityServlet; + @Autowired + private GetEnergyPricesOnSolidityServlet getEnergyPricesOnSolidityServlet; @Autowired private LiteFnQueryHttpFilter liteFnQueryHttpFilter; + @Autowired + private HttpApiAccessFilter httpApiAccessFilter; + @Override public void init() { @@ -240,16 +249,27 @@ public void start() { "/walletsolidity/gettransactioncountbyblocknum"); context.addServlet(new ServletHolder(getNodeInfoOnSolidityServlet), "/wallet/getnodeinfo"); + context.addServlet(new ServletHolder(getNodeInfoOnSolidityServlet), + "/walletsolidity/getnodeinfo"); context.addServlet(new ServletHolder(getBrokerageServlet), "/walletsolidity/getBrokerage"); context.addServlet(new ServletHolder(getRewardServlet), "/walletsolidity/getReward"); context .addServlet(new ServletHolder(getBurnTrxOnSolidityServlet), "/walletsolidity/getburntrx"); + context.addServlet(new ServletHolder(getEnergyPricesOnSolidityServlet), + "/walletsolidity/getenergyprices"); // filters the specified APIs // when node is lite fullnode and openHistoryQueryWhenLiteFN is false context.addFilter(new FilterHolder(liteFnQueryHttpFilter), "/*", EnumSet.allOf(DispatcherType.class)); + // api access filter + context.addFilter(new FilterHolder(httpApiAccessFilter), "/walletsolidity/*", + EnumSet.allOf(DispatcherType.class)); + context.getServletHandler().getFilterMappings()[1] + .setPathSpecs(new String[] {"/walletsolidity/*", + "/wallet/getnodeinfo"}); + int maxHttpConnectNumber = Args.getInstance().getMaxHttpConnectNumber(); if (maxHttpConnectNumber > 0) { server.addBean(new ConnectionLimit(maxHttpConnectNumber, server)); diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/BuildArguments.java b/framework/src/main/java/org/tron/core/services/jsonrpc/BuildArguments.java new file mode 100644 index 00000000000..57f8798e0e3 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/BuildArguments.java @@ -0,0 +1,105 @@ +package org.tron.core.services.jsonrpc; + +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.addressHashToByteArray; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.paramQuantityIsNull; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.paramStringIsNull; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.parseQuantityValue; + +import com.google.protobuf.ByteString; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.apache.commons.lang3.StringUtils; +import org.tron.api.GrpcAPI.BytesMessage; +import org.tron.core.Wallet; +import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.contract.SmartContractOuterClass.SmartContract; + +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class BuildArguments { + + public String from; + public String to; + public String gas = "0x0"; + public String gasPrice = ""; //not used + public String value; + public String data; + public String nonce = ""; //not used + + public Long tokenId = 0L; + public Long tokenValue = 0L; + public String abi = ""; + public Long consumeUserResourcePercent = 0L; + public Long originEnergyLimit = 0L; + public String name = ""; + + public Integer permissionId = 0; + public String extraData = ""; + + public boolean visible = false; + + public BuildArguments(CallArguments args) { + from = args.from; + to = args.to; + gas = args.gas; + gasPrice = args.gasPrice; + value = args.value; + data = args.data; + } + + public ContractType getContractType(Wallet wallet) throws JsonRpcInvalidRequestException, + JsonRpcInvalidParamsException { + ContractType contractType; + + // to is null + if (paramStringIsNull(to)) { + // data is null + if (paramStringIsNull(data)) { + throw new JsonRpcInvalidRequestException("invalid json request"); + } + + contractType = ContractType.CreateSmartContract; + } else { + // to is not null + byte[] contractAddressData = addressHashToByteArray(to); + BytesMessage.Builder build = BytesMessage.newBuilder(); + BytesMessage bytesMessage = build.setValue(ByteString.copyFrom(contractAddressData)).build(); + SmartContract smartContract = wallet.getContract(bytesMessage); + + // check if to is smart contract + if (smartContract != null) { + contractType = ContractType.TriggerSmartContract; + } else { + // tokenId and tokenValue: trc10, value: TRX + if (availableTransferAsset()) { + contractType = ContractType.TransferAssetContract; + } else { + if (StringUtils.isNotEmpty(value)) { + contractType = ContractType.TransferContract; + } else { + throw new JsonRpcInvalidRequestException("invalid json request"); + } + } + } + } + + return contractType; + } + + public long parseValue() throws JsonRpcInvalidParamsException { + return parseQuantityValue(value); + } + + public long parseGas() throws JsonRpcInvalidParamsException { + return parseQuantityValue(gas); + } + + private boolean availableTransferAsset() { + return tokenId > 0 && tokenValue > 0 && paramQuantityIsNull(value); + } + +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/CallArguments.java b/framework/src/main/java/org/tron/core/services/jsonrpc/CallArguments.java new file mode 100644 index 00000000000..b7d8ae711d7 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/CallArguments.java @@ -0,0 +1,73 @@ +package org.tron.core.services.jsonrpc; + +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.addressHashToByteArray; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.paramStringIsNull; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.parseQuantityValue; + +import com.google.protobuf.ByteString; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.apache.commons.lang3.StringUtils; +import org.tron.api.GrpcAPI.BytesMessage; +import org.tron.core.Wallet; +import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.contract.SmartContractOuterClass.SmartContract; + +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class CallArguments { + + public String from; + public String to; + public String gas = ""; //not used + public String gasPrice = ""; //not used + public String value = ""; + public String data; + public String nonce; // not used + + /** + * just support TransferContract, CreateSmartContract and TriggerSmartContract + * */ + public ContractType getContractType(Wallet wallet) throws JsonRpcInvalidRequestException, + JsonRpcInvalidParamsException { + ContractType contractType; + + // from or to is null + if (paramStringIsNull(from)) { + throw new JsonRpcInvalidRequestException("invalid json request"); + } else if (paramStringIsNull(to)) { + // data is null + if (paramStringIsNull(data)) { + throw new JsonRpcInvalidRequestException("invalid json request"); + } + + contractType = ContractType.CreateSmartContract; + } else { + byte[] contractAddressData = addressHashToByteArray(to); + BytesMessage.Builder build = BytesMessage.newBuilder(); + BytesMessage bytesMessage = + build.setValue(ByteString.copyFrom(contractAddressData)).build(); + SmartContract smartContract = wallet.getContract(bytesMessage); + + // check if to is smart contract + if (smartContract != null) { + contractType = ContractType.TriggerSmartContract; + } else { + if (StringUtils.isNotEmpty(value)) { + contractType = ContractType.TransferContract; + } else { + throw new JsonRpcInvalidRequestException("invalid json request: invalid value"); + } + } + } + return contractType; + } + + public long parseValue() throws JsonRpcInvalidParamsException { + return parseQuantityValue(value); + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/FullNodeJsonRpcHttpService.java b/framework/src/main/java/org/tron/core/services/jsonrpc/FullNodeJsonRpcHttpService.java new file mode 100644 index 00000000000..b333397542c --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/FullNodeJsonRpcHttpService.java @@ -0,0 +1,76 @@ +package org.tron.core.services.jsonrpc; + +import java.util.EnumSet; +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.jetty.server.ConnectionLimit; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.common.application.Service; +import org.tron.common.parameter.CommonParameter; +import org.tron.core.services.filter.HttpInterceptor; + +@Component +@Slf4j(topic = "API") +public class FullNodeJsonRpcHttpService implements Service { + + private int port = CommonParameter.getInstance().getJsonRpcHttpFullNodePort(); + + private Server server; + + @Autowired + private JsonRpcServlet jsonRpcServlet; + + @Override + public void init() { + + } + + @Override + public void init(CommonParameter args) { + } + + @Override + public void start() { + try { + server = new Server(port); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + server.setHandler(context); + + context.addServlet(new ServletHolder(jsonRpcServlet), "/jsonrpc"); + + int maxHttpConnectNumber = CommonParameter.getInstance().getMaxHttpConnectNumber(); + if (maxHttpConnectNumber > 0) { + server.addBean(new ConnectionLimit(maxHttpConnectNumber, server)); + } + + // filter + ServletHandler handler = new ServletHandler(); + FilterHolder fh = handler + .addFilterWithMapping((Class) HttpInterceptor.class, "/*", + EnumSet.of(DispatcherType.REQUEST)); + context.addFilter(fh, "/*", EnumSet.of(DispatcherType.REQUEST)); + + server.start(); + + } catch (Exception e) { + logger.debug("IOException: {}", e.getMessage()); + } + } + + @Override + public void stop() { + try { + server.stop(); + } catch (Exception e) { + logger.debug("IOException: {}", e.getMessage()); + } + } +} diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java new file mode 100644 index 00000000000..c44f3f1911a --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java @@ -0,0 +1,465 @@ +package org.tron.core.services.jsonrpc; + +import com.google.common.base.Throwables; +import com.google.common.primitives.Longs; +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import org.tron.api.GrpcAPI.AssetIssueList; +import org.tron.common.crypto.Hash; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ByteUtil; +import org.tron.common.utils.DecodeUtil; +import org.tron.common.utils.Sha256Hash; +import org.tron.common.utils.StringUtil; +import org.tron.core.Wallet; +import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.protos.Protocol.Block; +import org.tron.protos.Protocol.Transaction; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.TransactionInfo; +import org.tron.protos.contract.AccountContract.AccountCreateContract; +import org.tron.protos.contract.AssetIssueContractOuterClass.AssetIssueContract; +import org.tron.protos.contract.AssetIssueContractOuterClass.AssetIssueContract.FrozenSupply; +import org.tron.protos.contract.AssetIssueContractOuterClass.ParticipateAssetIssueContract; +import org.tron.protos.contract.AssetIssueContractOuterClass.TransferAssetContract; +import org.tron.protos.contract.AssetIssueContractOuterClass.UnfreezeAssetContract; +import org.tron.protos.contract.BalanceContract.FreezeBalanceContract; +import org.tron.protos.contract.BalanceContract.TransferContract; +import org.tron.protos.contract.BalanceContract.UnfreezeBalanceContract; +import org.tron.protos.contract.ExchangeContract.ExchangeInjectContract; +import org.tron.protos.contract.ExchangeContract.ExchangeTransactionContract; +import org.tron.protos.contract.ExchangeContract.ExchangeWithdrawContract; +import org.tron.protos.contract.ShieldContract.ShieldedTransferContract; +import org.tron.protos.contract.SmartContractOuterClass.ClearABIContract; +import org.tron.protos.contract.SmartContractOuterClass.TriggerSmartContract; +import org.tron.protos.contract.SmartContractOuterClass.UpdateEnergyLimitContract; +import org.tron.protos.contract.SmartContractOuterClass.UpdateSettingContract; +import org.tron.protos.contract.VoteAssetContractOuterClass.VoteAssetContract; +import org.tron.protos.contract.WitnessContract.VoteWitnessContract; +import org.tron.protos.contract.WitnessContract.VoteWitnessContract.Vote; + +@Slf4j(topic = "API") +public class JsonRpcApiUtil { + public static byte[] convertToTronAddress(byte[] address) { + byte[] newAddress = new byte[21]; + byte[] temp = new byte[] {Wallet.getAddressPreFixByte()}; + System.arraycopy(temp, 0, newAddress, 0, temp.length); + + if (address.length <= 20) { + int start = 20 - address.length; + System.arraycopy(address, 0, newAddress, temp.length + start, address.length); + } else { + int start = address.length - 20; + System.arraycopy(address, start, newAddress, temp.length, 20); + } + return newAddress; + } + + public static String encode58Check(byte[] input) { + if (input == null || input.length == 0) { + return ""; + } + return StringUtil.encode58Check(input); + } + + public static String getMethodSign(String method) { + byte[] selector = new byte[4]; + System.arraycopy(Hash.sha3(method.getBytes()), 0, selector, 0, 4); + return Hex.toHexString(selector); + } + + public static TriggerSmartContract triggerCallContract(byte[] address, byte[] contractAddress, + long callValue, byte[] data, long tokenValue, String tokenId) { + TriggerSmartContract.Builder builder = TriggerSmartContract.newBuilder(); + + builder.setOwnerAddress(ByteString.copyFrom(address)); + builder.setContractAddress(ByteString.copyFrom(contractAddress)); + builder.setData(ByteString.copyFrom(data)); + builder.setCallValue(callValue); + + if (StringUtils.isNotEmpty(tokenId)) { + builder.setCallTokenValue(tokenValue); + builder.setTokenId(Long.parseLong(tokenId)); + } + + return builder.build(); + } + + public static String getBlockID(Block block) { + long blockNum = block.getBlockHeader().getRawData().getNumber(); + byte[] blockHash = Sha256Hash.of(true, block.getBlockHeader().getRawData().toByteArray()) + .getByteString().toByteArray(); + byte[] numBytes = Longs.toByteArray(blockNum); + byte[] hash = new byte[blockHash.length]; + System.arraycopy(numBytes, 0, hash, 0, 8); + System.arraycopy(blockHash, 8, hash, 8, blockHash.length - 8); + return "0x" + ByteArray.toHexString(hash); + } + + public static byte[] getToAddress(Transaction transaction) { + List toAddressList = getTo(transaction); + if (!toAddressList.isEmpty()) { + return toAddressList.get(0).toByteArray(); + } else { + return null; + } + } + + public static List getTo(Transaction transaction) { + Transaction.Contract contract = transaction.getRawData().getContract(0); + List list = new ArrayList<>(); + try { + Any contractParameter = contract.getParameter(); + switch (contract.getType()) { + case AccountCreateContract: + list.add(contractParameter.unpack(AccountCreateContract.class).getAccountAddress()); + break; + case TransferContract: + list.add(contractParameter.unpack(TransferContract.class).getToAddress()); + break; + case TransferAssetContract: + list.add(contractParameter.unpack(TransferAssetContract.class).getToAddress()); + break; + case VoteAssetContract: + list.addAll(contractParameter.unpack(VoteAssetContract.class).getVoteAddressList()); + break; + case VoteWitnessContract: + for (Vote vote : contractParameter.unpack(VoteWitnessContract.class).getVotesList()) { + list.add(vote.getVoteAddress()); + } + break; + case ParticipateAssetIssueContract: + list.add(contractParameter.unpack(ParticipateAssetIssueContract.class).getToAddress()); + break; + case FreezeBalanceContract: + ByteString receiverAddress = contractParameter.unpack(FreezeBalanceContract.class) + .getReceiverAddress(); + if (receiverAddress != null && !receiverAddress.isEmpty()) { + list.add(receiverAddress); + } + break; + case UnfreezeBalanceContract: + receiverAddress = contractParameter.unpack(UnfreezeBalanceContract.class) + .getReceiverAddress(); + if (receiverAddress != null && !receiverAddress.isEmpty()) { + list.add(receiverAddress); + } + break; + case TriggerSmartContract: + list.add(contractParameter.unpack(TriggerSmartContract.class).getContractAddress()); + break; + case UpdateSettingContract: + list.add(contractParameter.unpack(UpdateSettingContract.class).getContractAddress()); + break; + case UpdateEnergyLimitContract: + list.add(contractParameter.unpack(UpdateEnergyLimitContract.class).getContractAddress()); + break; + case ClearABIContract: + list.add(contractParameter.unpack(ClearABIContract.class).getContractAddress()); + break; + case ShieldedTransferContract: + ShieldedTransferContract shieldedTransferContract = contract.getParameter() + .unpack(ShieldedTransferContract.class); + if (!shieldedTransferContract.getTransparentToAddress().isEmpty()) { + list.add(shieldedTransferContract.getTransparentToAddress()); + } + break; + default: + break; + } + return list; + } catch (Exception ex) { + ex.printStackTrace(); + } catch (Throwable t) { + t.printStackTrace(); + } + return list; + } + + public static String getTxID(Transaction transaction) { + return ByteArray.toHexString(Sha256Hash.hash(true, transaction.getRawData().toByteArray())); + } + + public static long getTransactionAmount(Transaction.Contract contract, String hash, + Wallet wallet) { + long amount = 0; + try { + switch (contract.getType()) { + case UnfreezeBalanceContract: + case WithdrawBalanceContract: + TransactionInfo transactionInfo = wallet + .getTransactionInfoById(ByteString.copyFrom(ByteArray.fromHexString(hash))); + amount = getAmountFromTransactionInfo(hash, contract.getType(), transactionInfo); + break; + default: + amount = getTransactionAmount(contract, hash, 0, null, wallet); + break; + } + } catch (Exception e) { + logger.error("Exception happens when get amount. Exception = [{}]", + Throwables.getStackTraceAsString(e)); + } catch (Throwable t) { + t.printStackTrace(); + } + + return amount; + } + + public static long getTransactionAmount(Transaction.Contract contract, String hash, + long blockNum, TransactionInfo transactionInfo, Wallet wallet) { + long amount = 0; + try { + Any contractParameter = contract.getParameter(); + switch (contract.getType()) { + case TransferContract: + amount = contractParameter.unpack(TransferContract.class).getAmount(); + break; + case TransferAssetContract: + amount = contractParameter.unpack(TransferAssetContract.class).getAmount(); + break; + case VoteWitnessContract: + List votesList = contractParameter.unpack(VoteWitnessContract.class).getVotesList(); + long voteNumber = 0L; + for (Vote vote : votesList) { + voteNumber += vote.getVoteCount(); + } + amount = voteNumber; + break; + case WitnessCreateContract: + amount = 9999_000_000L; + break; + case AssetIssueContract: + case ExchangeCreateContract: + amount = 1024_000_000L; + break; + case ParticipateAssetIssueContract: + // long token = DataImporter.getTokenID(blockNum, + // contractParameter.unpack(ParticipateAssetIssueContract.class).getAssetName()); + // long trxNum = contractParameter.unpack(ParticipateAssetIssueContract.class) + // .getAmount(); + // Token10Entity entity = DataImporter.getTokenEntity(token); + // long exchangeAmount = Math.multiplyExact(trxNum, entity.getNum()); + // exchangeAmount = Math.floorDiv(exchangeAmount, entity.getTrxNum()); + // amount = exchangeAmount; + break; + case FreezeBalanceContract: + amount = contractParameter.unpack(FreezeBalanceContract.class).getFrozenBalance(); + break; + case TriggerSmartContract: + amount = contractParameter.unpack(TriggerSmartContract.class).getCallValue(); + break; + case ExchangeInjectContract: + amount = contractParameter.unpack(ExchangeInjectContract.class).getQuant(); + break; + case ExchangeWithdrawContract: + amount = contractParameter.unpack(ExchangeWithdrawContract.class).getQuant(); + break; + case ExchangeTransactionContract: + amount = contractParameter.unpack(ExchangeTransactionContract.class).getQuant(); + break; + case AccountPermissionUpdateContract: + amount = 100_000_000L; + break; + case ShieldedTransferContract: + ShieldedTransferContract shieldedTransferContract = contract.getParameter() + .unpack(ShieldedTransferContract.class); + if (shieldedTransferContract.getFromAmount() > 0L) { + amount = shieldedTransferContract.getFromAmount(); + } else if (shieldedTransferContract.getToAmount() > 0L) { + amount = shieldedTransferContract.getToAmount(); + } + break; + case UnfreezeBalanceContract: + case WithdrawBalanceContract: + amount = getAmountFromTransactionInfo(hash, contract.getType(), transactionInfo); + break; + case UnfreezeAssetContract: + amount = getUnfreezeAssetAmount(contractParameter.unpack(UnfreezeAssetContract.class) + .getOwnerAddress().toByteArray(), wallet); + break; + default: + } + } catch (Exception e) { + logger.error("Exception happens when get amount. Exception = [{}]", + Throwables.getStackTraceAsString(e)); + } catch (Throwable t) { + t.printStackTrace(); + } + return amount; + } + + public static long getAmountFromTransactionInfo(String hash, ContractType contractType, + TransactionInfo transactionInfo) { + long amount = 0L; + try { + + if (transactionInfo != null) { + + switch (contractType) { + case UnfreezeBalanceContract: + amount = transactionInfo.getUnfreezeAmount(); + break; + case WithdrawBalanceContract: + amount = transactionInfo.getWithdrawAmount(); + break; + case ExchangeInjectContract: + amount = transactionInfo.getExchangeInjectAnotherAmount(); + break; + case ExchangeWithdrawContract: + amount = transactionInfo.getExchangeWithdrawAnotherAmount(); + break; + case ExchangeTransactionContract: + amount = transactionInfo.getExchangeReceivedAmount(); + break; + default: + break; + } + } else { + logger.error("Can't find transaction {} ", hash); + } + } catch (Exception e) { + logger.warn("Exception happens when get amount from transactionInfo. Exception = [{}]", + Throwables.getStackTraceAsString(e)); + } catch (Throwable t) { + t.printStackTrace(); + } + return amount; + } + + public static long getUnfreezeAssetAmount(byte[] addressBytes, Wallet wallet) { + long amount = 0L; + try { + if (addressBytes == null) { + return amount; + } + + AssetIssueList assetIssueList = wallet + .getAssetIssueByAccount(ByteString.copyFrom(addressBytes)); + if (assetIssueList != null) { + if (assetIssueList.getAssetIssueCount() != 1) { + return amount; + } else { + AssetIssueContract assetIssue = assetIssueList.getAssetIssue(0); + Iterator iterator = assetIssue.getFrozenSupplyList().iterator(); + while (iterator.hasNext()) { + FrozenSupply frozenSupply = iterator.next(); + amount += frozenSupply.getFrozenAmount(); + } + } + } + } catch (Exception e) { + logger.warn("Exception happens when get token10 frozenAmount. Exception = [{}]", + Throwables.getStackTraceAsString(e)); + } + return amount; + } + + public static byte[] addressHashToByteArray(String hash) throws JsonRpcInvalidParamsException { + byte[] bHash; + try { + bHash = ByteArray.fromHexString(hash); + if (bHash.length != DecodeUtil.ADDRESS_SIZE / 2 + && bHash.length != DecodeUtil.ADDRESS_SIZE / 2 - 1) { + throw new JsonRpcInvalidParamsException("invalid address hash value"); + } + + if (bHash.length == DecodeUtil.ADDRESS_SIZE / 2 - 1) { + bHash = ByteUtil.merge(new byte[] {DecodeUtil.addressPreFixByte}, bHash); + } + } catch (Exception e) { + throw new JsonRpcInvalidParamsException(e.getMessage()); + } + return bHash; + } + + public static boolean paramStringIsNull(String string) { + return StringUtils.isEmpty(string) || string.equals("0x"); + } + + public static boolean paramQuantityIsNull(String quantity) { + return StringUtils.isEmpty(quantity) || quantity.equals("0x0"); + } + + public static long parseQuantityValue(String value) throws JsonRpcInvalidParamsException { + long callValue = 0L; + + if (StringUtils.isNotEmpty(value)) { + try { + callValue = ByteArray.jsonHexToLong(value); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid param value: invalid hex number"); + } + } + + return callValue; + } + + public static long getEnergyUsageTotal(Transaction transaction, Wallet wallet) { + long energyUsageTotal = 0; + + byte[] txHash = Sha256Hash + .hash(CommonParameter.getInstance().isECKeyCryptoEngine(), + transaction.getRawData().toByteArray()); + TransactionInfo transactionInfo = wallet + .getTransactionInfoById(ByteString.copyFrom(txHash)); + if (transactionInfo != null) { + energyUsageTotal = transactionInfo.getReceipt().getEnergyUsageTotal(); + } + + return energyUsageTotal; + } + + public static long getEnergyUsageTotal(List transactionInfoList, int i, + long blockNum) { + long energyUsageTotal = 0; + + if (!transactionInfoList.isEmpty()) { + try { + energyUsageTotal = transactionInfoList.get(i).getReceipt().getEnergyUsageTotal(); + } catch (Exception e) { + logger.warn( + "getBlockResult cannot get energy from transactionInfo, block.num={}, error is {}", + blockNum, e.getMessage()); + } + } + + return energyUsageTotal; + } + + public static int getTransactionIndex(String txId, List txList) { + int transactionIndex = -1; + Transaction transaction; + + for (int index = 0; index < txList.size(); index++) { + transaction = txList.get(index); + if (getTxID(transaction).equals(txId)) { + transactionIndex = index; + break; + } + } + + return transactionIndex; + } + + public static long parseEnergyFee(long timestamp, String energyPriceHistory) { + String[] priceList = energyPriceHistory.split(","); + + for (int i = priceList.length - 1; i >= 0; i--) { + String[] priceArray = priceList[i].split(":"); + long time = Long.parseLong(priceArray[0]); + long price = Long.parseLong(priceArray[1]); + if (timestamp > time) { + return price; + } + } + + return -1; + } +} diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java new file mode 100644 index 00000000000..2b5387f6149 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java @@ -0,0 +1,65 @@ +package org.tron.core.services.jsonrpc; + +import com.googlecode.jsonrpc4j.HttpStatusCodeProvider; +import com.googlecode.jsonrpc4j.JsonRpcServer; +import com.googlecode.jsonrpc4j.ProxyUtil; +import java.io.IOException; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.tron.core.Wallet; +import org.tron.core.db.Manager; +import org.tron.core.services.NodeInfoService; +import org.tron.core.services.http.RateLimiterServlet; + +@Component +@Slf4j(topic = "API") +public class JsonRpcServlet extends RateLimiterServlet { + + private JsonRpcServer rpcServer = null; + + @Autowired + private NodeInfoService nodeInfoService; + @Autowired + private Wallet wallet; + @Autowired + private Manager manager; + + // @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + TronJsonRpcImpl jsonRpcImpl = new TronJsonRpcImpl(nodeInfoService, wallet, manager); + Object compositeService = ProxyUtil.createCompositeServiceProxy( + cl, + new Object[] {jsonRpcImpl}, + new Class[] {TronJsonRpc.class}, + true); + + rpcServer = new JsonRpcServer(compositeService); + + HttpStatusCodeProvider httpStatusCodeProvider = new HttpStatusCodeProvider() { + @Override + public int getHttpStatusCode(int resultCode) { + return 200; + } + + @Override + public Integer getJsonRpcCode(int httpStatusCode) { + return null; + } + }; + rpcServer.setHttpStatusCodeProvider(httpStatusCodeProvider); + + rpcServer.setShouldLogInvocationErrors(false); + } + + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + rpcServer.handle(req, resp); + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TransactionReceipt.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TransactionReceipt.java new file mode 100644 index 00000000000..b1f9d6d9fe0 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TransactionReceipt.java @@ -0,0 +1,141 @@ +package org.tron.core.services.jsonrpc; + +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.convertToTronAddress; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getToAddress; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.ArrayList; +import java.util.List; +import org.tron.api.GrpcAPI.TransactionInfoList; +import org.tron.common.utils.ByteArray; +import org.tron.core.Wallet; +import org.tron.core.capsule.BlockCapsule; +import org.tron.core.capsule.TransactionCapsule; +import org.tron.protos.Protocol; +import org.tron.protos.Protocol.ResourceReceipt; +import org.tron.protos.Protocol.Transaction.Contract; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.TransactionInfo; + +@JsonPropertyOrder(alphabetic = true) +public class TransactionReceipt { + + @JsonPropertyOrder(alphabetic = true) + public static class TransactionLog { + + public String logIndex; + public String blockHash; + public String blockNumber; + public String transactionIndex; + public String transactionHash; + public String address; + public String data; + public String[] topics; + public boolean removed = false; + + public TransactionLog() { + } + } + + public String blockHash; + public String blockNumber; + public String transactionIndex; + public String transactionHash; + public String from; + public String to; + + public String cumulativeGasUsed; + public String effectiveGasPrice; + public String gasUsed; + public String contractAddress; + public TransactionLog[] logs; + public String logsBloom; + @JsonInclude(JsonInclude.Include.NON_NULL) + public String root; // 32 bytes of post-transaction stateroot (pre Byzantium) + @JsonInclude(JsonInclude.Include.NON_NULL) + public String status; // either 1 (success) or 0 (failure) (post Byzantium) + + public String type = "0x0"; + + public TransactionReceipt(Protocol.Block block, TransactionInfo txInfo, Wallet wallet) { + BlockCapsule blockCapsule = new BlockCapsule(block); + String txid = ByteArray.toHexString(txInfo.getId().toByteArray()); + long blockNum = blockCapsule.getNum(); + + Protocol.Transaction transaction = null; + long cumulativeGas = 0; + long cumulativeLogCount = 0; + + TransactionInfoList infoList = wallet.getTransactionInfoByBlockNum(blockNum); + for (int index = 0; index < infoList.getTransactionInfoCount(); index++) { + TransactionInfo info = infoList.getTransactionInfo(index); + ResourceReceipt resourceReceipt = info.getReceipt(); + + long energyUsage = resourceReceipt.getEnergyUsageTotal(); + cumulativeGas += energyUsage; + + if (ByteArray.toHexString(info.getId().toByteArray()).equals(txid)) { + transactionIndex = ByteArray.toJsonHex(index); + cumulativeGasUsed = ByteArray.toJsonHex(cumulativeGas); + gasUsed = ByteArray.toJsonHex(energyUsage); + status = resourceReceipt.getResultValue() <= 1 ? "0x1" : "0x0"; + + transaction = block.getTransactions(index); + break; + } else { + cumulativeLogCount += info.getLogCount(); + } + } + + blockHash = ByteArray.toJsonHex(blockCapsule.getBlockId().getBytes()); + blockNumber = ByteArray.toJsonHex(blockCapsule.getNum()); + transactionHash = ByteArray.toJsonHex(txInfo.getId().toByteArray()); + effectiveGasPrice = ByteArray.toJsonHex(wallet.getEnergyFee(blockCapsule.getTimeStamp())); + + from = null; + to = null; + contractAddress = null; + + if (transaction != null && !transaction.getRawData().getContractList().isEmpty()) { + Contract contract = transaction.getRawData().getContract(0); + byte[] fromByte = TransactionCapsule.getOwner(contract); + byte[] toByte = getToAddress(transaction); + from = ByteArray.toJsonHexAddress(fromByte); + to = ByteArray.toJsonHexAddress(toByte); + + if (contract.getType() == ContractType.CreateSmartContract) { + contractAddress = ByteArray.toJsonHexAddress(txInfo.getContractAddress().toByteArray()); + } + } + + // logs + List logList = new ArrayList<>(); + for (int index = 0; index < txInfo.getLogCount(); index++) { + TransactionInfo.Log log = txInfo.getLogList().get(index); + + TransactionReceipt.TransactionLog transactionLog = new TransactionReceipt.TransactionLog(); + // index is the index in the block + transactionLog.logIndex = ByteArray.toJsonHex(index + cumulativeLogCount); + transactionLog.transactionHash = transactionHash; + transactionLog.transactionIndex = transactionIndex; + transactionLog.blockHash = blockHash; + transactionLog.blockNumber = blockNumber; + byte[] addressByte = convertToTronAddress(log.getAddress().toByteArray()); + transactionLog.address = ByteArray.toJsonHexAddress(addressByte); + transactionLog.data = ByteArray.toJsonHex(log.getData().toByteArray()); + + String[] topics = new String[log.getTopicsCount()]; + for (int i = 0; i < log.getTopicsCount(); i++) { + topics[i] = ByteArray.toJsonHex(log.getTopics(i).toByteArray()); + } + transactionLog.topics = topics; + + logList.add(transactionLog); + } + + logs = logList.toArray(new TransactionReceipt.TransactionLog[logList.size()]); + logsBloom = ByteArray.toJsonHex(new byte[256]); // no value + root = null; + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TransactionResult.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TransactionResult.java new file mode 100644 index 00000000000..828fb95426e --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TransactionResult.java @@ -0,0 +1,119 @@ +package org.tron.core.services.jsonrpc; + +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getToAddress; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getTransactionAmount; + +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.google.protobuf.ByteString; +import java.util.Arrays; +import lombok.ToString; +import org.tron.common.utils.ByteArray; +import org.tron.core.Wallet; +import org.tron.core.capsule.BlockCapsule; +import org.tron.core.capsule.TransactionCapsule; +import org.tron.protos.Protocol; +import org.tron.protos.Protocol.Transaction; +import org.tron.protos.Protocol.Transaction.Contract; + +@JsonPropertyOrder(alphabetic = true) +@ToString +public class TransactionResult { + + public String hash; + public String nonce; + public String blockHash; + public String blockNumber; + public String transactionIndex; + + public String from; + public String to; + public String gas; + public String gasPrice; + public String value; + public String input; + + public String v; + public String r; + public String s; + + public String type = "0x0"; + + private void parseSignature(Transaction tx) { + + if (tx.getSignatureCount() == 0) { + v = null; + r = null; + s = null; + return; + } + + ByteString signature = tx.getSignature(0); // r[32] + s[32] + v[1] + byte[] signData = signature.toByteArray(); + byte[] rByte = Arrays.copyOfRange(signData, 0, 32); + byte[] sByte = Arrays.copyOfRange(signData, 32, 64); + byte vByte = signData[64]; + if (vByte < 27) { + vByte += 27; + } + v = ByteArray.toJsonHex(vByte); + r = ByteArray.toJsonHex(rByte); + s = ByteArray.toJsonHex(sByte); + } + + public TransactionResult(BlockCapsule blockCapsule, int index, Protocol.Transaction tx, + long energyUsageTotal, long energyFee, Wallet wallet) { + byte[] txId = new TransactionCapsule(tx).getTransactionId().getBytes(); + hash = ByteArray.toJsonHex(txId); + nonce = null; // no value + blockHash = ByteArray.toJsonHex(blockCapsule.getBlockId().getBytes()); + blockNumber = ByteArray.toJsonHex(blockCapsule.getNum()); + transactionIndex = ByteArray.toJsonHex(index); + + if (!tx.getRawData().getContractList().isEmpty()) { + Contract contract = tx.getRawData().getContract(0); + byte[] fromByte = TransactionCapsule.getOwner(contract); + byte[] toByte = getToAddress(tx); + from = ByteArray.toJsonHexAddress(fromByte); + to = ByteArray.toJsonHexAddress(toByte); + value = ByteArray.toJsonHex(getTransactionAmount(contract, hash, wallet)); + } else { + from = null; + to = null; + value = null; + } + + gas = ByteArray.toJsonHex(energyUsageTotal); + gasPrice = ByteArray.toJsonHex(energyFee); + input = ByteArray.toJsonHex(tx.getRawData().getData().toByteArray()); + + parseSignature(tx); + } + + public TransactionResult(Transaction tx, Wallet wallet) { + byte[] txid = new TransactionCapsule(tx).getTransactionId().getBytes(); + hash = ByteArray.toJsonHex(txid); + nonce = null; // no value + blockHash = "0x"; + blockNumber = "0x"; + transactionIndex = "0x"; + + if (!tx.getRawData().getContractList().isEmpty()) { + Contract contract = tx.getRawData().getContract(0); + byte[] fromByte = TransactionCapsule.getOwner(contract); + byte[] toByte = getToAddress(tx); + from = ByteArray.toJsonHexAddress(fromByte); + to = ByteArray.toJsonHexAddress(toByte); + value = ByteArray.toJsonHex(getTransactionAmount(contract, hash, wallet)); + } else { + from = null; + to = null; + value = null; + } + + gas = "0x0"; + gasPrice = "0x"; + input = ByteArray.toJsonHex(tx.getRawData().getData().toByteArray()); + + parseSignature(tx); + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java new file mode 100644 index 00000000000..efb40cc680f --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java @@ -0,0 +1,338 @@ +package org.tron.core.services.jsonrpc; + +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.googlecode.jsonrpc4j.JsonRpcError; +import com.googlecode.jsonrpc4j.JsonRpcErrors; +import com.googlecode.jsonrpc4j.JsonRpcMethod; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.ToString; +import lombok.Value; +import org.springframework.stereotype.Component; +import org.tron.core.exception.JsonRpcInternalException; +import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.core.exception.JsonRpcMethodNotFoundException; + +@Component +public interface TronJsonRpc { + + @Value + @AllArgsConstructor + @ToString + class SyncingResult { + + private final String startingBlock; + private final String currentBlock; + private final String highestBlock; + } + + @JsonPropertyOrder(alphabetic = true) + class BlockResult { + + public String number; + public String hash; + public String parentHash; + public String nonce; + public String sha3Uncles; + public String logsBloom; + public String transactionsRoot; + public String stateRoot; + public String receiptsRoot; + public String miner; + public String difficulty; + public String totalDifficulty; + public String extraData; + public String size; + public String gasLimit; + public String gasUsed; + public String timestamp; + public Object[] transactions; //TransactionResult or byte32 + public String[] uncles; + + public String baseFeePerGas = null; + public String mixHash = null; + } + + class CompilationResult { + + public String code; + public CompilationInfo info; + + @Override + public String toString() { + return "CompilationResult{" + + "code='" + code + '\'' + + ", info=" + info + + '}'; + } + } + + class CompilationInfo { + + public String source; + public String language; + public String languageVersion; + public String compilerVersion; + // public CallTransaction.Function[] abiDefinition; + public String userDoc; + public String developerDoc; + + @Override + public String toString() { + return "CompilationInfo{" + + "source='" + source + '\'' + + ", language='" + language + '\'' + + ", languageVersion='" + languageVersion + '\'' + + ", compilerVersion='" + compilerVersion + '\'' + // + ", abiDefinition=" + abiDefinition + '\'' + + ", userDoc='" + userDoc + '\'' + + ", developerDoc='" + developerDoc + '\'' + + '}'; + } + } + + class TransactionJson { + + public JSONObject transaction; + } + + @JsonRpcMethod("web3_clientVersion") + String web3ClientVersion(); + + @JsonRpcMethod("web3_sha3") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + String web3Sha3(String data) throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getBlockTransactionCountByHash") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + String ethGetBlockTransactionCountByHash(String blockHash) throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getBlockTransactionCountByNumber") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + String ethGetBlockTransactionCountByNumber(String bnOrId) throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getBlockByHash") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + BlockResult ethGetBlockByHash(String blockHash, Boolean fullTransactionObjects) + throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getBlockByNumber") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + BlockResult ethGetBlockByNumber(String bnOrId, Boolean fullTransactionObjects) + throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("net_version") + String getNetVersion() throws JsonRpcInternalException; + + @JsonRpcMethod("eth_chainId") + String ethChainId() throws JsonRpcInternalException; + + @JsonRpcMethod("net_listening") + boolean isListening(); + + @JsonRpcMethod("eth_protocolVersion") + String getProtocolVersion(); + + @JsonRpcMethod("eth_blockNumber") + String getLatestBlockNum(); + + @JsonRpcMethod("eth_getBalance") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + String getTrxBalance(String address, String blockNumOrTag) throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getStorageAt") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + String getStorageAt(String address, String storageIdx, String blockNumOrTag) + throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getCode") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + String getABIOfSmartContract(String contractAddress, String bnOrId) + throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_coinbase") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInternalException.class, code = -32000, data = "{}"), + }) + String getCoinbase() throws JsonRpcInternalException; + + @JsonRpcMethod("eth_gasPrice") + String gasPrice(); + + @JsonRpcMethod("eth_estimateGas") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidRequestException.class, code = -32600, data = "{}"), + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + @JsonRpcError(exception = JsonRpcInternalException.class, code = -32000, data = "{}"), + }) + String estimateGas(CallArguments args) throws JsonRpcInvalidRequestException, + JsonRpcInvalidParamsException, JsonRpcInternalException; + + @JsonRpcMethod("eth_getTransactionByHash") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + TransactionResult getTransactionByHash(String txId) throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getTransactionByBlockHashAndIndex") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + TransactionResult getTransactionByBlockHashAndIndex(String blockHash, String index) + throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getTransactionByBlockNumberAndIndex") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + TransactionResult getTransactionByBlockNumberAndIndex(String blockNumOrTag, String index) + throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_getTransactionReceipt") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + TransactionReceipt getTransactionReceipt(String txid) throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("eth_call") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + }) + String getCall(CallArguments transactionCall, String blockNumOrTag) + throws JsonRpcInvalidParamsException; + + @JsonRpcMethod("net_peerCount") + String getPeerCount(); + + @JsonRpcMethod("eth_syncing") + Object getSyncingStatus(); + + @JsonRpcMethod("eth_getUncleByBlockHashAndIndex") + BlockResult getUncleByBlockHashAndIndex(String blockHash, String index); + + @JsonRpcMethod("eth_getUncleByBlockNumberAndIndex") + BlockResult getUncleByBlockNumberAndIndex(String blockNumOrTag, String index); + + @JsonRpcMethod("eth_getUncleCountByBlockHash") + String getUncleCountByBlockHash(String blockHash); + + @JsonRpcMethod("eth_getUncleCountByBlockNumber") + String getUncleCountByBlockNumber(String blockNumOrTag); + + @JsonRpcMethod("eth_getWork") + List ethGetWork(); + + @JsonRpcMethod("eth_hashrate") + String getHashRate(); + + @JsonRpcMethod("eth_mining") + boolean isMining(); + + @JsonRpcMethod("eth_accounts") + String[] getAccounts(); + + @JsonRpcMethod("buildTransaction") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidRequestException.class, code = -32600, data = "{}"), + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + @JsonRpcError(exception = JsonRpcInternalException.class, code = -32000, data = "{}"), + }) + TransactionJson buildTransaction(BuildArguments args) + throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + JsonRpcInternalException, JsonRpcMethodNotFoundException; + + // not supported + @JsonRpcMethod("eth_submitWork") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + boolean ethSubmitWork(String nonce, String header, String digest) + throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_sendRawTransaction") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + String ethSendRawTransaction(String rawData) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_sendTransaction") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + String ethSendTransaction(CallArguments transactionArgs) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_sign") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + String ethSign(String addr, String data) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_signTransaction") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + String ethSignTransaction(CallArguments transactionArgs) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("parity_nextNonce") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + String parityNextNonce(String address) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_getTransactionCount") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + String getSendTransactionCountOfAddress(String address, String blockNumOrTag) + throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_getCompilers") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + String[] getCompilers() throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_compileSolidity") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + CompilationResult ethCompileSolidity(String contract) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_compileLLL") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + CompilationResult ethCompileLLL(String contract) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_compileSerpent") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + CompilationResult ethCompileSerpent(String contract) throws JsonRpcMethodNotFoundException; + + @JsonRpcMethod("eth_submitHashrate") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcMethodNotFoundException.class, code = -32601, data = "{}"), + }) + CompilationResult ethSubmitHashrate(String hashrate, String id) + throws JsonRpcMethodNotFoundException; +} diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java new file mode 100644 index 00000000000..80d63382d2b --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -0,0 +1,1024 @@ +package org.tron.core.services.jsonrpc; + +import static org.tron.core.Wallet.CONTRACT_VALIDATE_ERROR; +import static org.tron.core.Wallet.CONTRACT_VALIDATE_EXCEPTION; +import static org.tron.core.services.http.Util.setTransactionExtraData; +import static org.tron.core.services.http.Util.setTransactionPermissionId; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.addressHashToByteArray; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getEnergyUsageTotal; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getTransactionIndex; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getTxID; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.triggerCallContract; + +import com.alibaba.fastjson.JSON; +import com.google.protobuf.ByteString; +import com.google.protobuf.GeneratedMessageV3; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.tron.api.GrpcAPI.BytesMessage; +import org.tron.api.GrpcAPI.Return; +import org.tron.api.GrpcAPI.Return.response_code; +import org.tron.api.GrpcAPI.TransactionExtention; +import org.tron.common.crypto.Hash; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.runtime.vm.DataWord; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ByteUtil; +import org.tron.common.utils.Sha256Hash; +import org.tron.core.Wallet; +import org.tron.core.capsule.BlockCapsule; +import org.tron.core.capsule.TransactionCapsule; +import org.tron.core.db.Manager; +import org.tron.core.db2.core.Chainbase; +import org.tron.core.exception.ContractExeException; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.HeaderNotFound; +import org.tron.core.exception.JsonRpcInternalException; +import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.core.exception.JsonRpcMethodNotFoundException; +import org.tron.core.exception.VMIllegalException; +import org.tron.core.services.NodeInfoService; +import org.tron.core.services.http.JsonFormat; +import org.tron.core.services.http.Util; +import org.tron.core.store.StorageRowStore; +import org.tron.core.vm.config.VMConfig; +import org.tron.core.vm.program.Storage; +import org.tron.program.Version; +import org.tron.protos.Protocol.Account; +import org.tron.protos.Protocol.Block; +import org.tron.protos.Protocol.Transaction; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.TransactionInfo; +import org.tron.protos.contract.AssetIssueContractOuterClass.TransferAssetContract; +import org.tron.protos.contract.BalanceContract.TransferContract; +import org.tron.protos.contract.SmartContractOuterClass.CreateSmartContract; +import org.tron.protos.contract.SmartContractOuterClass.SmartContract; +import org.tron.protos.contract.SmartContractOuterClass.SmartContract.ABI; +import org.tron.protos.contract.SmartContractOuterClass.SmartContractDataWrapper; +import org.tron.protos.contract.SmartContractOuterClass.TriggerSmartContract; + +@Slf4j(topic = "API") +public class TronJsonRpcImpl implements TronJsonRpc { + + public enum RequestSource { + FULLNODE, + SOLIDITY, + PBFT + } + + String regexHash = "(0x)?[a-zA-Z0-9]{64}$"; + private final int chainId = 100; + private final int networkId = 100; + + private NodeInfoService nodeInfoService; + private Wallet wallet; + private Manager manager; + + public TronJsonRpcImpl(NodeInfoService nodeInfoService, Wallet wallet, Manager manager) { + this.nodeInfoService = nodeInfoService; + this.wallet = wallet; + this.manager = manager; + } + + @Override + public String web3ClientVersion() { + Pattern shortVersion = Pattern.compile("(\\d\\.\\d).*"); + Matcher matcher = shortVersion.matcher(System.getProperty("java.version")); + matcher.matches(); + + return Arrays.asList( + "TRON", "v" + Version.getVersion(), + System.getProperty("os.name"), + "Java" + matcher.group(1), + Version.VERSION_NAME).stream() + .collect(Collectors.joining("/")); + } + + @Override + public String web3Sha3(String data) throws JsonRpcInvalidParamsException { + byte[] input; + try { + input = ByteArray.fromHexString(data); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid input value"); + } + + byte[] result = Hash.sha3(input); + return ByteArray.toJsonHex(result); + } + + @Override + public String ethGetBlockTransactionCountByHash(String blockHash) + throws JsonRpcInvalidParamsException { + Block b = getBlockByJsonHash(blockHash); + if (b == null) { + return null; + } + + long n = b.getTransactionsList().size(); + return ByteArray.toJsonHex(n); + } + + @Override + public String ethGetBlockTransactionCountByNumber(String blockNumOrTag) + throws JsonRpcInvalidParamsException { + List list = wallet.getTransactionsByJsonBlockId(blockNumOrTag); + if (list == null) { + return null; + } + + long n = list.size(); + return ByteArray.toJsonHex(n); + } + + @Override + public BlockResult ethGetBlockByHash(String blockHash, Boolean fullTransactionObjects) + throws JsonRpcInvalidParamsException { + final Block b = getBlockByJsonHash(blockHash); + return getBlockResult(b, fullTransactionObjects); + } + + @Override + public BlockResult ethGetBlockByNumber(String blockNumOrTag, Boolean fullTransactionObjects) + throws JsonRpcInvalidParamsException { + final Block b = wallet.getByJsonBlockId(blockNumOrTag); + return (b == null ? null : getBlockResult(b, fullTransactionObjects)); + } + + private byte[] hashToByteArray(String hash) throws JsonRpcInvalidParamsException { + if (!Pattern.matches(regexHash, hash)) { + throw new JsonRpcInvalidParamsException("invalid hash value"); + } + + byte[] bHash; + try { + bHash = ByteArray.fromHexString(hash); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException(e.getMessage()); + } + return bHash; + } + + private Block getBlockByJsonHash(String blockHash) throws JsonRpcInvalidParamsException { + byte[] bHash = hashToByteArray(blockHash); + return wallet.getBlockById(ByteString.copyFrom(bHash)); + } + + private BlockResult getBlockResult(Block block, boolean fullTx) { + if (block == null) { + return null; + } + + BlockCapsule blockCapsule = new BlockCapsule(block); + BlockResult br = new BlockResult(); + br.number = ByteArray.toJsonHex(blockCapsule.getNum()); + br.hash = ByteArray.toJsonHex(blockCapsule.getBlockId().getBytes()); + br.parentHash = ByteArray.toJsonHex(blockCapsule.getParentBlockId().getBytes()); + br.nonce = null; // no value + br.sha3Uncles = null; // no value + br.logsBloom = ByteArray.toJsonHex(new byte[256]); // no value + br.transactionsRoot = ByteArray + .toJsonHex(block.getBlockHeader().getRawData().getTxTrieRoot().toByteArray()); + br.stateRoot = ByteArray + .toJsonHex(block.getBlockHeader().getRawData().getAccountStateRoot().toByteArray()); + br.receiptsRoot = null; // no value + br.miner = ByteArray.toJsonHexAddress(blockCapsule.getWitnessAddress().toByteArray()); + br.difficulty = null; // no value + br.totalDifficulty = null; // no value + br.extraData = null; // no value + br.size = ByteArray.toJsonHex(block.getSerializedSize()); + br.timestamp = ByteArray.toJsonHex(blockCapsule.getTimeStamp()); + + long gasUsedInBlock = 0; + long gasLimitInBlock = 0; + + List txes = new ArrayList<>(); + List transactionsList = block.getTransactionsList(); + List transactionInfoList = + wallet.getTransactionInfoByBlockNum(blockCapsule.getNum()).getTransactionInfoList(); + if (fullTx) { + long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp()); + + for (int i = 0; i < transactionsList.size(); i++) { + Transaction transaction = transactionsList.get(i); + gasLimitInBlock += transaction.getRawData().getFeeLimit(); + + long energyUsageTotal = getEnergyUsageTotal(transactionInfoList, i, blockCapsule.getNum()); + gasUsedInBlock += energyUsageTotal; + + txes.add(new TransactionResult(blockCapsule, i, transaction, + energyUsageTotal, energyFee, wallet)); + } + } else { + for (int i = 0; i < transactionsList.size(); i++) { + gasLimitInBlock += transactionsList.get(i).getRawData().getFeeLimit(); + gasUsedInBlock += getEnergyUsageTotal(transactionInfoList, i, blockCapsule.getNum()); + + byte[] txHash = Sha256Hash + .hash(CommonParameter.getInstance().isECKeyCryptoEngine(), + transactionsList.get(i).getRawData().toByteArray()); + txes.add(ByteArray.toJsonHex(txHash)); + } + } + br.transactions = txes.toArray(); + + br.gasLimit = ByteArray.toJsonHex(gasLimitInBlock); + br.gasUsed = ByteArray.toJsonHex(gasUsedInBlock); + List ul = new ArrayList<>(); + br.uncles = ul.toArray(new String[0]); + + return br; + } + + @Override + public String getNetVersion() throws JsonRpcInternalException { + return ethChainId(); + } + + @Override + public String ethChainId() throws JsonRpcInternalException { + // return hash of genesis block + try { + byte[] chainId = wallet.getBlockCapsuleByNum(0).getBlockId().getBytes(); + return ByteArray.toJsonHex(Arrays.copyOfRange(chainId, chainId.length - 4, chainId.length)); + } catch (Exception e) { + throw new JsonRpcInternalException(e.getMessage()); + } + } + + @Override + public boolean isListening() { + int activeConnectCount = nodeInfoService.getNodeInfo().getActiveConnectCount(); + return activeConnectCount >= 1; + } + + @Override + public String getProtocolVersion() { + return ByteArray.toJsonHex(wallet.getNowBlock().getBlockHeader().getRawData().getVersion()); + } + + @Override + public String getLatestBlockNum() { + return ByteArray.toJsonHex(wallet.getNowBlock().getBlockHeader().getRawData().getNumber()); + } + + @Override + public String getTrxBalance(String address, String blockNumOrTag) + throws JsonRpcInvalidParamsException { + if ("earliest".equalsIgnoreCase(blockNumOrTag) + || "pending".equalsIgnoreCase(blockNumOrTag)) { + throw new JsonRpcInvalidParamsException("TAG [earliest | pending] not supported"); + } else if ("latest".equalsIgnoreCase(blockNumOrTag)) { + byte[] addressData = addressHashToByteArray(address); + + Account account = Account.newBuilder().setAddress(ByteString.copyFrom(addressData)).build(); + Account reply = wallet.getAccount(account); + long balance = 0; + + if (reply != null) { + balance = reply.getBalance(); + } + return ByteArray.toJsonHex(balance); + } else { + try { + ByteArray.hexToBigInteger(blockNumOrTag); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid block number"); + } + + throw new JsonRpcInvalidParamsException("QUANTITY not supported, just support TAG as latest"); + } + } + + private void callTriggerConstantContract(byte[] ownerAddressByte, byte[] contractAddressByte, + long value, byte[] data, TransactionExtention.Builder trxExtBuilder, + Return.Builder retBuilder) + throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException { + + TriggerSmartContract triggerContract = triggerCallContract( + ownerAddressByte, + contractAddressByte, + value, + data, + 0, + null + ); + + TransactionCapsule trxCap = wallet.createTransactionCapsule(triggerContract, + ContractType.TriggerSmartContract); + Transaction trx = + wallet.triggerConstantContract(triggerContract, trxCap, trxExtBuilder, retBuilder); + + trxExtBuilder.setTransaction(trx); + trxExtBuilder.setTxid(trxCap.getTransactionId().getByteString()); + trxExtBuilder.setResult(retBuilder); + retBuilder.setResult(true).setCode(response_code.SUCCESS); + } + + /** + * @param data Hash of the method signature and encoded parameters. for example: + * getMethodSign(methodName(uint256,uint256)) || data1 || data2 + */ + private String call(byte[] ownerAddressByte, byte[] contractAddressByte, byte[] data) { + + TransactionExtention.Builder trxExtBuilder = TransactionExtention.newBuilder(); + Return.Builder retBuilder = Return.newBuilder(); + TransactionExtention trxExt; + + try { + callTriggerConstantContract(ownerAddressByte, contractAddressByte, 0, data, + trxExtBuilder, retBuilder); + + } catch (ContractValidateException | VMIllegalException e) { + retBuilder.setResult(false).setCode(response_code.CONTRACT_VALIDATE_ERROR) + .setMessage(ByteString.copyFromUtf8(CONTRACT_VALIDATE_ERROR + e.getMessage())); + trxExtBuilder.setResult(retBuilder); + logger.warn(CONTRACT_VALIDATE_EXCEPTION, e.getMessage()); + } catch (RuntimeException e) { + retBuilder.setResult(false).setCode(response_code.CONTRACT_EXE_ERROR) + .setMessage(ByteString.copyFromUtf8(e.getClass() + " : " + e.getMessage())); + trxExtBuilder.setResult(retBuilder); + logger.warn("When run constant call in VM, have RuntimeException: " + e.getMessage()); + } catch (Exception e) { + retBuilder.setResult(false).setCode(response_code.OTHER_ERROR) + .setMessage(ByteString.copyFromUtf8(e.getClass() + " : " + e.getMessage())); + trxExtBuilder.setResult(retBuilder); + logger.warn("Unknown exception caught: " + e.getMessage(), e); + } finally { + trxExt = trxExtBuilder.build(); + } + + String result = "0x"; + String code = trxExt.getResult().getCode().toString(); + if ("SUCCESS".equals(code)) { + List list = trxExt.getConstantResultList(); + byte[] listBytes = new byte[0]; + for (ByteString bs : list) { + listBytes = ByteUtil.merge(listBytes, bs.toByteArray()); + } + result = ByteArray.toJsonHex(listBytes); + } else { + logger.error("trigger contract failed."); + } + + return result; + } + + @Override + public String getStorageAt(String address, String storageIdx, String blockNumOrTag) + throws JsonRpcInvalidParamsException { + if ("earliest".equalsIgnoreCase(blockNumOrTag) + || "pending".equalsIgnoreCase(blockNumOrTag)) { + throw new JsonRpcInvalidParamsException("TAG [earliest | pending] not supported"); + } else if ("latest".equalsIgnoreCase(blockNumOrTag)) { + byte[] addressByte = addressHashToByteArray(address); + + // get contract from contractStore + BytesMessage.Builder build = BytesMessage.newBuilder(); + BytesMessage bytesMessage = build.setValue(ByteString.copyFrom(addressByte)).build(); + SmartContract smartContract = wallet.getContract(bytesMessage); + if (smartContract == null) { + return ByteArray.toJsonHex(new byte[32]); + } + + StorageRowStore store = manager.getStorageRowStore(); + Storage storage = new Storage(addressByte, store); + + // init Tvm config + storage.setContractVersion(smartContract.getVersion()); + VMConfig.initAllowTvmCompatibleEvm(1); + + DataWord value = storage.getValue(new DataWord(ByteArray.fromHexString(storageIdx))); + return ByteArray.toJsonHex(value == null ? new byte[32] : value.getData()); + } else { + try { + ByteArray.hexToBigInteger(blockNumOrTag); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid block number"); + } + + throw new JsonRpcInvalidParamsException("QUANTITY not supported, just support TAG as latest"); + } + } + + @Override + public String getABIOfSmartContract(String contractAddress, String blockNumOrTag) + throws JsonRpcInvalidParamsException { + if ("earliest".equalsIgnoreCase(blockNumOrTag) + || "pending".equalsIgnoreCase(blockNumOrTag)) { + throw new JsonRpcInvalidParamsException("TAG [earliest | pending] not supported"); + } else if ("latest".equalsIgnoreCase(blockNumOrTag)) { + byte[] addressData = addressHashToByteArray(contractAddress); + + BytesMessage.Builder build = BytesMessage.newBuilder(); + BytesMessage bytesMessage = build.setValue(ByteString.copyFrom(addressData)).build(); + SmartContractDataWrapper contractDataWrapper = wallet.getContractInfo(bytesMessage); + + if (contractDataWrapper != null) { + return ByteArray.toJsonHex(contractDataWrapper.getRuntimecode().toByteArray()); + } else { + return "0x"; + } + + } else { + try { + ByteArray.hexToBigInteger(blockNumOrTag); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid block number"); + } + + throw new JsonRpcInvalidParamsException("QUANTITY not supported, just support TAG as latest"); + } + } + + @Override + public String getCoinbase() throws JsonRpcInternalException { + String address = wallet.getCoinbase(); + + if (StringUtils.isEmpty(address)) { + throw new JsonRpcInternalException("etherbase must be explicitly specified"); + } + + return address; + } + + // return energy fee + @Override + public String gasPrice() { + return ByteArray.toJsonHex(wallet.getEnergyFee()); + } + + @Override + public String estimateGas(CallArguments args) throws JsonRpcInvalidRequestException, + JsonRpcInvalidParamsException, JsonRpcInternalException { + byte[] ownerAddress = addressHashToByteArray(args.from); + + ContractType contractType = args.getContractType(wallet); + if (contractType == ContractType.TransferContract) { + buildTransferContractTransaction(ownerAddress, new BuildArguments(args)); + return "0x0"; + } + + TransactionExtention.Builder trxExtBuilder = TransactionExtention.newBuilder(); + Return.Builder retBuilder = Return.newBuilder(); + + try { + byte[] contractAddress; + + if (contractType == ContractType.TriggerSmartContract) { + contractAddress = addressHashToByteArray(args.to); + } else { + contractAddress = new byte[0]; + } + + callTriggerConstantContract(ownerAddress, + contractAddress, + args.parseValue(), + ByteArray.fromHexString(args.data), + trxExtBuilder, + retBuilder); + + return ByteArray.toJsonHex(trxExtBuilder.getEnergyUsed()); + } catch (ContractValidateException e) { + String errString = "invalid contract"; + if (e.getMessage() != null) { + errString = e.getMessage(); + } + + throw new JsonRpcInvalidRequestException(errString); + } catch (Exception e) { + String errString = "invalid json request"; + if (e.getMessage() != null) { + errString = e.getMessage().replaceAll("[\"]", "\'"); + } + + throw new JsonRpcInternalException(errString); + } + } + + @Override + public TransactionResult getTransactionByHash(String txId) throws JsonRpcInvalidParamsException { + ByteString transactionId = ByteString.copyFrom(hashToByteArray(txId)); + + TransactionInfo transactionInfo = wallet.getTransactionInfoById(transactionId); + if (transactionInfo == null) { + TransactionCapsule transactionCapsule = wallet.getTransactionCapsuleById(transactionId); + if (transactionCapsule == null) { + return null; + } + + BlockCapsule blockCapsule = wallet.getBlockCapsuleByNum(transactionCapsule.getBlockNum()); + if (blockCapsule == null) { + return new TransactionResult(transactionCapsule.getInstance(), wallet); + } else { + int transactionIndex = getTransactionIndex( + ByteArray.toHexString(transactionCapsule.getTransactionId().getBytes()), + blockCapsule.getInstance().getTransactionsList()); + + if (transactionIndex == -1) { + return null; + } + + long energyUsageTotal = 0; + return new TransactionResult(blockCapsule, transactionIndex, + transactionCapsule.getInstance(), energyUsageTotal, + wallet.getEnergyFee(blockCapsule.getTimeStamp()), wallet); + } + } else { + Block block = wallet.getBlockByNum(transactionInfo.getBlockNumber()); + if (block == null) { + return null; + } + + return formatTransactionResult(transactionInfo, block); + } + } + + private TransactionResult formatTransactionResult(TransactionInfo transactioninfo, Block block) { + String txId = ByteArray.toHexString(transactioninfo.getId().toByteArray()); + + Transaction transaction = null; + int transactionIndex = -1; + + List txList = block.getTransactionsList(); + for (int index = 0; index < txList.size(); index++) { + transaction = txList.get(index); + if (getTxID(transaction).equals(txId)) { + transactionIndex = index; + break; + } + } + + if (transactionIndex == -1) { + return null; + } + + long energyUsageTotal = transactioninfo.getReceipt().getEnergyUsageTotal(); + BlockCapsule blockCapsule = new BlockCapsule(block); + return new TransactionResult(blockCapsule, transactionIndex, transaction, + energyUsageTotal, wallet.getEnergyFee(blockCapsule.getTimeStamp()), wallet); + } + + private TransactionResult getTransactionByBlockAndIndex(Block block, String index) + throws JsonRpcInvalidParamsException { + int txIndex; + try { + txIndex = ByteArray.jsonHexToInt(index); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid index value"); + } + + if (txIndex >= block.getTransactionsCount()) { + return null; + } + + Transaction transaction = block.getTransactions(txIndex); + long energyUsageTotal = getEnergyUsageTotal(transaction, wallet); + BlockCapsule blockCapsule = new BlockCapsule(block); + + return new TransactionResult(blockCapsule, txIndex, transaction, energyUsageTotal, + wallet.getEnergyFee(blockCapsule.getTimeStamp()), wallet); + } + + @Override + public TransactionResult getTransactionByBlockHashAndIndex(String blockHash, String index) + throws JsonRpcInvalidParamsException { + final Block block = getBlockByJsonHash(blockHash); + + if (block == null) { + return null; + } + + return getTransactionByBlockAndIndex(block, index); + } + + @Override + public TransactionResult getTransactionByBlockNumberAndIndex(String blockNumOrTag, String index) + throws JsonRpcInvalidParamsException { + Block block = wallet.getByJsonBlockId(blockNumOrTag); + if (block == null) { + return null; + } + + return getTransactionByBlockAndIndex(block, index); + } + + @Override + public TransactionReceipt getTransactionReceipt(String txId) + throws JsonRpcInvalidParamsException { + TransactionInfo transactionInfo = + wallet.getTransactionInfoById(ByteString.copyFrom(hashToByteArray(txId))); + if (transactionInfo == null) { + return null; + } + + Block block = wallet.getBlockByNum(transactionInfo.getBlockNumber()); + if (block == null) { + return null; + } + + return new TransactionReceipt(block, transactionInfo, wallet); + } + + @Override + public String getCall(CallArguments transactionCall, String blockNumOrTag) + throws JsonRpcInvalidParamsException { + if ("earliest".equalsIgnoreCase(blockNumOrTag) + || "pending".equalsIgnoreCase(blockNumOrTag)) { + throw new JsonRpcInvalidParamsException("TAG [earliest | pending] not supported"); + } else if ("latest".equalsIgnoreCase(blockNumOrTag)) { + byte[] addressData = addressHashToByteArray(transactionCall.from); + byte[] contractAddressData = addressHashToByteArray(transactionCall.to); + + return call(addressData, contractAddressData, ByteArray.fromHexString(transactionCall.data)); + } else { + try { + ByteArray.hexToBigInteger(blockNumOrTag).longValue(); + } catch (Exception e) { + throw new JsonRpcInvalidParamsException("invalid block number"); + } + + throw new JsonRpcInvalidParamsException("QUANTITY not supported, just support TAG as latest"); + } + } + + @Override + public String getPeerCount() { + // return the peer list count + return ByteArray.toJsonHex(nodeInfoService.getNodeInfo().getPeerList().size()); + } + + @Override + public Object getSyncingStatus() { + if (nodeInfoService.getNodeInfo().getPeerList().isEmpty()) { + return false; + } + + long startingBlockNum = nodeInfoService.getNodeInfo().getBeginSyncNum(); + Block nowBlock = wallet.getNowBlock(); + long currentBlockNum = nowBlock.getBlockHeader().getRawData().getNumber(); + long diff = (System.currentTimeMillis() + - nowBlock.getBlockHeader().getRawData().getTimestamp()) / 3000; + diff = diff > 0 ? diff : 0; + long highestBlockNum = currentBlockNum + diff; // estimated the highest block number + + return new SyncingResult(ByteArray.toJsonHex(startingBlockNum), + ByteArray.toJsonHex(currentBlockNum), + ByteArray.toJsonHex(highestBlockNum) + ); + } + + @Override + public BlockResult getUncleByBlockHashAndIndex(String blockHash, String index) { + return null; + } + + @Override + public BlockResult getUncleByBlockNumberAndIndex(String blockNumOrTag, String index) { + return null; + } + + @Override + public String getUncleCountByBlockHash(String blockHash) { + return "0x0"; + } + + @Override + public String getUncleCountByBlockNumber(String blockNumOrTag) { + return "0x0"; + } + + @Override + public List ethGetWork() { + Block block = wallet.getNowBlock(); + String blockHash = null; + + if (block != null) { + blockHash = ByteArray.toJsonHex(new BlockCapsule(block).getBlockId().getBytes()); + } + + return Arrays.asList( + blockHash, + null, + null + ); + } + + @Override + public String getHashRate() { + return "0x0"; + } + + @Override + public boolean isMining() { + return wallet.isMining(); + } + + @Override + public String[] getAccounts() { + return new String[0]; + } + + private TransactionJson buildCreateSmartContractTransaction(byte[] ownerAddress, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + JsonRpcInternalException { + try { + CreateSmartContract.Builder build = CreateSmartContract.newBuilder(); + + build.setOwnerAddress(ByteString.copyFrom(ownerAddress)); + + build.setCallTokenValue(args.tokenValue) + .setTokenId(args.tokenId); + + ABI.Builder abiBuilder = ABI.newBuilder(); + if (StringUtils.isNotEmpty(args.abi)) { + String abiStr = "{" + "\"entrys\":" + args.abi + "}"; + JsonFormat.merge(abiStr, abiBuilder, args.visible); + } + + SmartContract.Builder smartBuilder = SmartContract.newBuilder(); + smartBuilder + .setAbi(abiBuilder) + .setCallValue(args.parseValue()) + .setConsumeUserResourcePercent(args.consumeUserResourcePercent) + .setOriginEnergyLimit(args.originEnergyLimit); + + smartBuilder.setOriginAddress(ByteString.copyFrom(ownerAddress)); + + // bytecode + parameter + smartBuilder.setBytecode(ByteString.copyFrom(ByteArray.fromHexString(args.data))); + + if (StringUtils.isNotEmpty(args.name)) { + smartBuilder.setName(args.name); + } + + build.setNewContract(smartBuilder); + + Transaction tx = wallet + .createTransactionCapsule(build.build(), ContractType.CreateSmartContract).getInstance(); + Transaction.Builder txBuilder = tx.toBuilder(); + Transaction.raw.Builder rawBuilder = tx.getRawData().toBuilder(); + rawBuilder.setFeeLimit(args.parseGas() * wallet.getEnergyFee()); + + txBuilder.setRawData(rawBuilder); + tx = setTransactionPermissionId(args.permissionId, txBuilder.build()); + + TransactionJson transactionJson = new TransactionJson(); + transactionJson.transaction = JSON.parseObject(Util.printCreateTransaction(tx, false)); + + return transactionJson; + } catch (JsonRpcInvalidParamsException e) { + throw new JsonRpcInvalidParamsException(e.getMessage()); + } catch (ContractValidateException e) { + throw new JsonRpcInvalidRequestException(e.getMessage()); + } catch (Exception e) { + throw new JsonRpcInternalException(e.getMessage()); + } + } + + // from and to should not be null + private TransactionJson buildTriggerSmartContractTransaction(byte[] ownerAddress, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + JsonRpcInternalException { + byte[] contractAddress = addressHashToByteArray(args.to); + + TriggerSmartContract.Builder build = TriggerSmartContract.newBuilder(); + TransactionExtention.Builder trxExtBuilder = TransactionExtention.newBuilder(); + Return.Builder retBuilder = Return.newBuilder(); + + try { + + build.setOwnerAddress(ByteString.copyFrom(ownerAddress)) + .setContractAddress(ByteString.copyFrom(contractAddress)); + + if (StringUtils.isNotEmpty(args.data)) { + build.setData(ByteString.copyFrom(ByteArray.fromHexString(args.data))); + } else { + build.setData(ByteString.copyFrom(new byte[0])); + } + + build.setCallTokenValue(args.tokenValue) + .setTokenId(args.tokenId) + .setCallValue(args.parseValue()); + + Transaction tx = wallet + .createTransactionCapsule(build.build(), ContractType.TriggerSmartContract).getInstance(); + + Transaction.Builder txBuilder = tx.toBuilder(); + Transaction.raw.Builder rawBuilder = tx.getRawData().toBuilder(); + rawBuilder.setFeeLimit(args.parseGas() * wallet.getEnergyFee()); + txBuilder.setRawData(rawBuilder); + + Transaction trx = wallet + .triggerContract(build.build(), new TransactionCapsule(txBuilder.build()), trxExtBuilder, + retBuilder); + trx = setTransactionPermissionId(args.permissionId, trx); + trxExtBuilder.setTransaction(trx); + } catch (JsonRpcInvalidParamsException e) { + throw new JsonRpcInvalidParamsException(e.getMessage()); + } catch (ContractValidateException e) { + throw new JsonRpcInvalidRequestException(e.getMessage()); + } catch (Exception e) { + String errString = "invalid json request"; + if (e.getMessage() != null) { + errString = e.getMessage().replaceAll("[\"]", "\'"); + } + + throw new JsonRpcInternalException(errString); + } + + String jsonString = Util.printTransaction(trxExtBuilder.build().getTransaction(), args.visible); + TransactionJson transactionJson = new TransactionJson(); + transactionJson.transaction = JSON.parseObject(jsonString); + + return transactionJson; + } + + private TransactionJson createTransactionJson(GeneratedMessageV3.Builder build, + ContractType contractTyp, BuildArguments args) + throws JsonRpcInvalidRequestException, JsonRpcInternalException { + try { + Transaction tx = wallet + .createTransactionCapsule(build.build(), contractTyp) + .getInstance(); + tx = setTransactionPermissionId(args.permissionId, tx); + tx = setTransactionExtraData(args.extraData, tx, args.visible); + + String jsonString = Util.printCreateTransaction(tx, args.visible); + + TransactionJson transactionJson = new TransactionJson(); + transactionJson.transaction = JSON.parseObject(jsonString); + + return transactionJson; + } catch (ContractValidateException e) { + throw new JsonRpcInvalidRequestException(e.getMessage()); + } catch (Exception e) { + throw new JsonRpcInternalException(e.getMessage()); + } + } + + private TransactionJson buildTransferContractTransaction(byte[] ownerAddress, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + JsonRpcInternalException { + long amount = args.parseValue(); + + TransferContract.Builder build = TransferContract.newBuilder(); + build.setOwnerAddress(ByteString.copyFrom(ownerAddress)) + .setToAddress(ByteString.copyFrom(addressHashToByteArray(args.to))) + .setAmount(amount); + + return createTransactionJson(build, ContractType.TransferContract, args); + } + + // tokenId and tokenValue should not be null + private TransactionJson buildTransferAssetContractTransaction(byte[] ownerAddress, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + JsonRpcInternalException { + byte[] tokenIdArr = ByteArray.fromString(String.valueOf(args.tokenId)); + if (tokenIdArr == null) { + throw new JsonRpcInvalidParamsException("invalid param value: invalid tokenId"); + } + + TransferAssetContract.Builder build = TransferAssetContract.newBuilder(); + build.setOwnerAddress(ByteString.copyFrom(ownerAddress)) + .setToAddress(ByteString.copyFrom(addressHashToByteArray(args.to))) + .setAssetName(ByteString.copyFrom(tokenIdArr)) + .setAmount(args.tokenValue); + + return createTransactionJson(build, ContractType.TransferAssetContract, args); + } + + public RequestSource getSource() { + Chainbase.Cursor cursor = wallet.getCursor(); + switch (cursor) { + case SOLIDITY: + return RequestSource.SOLIDITY; + case PBFT: + return RequestSource.PBFT; + default: + return RequestSource.FULLNODE; + } + } + + @Override + public TransactionJson buildTransaction(BuildArguments args) + throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + JsonRpcInternalException, JsonRpcMethodNotFoundException { + + if (getSource() != RequestSource.FULLNODE) { + String msg = String + .format("the method buildTransaction does not exist/is not available in %s", + getSource().toString()); + throw new JsonRpcMethodNotFoundException(msg); + } + + byte[] fromAddressData; + try { + fromAddressData = addressHashToByteArray(args.from); + } catch (JsonRpcInvalidParamsException e) { + throw new JsonRpcInvalidRequestException("invalid json request"); + } + + // check possible ContractType + ContractType contractType = args.getContractType(wallet); + switch (contractType.getNumber()) { + case ContractType.CreateSmartContract_VALUE: + return buildCreateSmartContractTransaction(fromAddressData, args); + case ContractType.TriggerSmartContract_VALUE: + return buildTriggerSmartContractTransaction(fromAddressData, args); + case ContractType.TransferContract_VALUE: + return buildTransferContractTransaction(fromAddressData, args); + case ContractType.TransferAssetContract_VALUE: + return buildTransferAssetContractTransaction(fromAddressData, args); + default: + break; + } + + return null; + } + + @Override + public boolean ethSubmitWork(String nonceHex, String headerHex, String digestHex) + throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_submitWork does not exist/is not available"); + } + + @Override + public String ethSendRawTransaction(String rawData) throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_sendRawTransaction does not exist/is not available"); + } + + @Override + public String ethSendTransaction(CallArguments args) throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_sendTransaction does not exist/is not available"); + } + + @Override + public String ethSign(String address, String msg) throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_sign does not exist/is not available"); + } + + @Override + public String ethSignTransaction(CallArguments transactionArgs) + throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_signTransaction does not exist/is not available"); + } + + @Override + public String parityNextNonce(String address) throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method parity_nextNonce does not exist/is not available"); + } + + @Override + public String getSendTransactionCountOfAddress(String address, String blockNumOrTag) + throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_getTransactionCount does not exist/is not available"); + } + + @Override + public String[] getCompilers() throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_getCompilers does not exist/is not available"); + } + + @Override + public CompilationResult ethCompileSolidity(String contract) + throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_compileSolidity does not exist/is not available"); + } + + @Override + public CompilationResult ethCompileLLL(String contract) throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_compileLLL does not exist/is not available"); + } + + @Override + public CompilationResult ethCompileSerpent(String contract) + throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_compileSerpent does not exist/is not available"); + } + + @Override + public CompilationResult ethSubmitHashrate(String hashrate, String id) + throws JsonRpcMethodNotFoundException { + throw new JsonRpcMethodNotFoundException( + "the method eth_submitHashrate does not exist/is not available"); + } +} diff --git a/framework/src/main/java/org/tron/core/services/ratelimiter/RateLimiterInterceptor.java b/framework/src/main/java/org/tron/core/services/ratelimiter/RateLimiterInterceptor.java index f7abc4f10a6..a74f89df517 100644 --- a/framework/src/main/java/org/tron/core/services/ratelimiter/RateLimiterInterceptor.java +++ b/framework/src/main/java/org/tron/core/services/ratelimiter/RateLimiterInterceptor.java @@ -21,11 +21,8 @@ import org.tron.core.metrics.MetricsKey; import org.tron.core.metrics.MetricsUtil; import org.tron.core.services.ratelimiter.adapter.DefaultBaseQqsAdapter; -import org.tron.core.services.ratelimiter.adapter.GlobalPreemptibleAdapter; -import org.tron.core.services.ratelimiter.adapter.IPQPSRateLimiterAdapter; import org.tron.core.services.ratelimiter.adapter.IPreemptibleRateLimiter; import org.tron.core.services.ratelimiter.adapter.IRateLimiter; -import org.tron.core.services.ratelimiter.adapter.QpsRateLimiterAdapter; @Slf4j diff --git a/framework/src/main/java/org/tron/core/services/ratelimiter/RpcApiAccessInterceptor.java b/framework/src/main/java/org/tron/core/services/ratelimiter/RpcApiAccessInterceptor.java new file mode 100644 index 00000000000..c3471c2829c --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/ratelimiter/RpcApiAccessInterceptor.java @@ -0,0 +1,54 @@ +package org.tron.core.services.ratelimiter; + +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCall.Listener; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import io.grpc.Status; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.tron.common.parameter.CommonParameter; + +@Slf4j +@Component +public class RpcApiAccessInterceptor implements ServerInterceptor { + + @Override + public Listener interceptCall(ServerCall call, + Metadata headers, + ServerCallHandler next) { + + String endpoint = call.getMethodDescriptor().getFullMethodName(); + + try { + if (isDisabled(endpoint)) { + call.close(Status.UNAVAILABLE + .withDescription("this API is unavailable due to config"), headers); + return new ServerCall.Listener() {}; + + } else { + return next.startCall(call, headers); + } + } catch (Exception e) { + logger.error("check rpc api access Error: {}", e.getMessage()); + return next.startCall(call, headers); + } + } + + private boolean isDisabled(String endpoint) { + boolean disabled = false; + + try { + List disabledApiList = CommonParameter.getInstance().getDisabledApiList(); + if (!disabledApiList.isEmpty()) { + disabled = disabledApiList.contains(endpoint.split("/")[1].toLowerCase()); + } + } catch (Exception e) { + logger.error("check isDisabled except, endpoint={}, error is {}", endpoint, e.getMessage()); + } + + return disabled; + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/program/DBConvert.java b/framework/src/main/java/org/tron/program/DBConvert.java index b4e312d83dc..8dd2ad04793 100644 --- a/framework/src/main/java/org/tron/program/DBConvert.java +++ b/framework/src/main/java/org/tron/program/DBConvert.java @@ -30,6 +30,7 @@ import org.rocksdb.RocksDB; import org.rocksdb.RocksDBException; import org.rocksdb.RocksIterator; +import org.rocksdb.Status; import org.tron.common.utils.FileUtil; import org.tron.common.utils.MarketOrderPriceComparatorForLevelDB; import org.tron.common.utils.MarketOrderPriceComparatorForRockDB; @@ -57,14 +58,7 @@ public class DBConvert implements Callable { private final long startTime; private static final int CPUS = Runtime.getRuntime().availableProcessors(); private static final int BATCH = 256; - private static final ThreadPoolExecutor esDb = new ThreadPoolExecutor( - CPUS, 16 * CPUS, 1, TimeUnit.MINUTES, - new ArrayBlockingQueue<>(CPUS, true), Executors.defaultThreadFactory(), - new ThreadPoolExecutor.CallerRunsPolicy()); - static { - esDb.allowCoreThreadTimeOut(true); - } @Override public Boolean call() throws Exception { @@ -80,7 +74,7 @@ public DBConvert(String src, String dst, String name) { this.startTime = System.currentTimeMillis(); } - private static org.iq80.leveldb.Options newDefaultLevelDbOptions() { + public static org.iq80.leveldb.Options newDefaultLevelDbOptions() { org.iq80.leveldb.Options dbOptions = new org.iq80.leveldb.Options(); dbOptions.createIfMissing(true); dbOptions.paranoidChecks(true); @@ -94,6 +88,13 @@ private static org.iq80.leveldb.Options newDefaultLevelDbOptions() { } public static void main(String[] args) { + int code = run(args); + logger.info("exit code {}.", code); + System.out.printf("exit code %d.\n", code); + System.exit(code); + } + + public static int run(String[] args) { String dbSrc; String dbDst; if (args.length < 2) { @@ -106,7 +107,7 @@ public static void main(String[] args) { File dbDirectory = new File(dbSrc); if (!dbDirectory.exists()) { logger.info(" {} does not exist.", dbSrc); - return; + return 404; } List files = Arrays.stream(Objects.requireNonNull(dbDirectory.listFiles())) .filter(File::isDirectory).collect( @@ -114,11 +115,18 @@ public static void main(String[] args) { if (files.isEmpty()) { logger.info("{} does not contain any database.", dbSrc); - return; + return 0; } final long time = System.currentTimeMillis(); final List> res = new ArrayList<>(); + final ThreadPoolExecutor esDb = new ThreadPoolExecutor( + CPUS, 16 * CPUS, 1, TimeUnit.MINUTES, + new ArrayBlockingQueue<>(CPUS, true), Executors.defaultThreadFactory(), + new ThreadPoolExecutor.CallerRunsPolicy()); + + esDb.allowCoreThreadTimeOut(true); + files.forEach(f -> res.add(esDb.submit(new DBConvert(dbSrc, dbDst, f.getName())))); int fails = res.size(); @@ -142,7 +150,7 @@ public static void main(String[] args) { if (fails > 0) { logger.error("failed!!!!!!!!!!!!!!!!!!!!!!!! size:{}", fails); } - System.exit(fails); + return fails; } public DB newLevelDb(Path db) throws Exception { @@ -206,12 +214,18 @@ private void batchInsert(RocksDB rocks, List keys, List values) values.clear(); } + /** + * https://github.com/facebook/rocksdb/issues/6625 + * @param rocks db + * @param batch write batch + * @throws Exception RocksDBException + */ private void write(RocksDB rocks, org.rocksdb.WriteBatch batch) throws Exception { try { rocks.write(new org.rocksdb.WriteOptions(), batch); } catch (RocksDBException e) { // retry - if (e.getMessage() != null && "Write stall".equalsIgnoreCase(e.getMessage())) { + if (maybeRetry(e)) { TimeUnit.MILLISECONDS.sleep(1); write(rocks, batch); } else { @@ -220,6 +234,17 @@ private void write(RocksDB rocks, org.rocksdb.WriteBatch batch) throws Exception } } + private boolean maybeRetry(RocksDBException e) { + boolean retry = false; + if (e.getStatus() != null) { + retry = e.getStatus().getCode() == Status.Code.TryAgain + || e.getStatus().getCode() == Status.Code.Busy + || e.getStatus().getCode() == Status.Code.Incomplete; + } + return retry || (e.getMessage() != null && ("Write stall".equalsIgnoreCase(e.getMessage()) + || ("Incomplete").equalsIgnoreCase(e.getMessage()))); + } + /** * https://github.com/facebook/rocksdb/wiki/RocksDB-FAQ . * What's the fastest way to load data into RocksDB? diff --git a/framework/src/main/java/org/tron/program/FullNode.java b/framework/src/main/java/org/tron/program/FullNode.java index 3d3d0f9bd8e..25de4259a00 100644 --- a/framework/src/main/java/org/tron/program/FullNode.java +++ b/framework/src/main/java/org/tron/program/FullNode.java @@ -15,16 +15,21 @@ import org.tron.core.config.args.Args; import org.tron.core.services.RpcApiService; import org.tron.core.services.http.FullNodeHttpApiService; +import org.tron.core.services.interfaceJsonRpcOnPBFT.JsonRpcServiceOnPBFT; +import org.tron.core.services.interfaceJsonRpcOnSolidity.JsonRpcServiceOnSolidity; import org.tron.core.services.interfaceOnPBFT.RpcApiServiceOnPBFT; import org.tron.core.services.interfaceOnPBFT.http.PBFT.HttpApiOnPBFTService; import org.tron.core.services.interfaceOnSolidity.RpcApiServiceOnSolidity; import org.tron.core.services.interfaceOnSolidity.http.solidity.HttpApiOnSolidityService; +import org.tron.core.services.jsonrpc.FullNodeJsonRpcHttpService; @Slf4j(topic = "app") public class FullNode { - + public static final int dbVersion = 2; + public static volatile boolean shutDownSign = false; + public static void load(String path) { try { File file = new File(path); @@ -82,9 +87,16 @@ public static void main(String[] args) { appT.addService(httpApiService); } + // JSON-RPC http server + if (CommonParameter.getInstance().jsonRpcHttpFullNodeEnable) { + FullNodeJsonRpcHttpService jsonRpcHttpService = + context.getBean(FullNodeJsonRpcHttpService.class); + appT.addService(jsonRpcHttpService); + } + // full node and solidity node fuse together // provide solidity rpc and http server on the full node. - if (Args.getInstance().getStorage().getDbVersion() == dbVersion) { + if (CommonParameter.getInstance().getStorage().getDbVersion() == dbVersion) { RpcApiServiceOnSolidity rpcApiServiceOnSolidity = context .getBean(RpcApiServiceOnSolidity.class); appT.addService(rpcApiServiceOnSolidity); @@ -93,16 +105,29 @@ public static void main(String[] args) { if (CommonParameter.getInstance().solidityNodeHttpEnable) { appT.addService(httpApiOnSolidityService); } + + // JSON-RPC on solidity + if (CommonParameter.getInstance().jsonRpcHttpSolidityNodeEnable) { + JsonRpcServiceOnSolidity jsonRpcServiceOnSolidity = context + .getBean(JsonRpcServiceOnSolidity.class); + appT.addService(jsonRpcServiceOnSolidity); + } } // PBFT API (HTTP and GRPC) - if (Args.getInstance().getStorage().getDbVersion() == dbVersion) { + if (CommonParameter.getInstance().getStorage().getDbVersion() == dbVersion) { RpcApiServiceOnPBFT rpcApiServiceOnPBFT = context .getBean(RpcApiServiceOnPBFT.class); appT.addService(rpcApiServiceOnPBFT); HttpApiOnPBFTService httpApiOnPBFTService = context .getBean(HttpApiOnPBFTService.class); appT.addService(httpApiOnPBFTService); + + // JSON-RPC on PBFT + if (CommonParameter.getInstance().jsonRpcHttpPBFTNodeEnable) { + JsonRpcServiceOnPBFT jsonRpcServiceOnPBFT = context.getBean(JsonRpcServiceOnPBFT.class); + appT.addService(jsonRpcServiceOnPBFT); + } } appT.initServices(parameter); diff --git a/framework/src/main/java/org/tron/program/Version.java b/framework/src/main/java/org/tron/program/Version.java index 106230f26d4..1b245d91923 100644 --- a/framework/src/main/java/org/tron/program/Version.java +++ b/framework/src/main/java/org/tron/program/Version.java @@ -4,7 +4,7 @@ public class Version { public static final String VERSION_NAME = "GreatVoyage-v4.2.2.1-281-gc1d9dfd6c"; public static final String VERSION_CODE = "15872"; - private static final String VERSION = "4.3.0"; + private static final String VERSION = "4.4.0"; public static String getVersion() { return VERSION; diff --git a/framework/src/main/resources/config-localtest.conf b/framework/src/main/resources/config-localtest.conf index a9a56591800..5c9eb55e402 100644 --- a/framework/src/main/resources/config-localtest.conf +++ b/framework/src/main/resources/config-localtest.conf @@ -152,6 +152,15 @@ node { # maxHeaderListSize = } + jsonrpc { + # httpFullNodeEnable = true + # httpFullNodePort = 8545 + # httpSolidityEnable = true + # httpSolidityPort = 8555 + # httpPBFTEnable = true + # httpPBFTPort = 8565 + } + } diff --git a/framework/src/main/resources/config.conf b/framework/src/main/resources/config.conf index 2326876f17c..dda18b2665f 100644 --- a/framework/src/main/resources/config.conf +++ b/framework/src/main/resources/config.conf @@ -216,6 +216,24 @@ node { # note: above APIs may return null even if blocks and transactions actually are on the blockchain # when opening on a lite fullnode. only open it if the consequences being clearly known # openHistoryQueryWhenLiteFN = false + + jsonrpc { + # httpFullNodeEnable = true + # httpFullNodePort = 8545 + # httpSolidityEnable = true + # httpSolidityPort = 8555 + # httpPBFTEnable = true + # httpPBFTPort = 8565 + } + + # Disabled api list, it will work for http, rpc and pbft, both fullnode and soliditynode, + # but not jsonrpc. + # Sample: The setting is case insensitive, GetNowBlock2 is equal to getnowblock2 + # + # disabledApi = [ + # "getaccount", + # "getnowblock2" + # ] } ## rate limiter config @@ -508,6 +526,7 @@ block = { vm = { supportConstant = false + maxEnergyLimitForConstant = 100000000 minTimeRatio = 0.0 maxTimeRatio = 5.0 saveInternalTx = false diff --git a/framework/src/main/resources/logback.xml b/framework/src/main/resources/logback.xml index ec2d2b3c1c9..fcdb7ffd16e 100644 --- a/framework/src/main/resources/logback.xml +++ b/framework/src/main/resources/logback.xml @@ -3,7 +3,7 @@ - + diff --git a/framework/src/test/java/org/tron/common/overlay/discover/node/NodeHandlerTest.java b/framework/src/test/java/org/tron/common/overlay/discover/node/NodeHandlerTest.java index 8e14edeb0b2..dfe24f8e644 100644 --- a/framework/src/test/java/org/tron/common/overlay/discover/node/NodeHandlerTest.java +++ b/framework/src/test/java/org/tron/common/overlay/discover/node/NodeHandlerTest.java @@ -3,62 +3,57 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import org.junit.After; +import org.junit.AfterClass; import org.junit.Assert; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.tron.common.application.Application; -import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; -import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.FileUtil; import org.tron.core.ChainBaseManager; import org.tron.core.Constant; import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; -import org.tron.core.db.Manager; public class NodeHandlerTest { private static final Logger logger = LoggerFactory.getLogger("Test"); - private Manager dbManager; - private TronApplicationContext context; - private Application appTest; - private CommonParameter argsTest; - private Node currNode; - private Node oldNode; - private Node replaceNode; - private NodeHandler currHandler; - private NodeHandler oldHandler; - private NodeHandler replaceHandler; - private NodeManager nodeManager; + // private static Manager dbManager; + private static TronApplicationContext context; + // private Application appTest; + // private CommonParameter argsTest; + private static Node currNode; + private static Node oldNode; + private static Node replaceNode; + private static NodeHandler currHandler; + private static NodeHandler oldHandler; + private static NodeHandler replaceHandler; + private static NodeManager nodeManager; + private static String dbPath = "NodeHandlerTest"; + + static { + Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF); + context = new TronApplicationContext(DefaultConfig.class); + } /** * init the application. */ - @Before - public void init() { - argsTest = Args.getInstance(); - Args.setParam(new String[]{"--output-directory", "output-directory", "--debug"}, - Constant.TEST_CONF); - context = new TronApplicationContext(DefaultConfig.class); - appTest = ApplicationFactory.create(context); - appTest.initServices(argsTest); - appTest.startServices(); - appTest.startup(); + @BeforeClass + public static void init() { + initNodes(); } /** * destroy the context. */ - @After - public void destroy() { + @AfterClass + public static void destroy() { Args.clearParam(); context.destroy(); - if (FileUtil.deleteDir(new File("output-directory"))) { + if (FileUtil.deleteDir(new File(dbPath))) { logger.info("Release resources successful."); } else { logger.info("Release resources failure."); @@ -68,9 +63,8 @@ public void destroy() { /** * init nodes. */ - @Before - public void initNodes() { - dbManager = context.getBean(Manager.class); + public static void initNodes() { + // dbManager = context.getBean(Manager.class); nodeManager = new NodeManager(context.getBean(ChainBaseManager.class)); String currNodeId = "74c11ffad1d59d7b1a56691a0b84a53f0791c92361357364f1d2537" + "898407ef0249bbbf5a4ce8cff9e34e2fdf8bac883540e026d1e5d6ebf536414bdde81198e"; @@ -100,7 +94,7 @@ public void stateNonActiveTest() throws Exception { nh.changeState(NodeHandler.State.NONACTIVE); replaceHandler.changeState(NodeHandler.State.ALIVE); - Assert.assertTrue(!nodeManager.getTable().contains(oldNode)); + Assert.assertFalse(nodeManager.getTable().contains(oldNode)); Assert.assertTrue(nodeManager.getTable().contains(replaceNode)); } } diff --git a/framework/src/test/java/org/tron/common/overlay/discover/node/NodeManagerTest.java b/framework/src/test/java/org/tron/common/overlay/discover/node/NodeManagerTest.java index c5f12861b3a..f5b870bacdf 100644 --- a/framework/src/test/java/org/tron/common/overlay/discover/node/NodeManagerTest.java +++ b/framework/src/test/java/org/tron/common/overlay/discover/node/NodeManagerTest.java @@ -6,14 +6,13 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.junit.After; +import org.junit.AfterClass; import org.junit.Assert; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tron.common.application.Application; -import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.FileUtil; @@ -27,37 +26,47 @@ public class NodeManagerTest { private static final Logger logger = LoggerFactory.getLogger("Test"); - private Manager manager; - private NodeManager nodeManager; - private TronApplicationContext context; - private CommonParameter argsTest; - private Application appTest; - private Class nodeManagerClazz; - + private static Manager manager; + private static NodeManager nodeManager; + private static TronApplicationContext context; + private static CommonParameter argsTest; + private static Application appTest; + private static Class nodeManagerClazz; + private static String dbPath = "NodeManagerTest"; + + static { + Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF); + context = new TronApplicationContext(DefaultConfig.class); + } /** * start the application. */ - @Before - public void init() { - argsTest = Args.getInstance(); - Args.setParam(new String[]{"--output-directory", "output-directory", "--debug"}, - Constant.TEST_CONF); - context = new TronApplicationContext(DefaultConfig.class); - appTest = ApplicationFactory.create(context); - appTest.initServices(argsTest); - appTest.startServices(); - appTest.startup(); + @BeforeClass + public static void init() { + // argsTest = Args.getInstance(); + // Args.setParam(new String[]{"--output-directory", dbPath}, + // Constant.TEST_CONF); + // context = new TronApplicationContext(DefaultConfig.class); + // appTest = ApplicationFactory.create(context); + // appTest.initServices(argsTest); + // appTest.startServices(); + // appTest.startup(); + try { + initManager(); + } catch (Exception e) { + logger.error("init failed {}", e.getMessage()); + } } /** * destroy the context. */ - @After - public void destroy() { + @AfterClass + public static void destroy() { Args.clearParam(); context.destroy(); - if (FileUtil.deleteDir(new File("output-directory"))) { + if (FileUtil.deleteDir(new File(dbPath))) { logger.info("Release resources successful."); } else { logger.info("Release resources failure."); @@ -67,18 +76,19 @@ public void destroy() { /** * init the managers. */ - @Before - public void initManager() throws Exception { + // @Before + public static void initManager() throws Exception { nodeManagerClazz = NodeManager.class; - Constructor handlerConstructor - = nodeManagerClazz.getConstructor(ChainBaseManager.class); + // Constructor handlerConstructor + // = nodeManagerClazz.getConstructor(ChainBaseManager.class); manager = context.getBean(Manager.class); - nodeManager = handlerConstructor.newInstance(context.getBean(ChainBaseManager.class)); + // nodeManager = handlerConstructor.newInstance(context.getBean(ChainBaseManager.class)); + nodeManager = new NodeManager(context.getBean(ChainBaseManager.class)); } @Test public void isNodeAliveTest() { - Node node = new Node(new byte[64], "128.0.0.1", 18888, 18888); + Node node = new Node(new byte[64], "128.0.0.1", 18889, 18889); nodeManager.getTable().addNode(node); NodeHandler nodeHandler = new NodeHandler(node, nodeManager); nodeHandler.changeState(NodeHandler.State.ACTIVE); @@ -94,6 +104,8 @@ public void trimTableTest_removeByReputation() throws Exception { //insert 3001 nodes(isConnectible = true) with threshold = 3000 final int totalNodes = insertValues(3002); Assert.assertEquals(calculateTrimNodes(totalNodes, 0), getHandlerMapSize()); + + clearNodeManager(); } @Test @@ -104,6 +116,12 @@ public void trimTableTest_removeNotConnectibleNodes() throws Exception { method.setAccessible(true); method.invoke(nodeManager); Assert.assertEquals(calculateTrimNodes(totalNodes, 2), getHandlerMapSize()); + + clearNodeManager(); + } + + private void clearNodeManager() { + nodeManager.clearNodeHandlerMap(); } /** @@ -150,7 +168,7 @@ public int insertValues(int totalNodes) throws Exception { Class nodeClazz = Node.class; Constructor nodeConstructor = nodeClazz.getConstructor(byte[].class, String.class, int.class, int.class); - Node node = nodeConstructor.newInstance(bytes, stringBuilder.toString(), 18888, 18888); + Node node = nodeConstructor.newInstance(bytes, stringBuilder.toString(), 18889, 18889); Field isConnectableField = nodeClazz.getDeclaredField("p2pVersion"); isConnectableField.setAccessible(true); isConnectableField.set(node, Args.getInstance().getNodeP2pVersion()); @@ -166,10 +184,10 @@ public void insertNotConnectibleNodes() throws Exception { Class nodeClazz = Node.class; Constructor nodeConstructor = nodeClazz.getConstructor(byte[].class, String.class, int.class, int.class); - Node wrongNode1 = nodeConstructor.newInstance(new byte[64], "128.0.0.1", 1111, 18888); + Node wrongNode1 = nodeConstructor.newInstance(new byte[64], "128.0.0.1", 1111, 18889); byte[] id = new byte[64]; id[63] = 1; - Node wrongNode2 = nodeConstructor.newInstance(id, "128.0.0.2", 1111, 18888); + Node wrongNode2 = nodeConstructor.newInstance(id, "128.0.0.2", 1111, 18889); Field isConnectableField = nodeClazz.getDeclaredField("p2pVersion"); isConnectableField.setAccessible(true); isConnectableField.set(wrongNode1, 999); @@ -193,9 +211,9 @@ public int getHandlerMapSize() throws Exception { @Test public void dumpActiveNodesTest() { - Node node1 = new Node(new byte[64], "128.0.0.1", 18888, 18888); - Node node2 = new Node(new byte[64], "128.0.0.2", 18888, 18888); - Node node3 = new Node(new byte[64], "128.0.0.3", 18888, 18888); + Node node1 = new Node(new byte[64], "128.0.0.1", 18889, 18889); + Node node2 = new Node(new byte[64], "128.0.0.2", 18889, 18889); + Node node3 = new Node(new byte[64], "128.0.0.3", 18889, 18889); NodeHandler nodeHandler1 = nodeManager.getNodeHandler(node1); NodeHandler nodeHandler2 = nodeManager.getNodeHandler(node2); NodeHandler nodeHandler3 = nodeManager.getNodeHandler(node3); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmCompatibleEvmTest.java b/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmCompatibleEvmTest.java new file mode 100644 index 00000000000..0b24d357a8a --- /dev/null +++ b/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmCompatibleEvmTest.java @@ -0,0 +1,311 @@ +package org.tron.common.runtime.vm; + +import static org.tron.common.utils.ByteUtil.hexToBytes; +import static org.tron.common.utils.ByteUtil.longTo32Bytes; + +import java.util.Collections; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.util.encoders.Hex; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.testng.Assert; +import org.tron.common.runtime.TVMTestResult; +import org.tron.common.runtime.TvmTestUtils; +import org.tron.common.utils.WalletUtil; +import org.tron.core.exception.ContractExeException; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.ReceiptCheckErrException; +import org.tron.core.exception.VMIllegalException; +import org.tron.core.vm.config.ConfigLoader; +import org.tron.core.vm.config.VMConfig; +import org.tron.protos.Protocol; +import stest.tron.wallet.common.client.utils.AbiUtil; + +@Slf4j +public class AllowTvmCompatibleEvmTest extends VMTestBase { + /*contract c { + function getRipemd160() public view returns(bytes32 output) { + string memory input = "11"; + assembly { + if iszero(staticcall(not(0), 0x20003, add(input, 0x20), 0x2, output, 0x20)) { + revert(0, 0) + } + output := mload(add(output,0x0c)) + } + + } + }*/ + + @BeforeClass + public static void beforeClass() { + ConfigLoader.disable = true; + VMConfig.initAllowTvmTransferTrc10(1); + VMConfig.initAllowTvmConstantinople(1); + VMConfig.initAllowTvmSolidity059(1); + VMConfig.initAllowTvmIstanbul(1); + VMConfig.initAllowTvmLondon(1); + VMConfig.initAllowTvmCompatibleEvm(1); + } + + @Test + public void testEthRipemd160() throws ContractExeException, ReceiptCheckErrException, + VMIllegalException, ContractValidateException { + String contractName = "testEthRipemd160"; + byte[] address = Hex.decode(OWNER_ADDRESS); + String abi = "[{\"inputs\":[],\"name\":\"getRipemd160\"," + + "\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"output\",\"type\":\"bytes32\"}]," + + "\"stateMutability\":\"view\",\"type\":\"function\"}]"; + String factoryCode = "608060405234801561001057600080fd5b5060bc" + + "8061001f6000396000f3fe6080604052348015600f57600080fd5b506" + + "004361060285760003560e01c8063c99ea27e14602d575b600080fd5b" + + "60336045565b60405190815260200160405180910390f35b600080604" + + "05180604001604052806002815260200161313160f01b815250905060" + + "208260026020840162020003600019fa607e57600080fd5b50600c015" + + "19056fea2646970667358221220d2f0f2cba312fd79e42db9191048a6" + + "1e0eea399c580d9f2b3c13dd154afebfe164736f6c63430008070033"; + long value = 0; + long feeLimit = 100000000; + long consumeUserResourcePercent = 0; + + // deploy contract + Protocol.Transaction trx = TvmTestUtils.generateDeploySmartContractAndGetTransaction( + contractName, address, abi, factoryCode, value, feeLimit, consumeUserResourcePercent, + null); + byte[] factoryAddress = WalletUtil.generateContractAddress(trx); + runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + Assert.assertNull(runtime.getRuntimeError()); + + // Trigger contract method: getRipemd160() + String methodByAddr = "getRipemd160()"; + String hexInput = + AbiUtil.parseMethod(methodByAddr, Collections.singletonList("")); + + TVMTestResult result = TvmTestUtils + .triggerContractAndReturnTvmTestResult(Hex.decode(OWNER_ADDRESS), + factoryAddress, Hex.decode(hexInput), 0, feeLimit, manager, null); + byte[] returnValue = result.getRuntime().getResult().getHReturn(); + Assert.assertNull(result.getRuntime().getRuntimeError()); + Assert.assertEquals(returnValue, + hexToBytes("a76d892cc3522eab763529dfc84b12c080ee1" + + "fe8000000000000000000000000")); + } + + /*contract c { + function F(uint32 rounds, bytes32[2] memory h, bytes32[4] memory m, + bytes8[2] memory t, bool f) public view returns (bytes32[2] memory) { + bytes32[2] memory output; + + bytes memory args = abi.encodePacked( + rounds, h[0], h[1], m[0], m[1], m[2], m[3], t[0], t[1], f); + + assembly { + if iszero(staticcall(not(0), 0x20009, add(args, 32), 0xd5, output, 0x40)) { + revert(0, 0) + } + } + + return output; + } + + function callF() public view returns (bytes32[2] memory) { + uint32 rounds = 12; + + bytes32[2] memory h; + h[0] = hex"48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5"; + h[1] = hex"d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b"; + + bytes32[4] memory m; + m[0] = hex"6162630000000000000000000000000000000000000000000000000000000000"; + m[1] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + m[2] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + m[3] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + + bytes8[2] memory t; + t[0] = hex"03000000"; + t[1] = hex"00000000"; + + bool f = true; + + // Expected output: + // ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1 + // 7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923 + return F(rounds, h, m, t, f); + } + }*/ + + @Test + public void testBlake2f() throws ContractExeException, ReceiptCheckErrException, + VMIllegalException, ContractValidateException { + String contractName = "testBlake2f"; + byte[] address = Hex.decode(OWNER_ADDRESS); + String abi = "[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rounds\"," + + "\"type\":\"uint32\"},{\"internalType\":\"bytes32[2]\",\"name\":\"h\"," + + "\"type\":\"bytes32[2]\"},{\"internalType\":\"bytes32[4]\",\"name\":\"m\"," + + "\"type\":\"bytes32[4]\"},{\"internalType\":\"bytes8[2]\",\"name\":\"t\"," + + "\"type\":\"bytes8[2]\"},{\"internalType\":\"bool\",\"name\":\"f\",\"type\":\"bool\"}]," + + "\"name\":\"F\",\"outputs\":[{\"internalType\":\"bytes32[2]\",\"name\":\"\"," + + "\"type\":\"bytes32[2]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}," + + "{\"inputs\":[],\"name\":\"callF\",\"outputs\":[{\"internalType\":\"bytes32[2]\"," + + "\"name\":\"\",\"type\":\"bytes32[2]\"}],\"stateMutability\":\"view\"," + + "\"type\":\"function\"}]"; + String factoryCode = "608060405234801561001057600080fd5b506104b28061" + + "00206000396000f3fe608060405234801561001057600080fd5b50600436106" + + "100365760003560e01c806372de3cbd1461003b578063fc75ac471461006457" + + "5b600080fd5b61004e61004936600461035a565b61006c565b60405161005b9" + + "190610414565b60405180910390f35b61004e610165565b610074610215565b" + + "61007c610215565b60008787826020020151886001602002015188600060200" + + "2015189600160200201518a600260200201518b600360200201518b60006020" + + "0201518c6001602090810291909101516040516001600160e01b031960e09b9" + + "09b1b9a909a16918a0191909152602489019790975260448801959095526064" + + "870193909352608486019190915260a485015260c48401526001600160c01b0" + + "31990811660e48401521660ec82015284151560f81b60f482015260f5016040" + + "51602081830303815290604052905060408260d56020840162020009600019f" + + "a61015a57600080fd5b509695505050505050565b61016d610215565b600c61" + + "0177610215565b7f48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3" + + "cf1361d5f3af54fa581527fd182e6ad7f520e511f6c3e2b8c68059b6bbd41fb" + + "abd9831f79217e1319cde05b60208201526101c8610233565b6261626360e81" + + "b81526000602082018190526040820181905260608201526101ee610215565b" + + "600360f81b815260006020820152600161020b858585858561006c565b95505" + + "05050505090565b604051806040016040528060029060208202803683375091" + + "92915050565b604051806080016040528060049060208202803683375091929" + + "15050565b600082601f83011261026257600080fd5b60405160808101818110" + + "67ffffffffffffffff8211171561029357634e487b7160e01b6000526041600" + + "45260246000fd5b6040528083608081018610156102a857600080fd5b60005b" + + "60048110156102ca5781358352602092830192909101906001016102ab565b5" + + "09195945050505050565b600082601f8301126102e657600080fd5b6102ee61" + + "0445565b80838560408601111561030057600080fd5b6000805b60028110156" + + "103395782356001600160c01b031981168114610324578283fd5b8552602094" + + "8501949290920191600101610304565b50919695505050505050565b8035801" + + "515811461035557600080fd5b919050565b6000806000806000610140868803" + + "121561037357600080fd5b853563ffffffff8116811461038757600080fd5b9" + + "4506020603f8701881361039a57600080fd5b6103a2610445565b8082890160" + + "608a018b8111156103b757600080fd5b60005b60028110156103d7578235855" + + "293850193918501916001016103ba565b508298506103e58c82610251565b97" + + "5050505050506103f98760e088016102d5565b9150610408610120870161034" + + "5565b90509295509295909350565b60408101818360005b600281101561043c" + + "57815183526020928301929091019060010161041d565b50505092915050565" + + "b6040805190810167ffffffffffffffff8111828210171561047657634e487b" + + "7160e01b600052604160045260246000fd5b6040529056fea26469706673582" + + "21220a4795cc7f3618b8a552add0f65ee25825ffc8b8077ec1f838fe8dbae5c" + + "3f412364736f6c63430008070033"; + long value = 0; + long feeLimit = 100000000; + long consumeUserResourcePercent = 0; + + // deploy contract + Protocol.Transaction trx = TvmTestUtils.generateDeploySmartContractAndGetTransaction( + contractName, address, abi, factoryCode, value, feeLimit, consumeUserResourcePercent, + null); + byte[] factoryAddress = WalletUtil.generateContractAddress(trx); + runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + Assert.assertNull(runtime.getRuntimeError()); + + // Trigger contract method: callF() + String methodByAddr = "callF()"; + String hexInput = + AbiUtil.parseMethod(methodByAddr, Collections.singletonList("")); + + TVMTestResult result = TvmTestUtils + .triggerContractAndReturnTvmTestResult(Hex.decode(OWNER_ADDRESS), + factoryAddress, Hex.decode(hexInput), 0, feeLimit, manager, null); + byte[] returnValue = result.getRuntime().getResult().getHReturn(); + Assert.assertNull(result.getRuntime().getRuntimeError()); + Assert.assertEquals(returnValue, + hexToBytes("ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87" + + "c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923")); + } + + /*contract c { + function getprice() public view returns(uint) { + return tx.gasprice; + } + }*/ + + @Test + public void testGasPrice() throws ContractExeException, ReceiptCheckErrException, + VMIllegalException, ContractValidateException { + String contractName = "testGasPrice"; + byte[] address = Hex.decode(OWNER_ADDRESS); + String abi = "[{\"inputs\":[],\"name\":\"getprice\"," + + "\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}]," + + "\"stateMutability\":\"view\",\"type\":\"function\"}]"; + String factoryCode = "6080604052348015600f57600080fd5b50607680601d" + + "6000396000f3fe6080604052348015600f57600080fd5b506004361060285" + + "760003560e01c80630fcb598414602d575b600080fd5b3a60405190815260" + + "200160405180910390f3fea2646970667358221220ee994af43fb1d2a4594" + + "ae1355099296fc098d01a7dbe9056530031db6fb9b9c464736f6c63430008070033"; + long value = 0; + long feeLimit = 100000000; + long consumeUserResourcePercent = 0; + + // deploy contract + Protocol.Transaction trx = TvmTestUtils.generateDeploySmartContractAndGetTransaction( + contractName, address, abi, factoryCode, value, feeLimit, consumeUserResourcePercent, + null); + byte[] factoryAddress = WalletUtil.generateContractAddress(trx); + runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + Assert.assertNull(runtime.getRuntimeError()); + + // Trigger contract method: getprice() + String methodByAddr = "getprice()"; + String hexInput = + AbiUtil.parseMethod(methodByAddr, Collections.singletonList("")); + + TVMTestResult result = TvmTestUtils + .triggerContractAndReturnTvmTestResult(Hex.decode(OWNER_ADDRESS), + factoryAddress, Hex.decode(hexInput), 0, feeLimit, manager, null); + byte[] returnValue = result.getRuntime().getResult().getHReturn(); + Assert.assertNull(result.getRuntime().getRuntimeError()); + Assert.assertEquals(returnValue, + longTo32Bytes(manager.getDynamicPropertiesStore().getEnergyFee())); + } + + @Test + public void testChainId() throws ContractExeException, ReceiptCheckErrException, + VMIllegalException, ContractValidateException { + String contractName = "TestChainId"; + byte[] address = Hex.decode(OWNER_ADDRESS); + String contractCode = "608060405234801561001057600080fd5b5060b58061001f6000" + + "396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c" + + "80633408e47014602d575b600080fd5b60336047565b604051603e9190605c565b6040" + + "5180910390f35b600046905090565b6056816075565b82525050565b60006020820190" + + "50606f6000830184604f565b92915050565b600081905091905056fea2646970667358" + + "2212203ccbe28f012f703b4369308e34d6dfc1a89a5f51e3ea42d531fcf3a2dba31150" + + "64736f6c63430008070033"; + long feeLimit = 100_000_000L; + + // deploy contract + Protocol.Transaction trx = TvmTestUtils.generateDeploySmartContractAndGetTransaction( + contractName, address, "[]", contractCode, 0, feeLimit, 0, null); + byte[] factoryAddress = WalletUtil.generateContractAddress(trx); + runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + Assert.assertNull(runtime.getRuntimeError()); + + // Trigger contract method: getChainId() + String methodSignature = "getChainId()"; + String hexInput = + AbiUtil.parseMethod(methodSignature, Collections.singletonList("")); + + TVMTestResult result = TvmTestUtils + .triggerContractAndReturnTvmTestResult(Hex.decode(OWNER_ADDRESS), + factoryAddress, Hex.decode(hexInput), 0, feeLimit, manager, null); + byte[] returnValue = result.getRuntime().getResult().getHReturn(); + Assert.assertNull(result.getRuntime().getRuntimeError()); + Assert.assertEquals(Hex.toHexString(returnValue), + "0000000000000000000000000000000000000000000000000000000028c12d1e"); + + VMConfig.initAllowTvmCompatibleEvm(0); + } + + @AfterClass + public static void afterClass() { + ConfigLoader.disable = false; + VMConfig.initAllowTvmTransferTrc10(0); + VMConfig.initAllowTvmConstantinople(0); + VMConfig.initAllowTvmSolidity059(0); + VMConfig.initAllowTvmIstanbul(0); + VMConfig.initAllowTvmCompatibleEvm(0); + } + +} diff --git a/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmLondonTest.java b/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmLondonTest.java new file mode 100644 index 00000000000..c6b3ec10a98 --- /dev/null +++ b/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmLondonTest.java @@ -0,0 +1,109 @@ +package org.tron.common.runtime.vm; + +import static org.tron.common.utils.ByteUtil.longTo32Bytes; + +import java.util.Collections; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Test; +import org.testng.Assert; +import org.tron.common.runtime.TVMTestResult; +import org.tron.common.runtime.TvmTestUtils; +import org.tron.common.utils.WalletUtil; +import org.tron.core.exception.ContractExeException; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.ReceiptCheckErrException; +import org.tron.core.exception.VMIllegalException; +import org.tron.core.vm.config.ConfigLoader; +import org.tron.core.vm.config.VMConfig; +import org.tron.protos.Protocol; +import stest.tron.wallet.common.client.utils.AbiUtil; + +@Slf4j +public class AllowTvmLondonTest extends VMTestBase { + + /*contract c { + + function getbasefee() public returns(uint) { + return block.basefee; + } + + }*/ + + @Test + public void testBaseFee() throws ContractExeException, ReceiptCheckErrException, + VMIllegalException, ContractValidateException { + ConfigLoader.disable = true; + VMConfig.initAllowTvmTransferTrc10(1); + VMConfig.initAllowTvmConstantinople(1); + VMConfig.initAllowTvmSolidity059(1); + VMConfig.initAllowTvmIstanbul(1); + VMConfig.initAllowTvmLondon(1); + manager.getDynamicPropertiesStore().saveChangeDelegation(1); + + String contractName = "testBaseFee"; + byte[] address = Hex.decode(OWNER_ADDRESS); + String abi = "[{\"inputs\":[],\"name\":\"getbasefee\"," + + "\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}]," + + "\"stateMutability\":\"view\",\"type\":\"function\"}]"; + String factoryCode = "6080604052348015600f57600080fd5b50607680" + + "601d6000396000f3fe6080604052348015600f57600080fd5b5060043" + + "61060285760003560e01c80632266bff614602d575b600080fd5b4860" + + "405190815260200160405180910390f3fea2646970667358221220091" + + "a527d7e484183e543b1ba4520176c089c72f6f3451d8419a19b363314" + + "674a64736f6c63430008070033"; + long value = 0; + long feeLimit = 100000000; + long consumeUserResourcePercent = 0; + + // deploy contract + Protocol.Transaction trx = TvmTestUtils.generateDeploySmartContractAndGetTransaction( + contractName, address, abi, factoryCode, value, feeLimit, consumeUserResourcePercent, + null); + byte[] factoryAddress = WalletUtil.generateContractAddress(trx); + runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + Assert.assertNull(runtime.getRuntimeError()); + + // Trigger contract method: getbasefee() + String methodByAddr = "getbasefee()"; + String hexInput = + AbiUtil.parseMethod(methodByAddr, Collections.singletonList("")); + + TVMTestResult result = TvmTestUtils + .triggerContractAndReturnTvmTestResult(Hex.decode(OWNER_ADDRESS), + factoryAddress, Hex.decode(hexInput), 0, feeLimit, manager, null); + byte[] returnValue = result.getRuntime().getResult().getHReturn(); + Assert.assertNull(result.getRuntime().getRuntimeError()); + Assert.assertEquals(returnValue, + longTo32Bytes(manager.getDynamicPropertiesStore().getEnergyFee())); + } + + @Test + public void testStartWithEF() throws ContractExeException, ReceiptCheckErrException, + VMIllegalException, ContractValidateException { + ConfigLoader.disable = true; + VMConfig.initAllowTvmTransferTrc10(1); + VMConfig.initAllowTvmConstantinople(1); + VMConfig.initAllowTvmSolidity059(1); + VMConfig.initAllowTvmIstanbul(1); + VMConfig.initAllowTvmLondon(1); + manager.getDynamicPropertiesStore().saveChangeDelegation(1); + + String contractName = "testStartWithEF"; + byte[] address = Hex.decode(OWNER_ADDRESS); + String abi = "[{\"inputs\":[],\"name\":\"getbasefee\"," + + "\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}]," + + "\"stateMutability\":\"view\",\"type\":\"function\"}]"; + String factoryCode = "60ef60005360016000f3"; + long value = 0; + long feeLimit = 100000000; + long consumeUserResourcePercent = 0; + + // deploy contract + Protocol.Transaction trx = TvmTestUtils.generateDeploySmartContractAndGetTransaction( + contractName, address, abi, factoryCode, value, feeLimit, consumeUserResourcePercent, + null); + runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + Assert.assertNotNull(runtime.getRuntimeError()); + } +} diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BatchValidateSignContractTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BatchValidateSignContractTest.java index d83d61dc4cb..f7226bb3b3d 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BatchValidateSignContractTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BatchValidateSignContractTest.java @@ -6,8 +6,9 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; import org.bouncycastle.util.encoders.Hex; +import org.junit.Ignore; +import org.junit.Test; import org.testng.Assert; -import org.testng.annotations.Test; import org.tron.common.crypto.ECKey; import org.tron.common.crypto.Hash; import org.tron.common.utils.StringUtil; @@ -25,7 +26,7 @@ public class BatchValidateSignContractTest { static { smellData = new byte[10]; - longData = new byte[100000000]; + longData = new byte[1000]; Arrays.fill(smellData, (byte) 1); Arrays.fill(longData, (byte) 2); } @@ -33,7 +34,7 @@ public class BatchValidateSignContractTest { PrecompiledContracts.BatchValidateSign contract = new BatchValidateSign(); @Test - void staticCallTest() { + public void staticCallTest() { contract.setConstantCall(true); List signatures = new ArrayList<>(); List addresses = new ArrayList<>(); @@ -57,9 +58,7 @@ void staticCallTest() { Pair ret; ret = validateMultiSign(hash, signatures, addresses); for (int i = 0; i < 16; i++) { - if (i >= 27) { - Assert.assertEquals(ret.getValue()[i], 0); - } else if (i % 5 == 0) { + if (i % 5 == 0) { Assert.assertEquals(ret.getValue()[i], 0); } else if (i == 13) { Assert.assertEquals(ret.getValue()[i], 0); @@ -67,27 +66,19 @@ void staticCallTest() { Assert.assertEquals(ret.getValue()[i], 1); } } - signatures = new ArrayList<>(); - addresses = new ArrayList<>(); //test when length >= 16 - for (int i = 0; i < 100; i++) { - ECKey key = new ECKey(); - byte[] sign = key.sign(hash).toByteArray(); - if (i == 11) { - signatures.add(Hex.toHexString(DataWord.ONE().getData())); - } else { - signatures.add(Hex.toHexString(sign)); - } - addresses.add(StringUtil.encode58Check(key.getAddress())); - } + signatures.add(Hex.toHexString(DataWord.ONE().getData())); + addresses + .add(StringUtil.encode58Check(TransactionTrace.convertToTronAddress(new byte[20]))); ret = validateMultiSign(hash, signatures, addresses); Assert.assertEquals(ret.getValue().length, 32); Assert.assertEquals(ret.getValue(), new byte[32]); + System.gc(); // force triggering full gc to avoid timeout for next test } - + @Test - void correctionTest() { + public void correctionTest() { contract.setConstantCall(false); List signatures = new ArrayList<>(); List addresses = new ArrayList<>(); @@ -129,25 +120,7 @@ void correctionTest() { incorrectSigns.remove(incorrectSigns.size() - 1); ret = validateMultiSign(hash, incorrectSigns, addresses); Assert.assertEquals(ret.getValue(), DataWord.ZERO().getData()); - - //test when length >= 32 - signatures = new ArrayList<>(); - addresses = new ArrayList<>(); - for (int i = 0; i < 80; i++) { - ECKey key = new ECKey(); - byte[] sign = key.sign(hash).toByteArray(); - if (i == 13) { - signatures.add(Hex.toHexString(DataWord.ONE().getData())); - } else { - signatures.add(Hex.toHexString(sign)); - } - addresses.add(StringUtil.encode58Check(key.getAddress())); - } - ret = validateMultiSign(hash, signatures, addresses); - Assert.assertEquals(ret.getValue().length, 32); - Assert.assertEquals(ret.getValue(), new byte[32]); - - + System.gc(); // force triggering full gc to avoid timeout for next test } Pair validateMultiSign(byte[] hash, List signatures, diff --git a/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java b/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java index f44a19b3737..9b470f2df50 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java @@ -143,7 +143,12 @@ public void testCreate2() contractName, address, abi, factoryCode, value, fee, consumeUserResourcePercent, null); byte[] factoryAddress = WalletUtil.generateContractAddress(trx); - runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + for (int i = 0; i < 3; i++) { + runtime = TvmTestUtils.processTransactionAndReturnRuntime(trx, rootDeposit, null); + if (runtime.getRuntimeError() == null) { + break; + } + } Assert.assertNull(runtime.getRuntimeError()); // Trigger contract method: deploy(bytes,uint) diff --git a/framework/src/test/java/org/tron/common/runtime/vm/FreezeTest.java b/framework/src/test/java/org/tron/common/runtime/vm/FreezeTest.java index a2f8790a8ba..8fea80d691a 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/FreezeTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/FreezeTest.java @@ -140,7 +140,7 @@ public void init() throws Exception { rootDeposit.commit(); ConfigLoader.disable = true; - //manager.getDynamicPropertiesStore().saveAllowTvmFreeze(1); + manager.getDynamicPropertiesStore().saveAllowTvmFreeze(1); VMConfig.initVmHardFork(true); VMConfig.initAllowTvmTransferTrc10(1); VMConfig.initAllowTvmConstantinople(1); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/ValidateMultiSignContractTest.java b/framework/src/test/java/org/tron/common/runtime/vm/ValidateMultiSignContractTest.java index 8064e58be22..4ce516cd11f 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/ValidateMultiSignContractTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/ValidateMultiSignContractTest.java @@ -1,14 +1,16 @@ package org.tron.common.runtime.vm; import com.google.protobuf.ByteString; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; import org.bouncycastle.util.encoders.Hex; +import org.junit.AfterClass; +import org.junit.Test; import org.testng.Assert; -import org.testng.annotations.Test; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; @@ -17,6 +19,7 @@ import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.ByteUtil; +import org.tron.common.utils.FileUtil; import org.tron.common.utils.Sha256Hash; import org.tron.common.utils.StringUtil; import org.tron.core.Constant; @@ -34,7 +37,7 @@ @Slf4j public class ValidateMultiSignContractTest { - private static final String dbPath = "output_PrecompiledContracts_test"; + private static final String dbPath = "output_ValidateMultiSignContract_test"; private static final String METHOD_SIGN = "validatemultisign(address,uint256,bytes32,bytes[])"; private static final byte[] longData; private static TronApplicationContext context; @@ -49,14 +52,28 @@ public class ValidateMultiSignContractTest { dbManager.getDynamicPropertiesStore().saveAllowMultiSign(1); dbManager.getDynamicPropertiesStore().saveTotalSignNum(5); - longData = new byte[100000000]; + longData = new byte[1000000]; Arrays.fill(longData, (byte) 2); } ValidateMultiSign contract = new ValidateMultiSign(); + /** + * Release resources. + */ + @AfterClass + public static void destroy() { + Args.clearParam(); + context.destroy(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + } + @Test - void testAddressNonExist() { + public void testAddressNonExist() { byte[] hash = Hash.sha3(longData); ECKey key = new ECKey(); byte[] sign = key.sign(hash).toByteArray(); @@ -70,7 +87,7 @@ void testAddressNonExist() { } @Test - void testDifferentCase() { + public void testDifferentCase() { //Create an account with permission ECKey key = new ECKey(); diff --git a/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java b/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java index ef27e6e6e66..e872b4ddfab 100644 --- a/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java +++ b/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java @@ -18,6 +18,7 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.tron.common.storage.rocksdb.RocksDbDataSourceImpl; import org.tron.common.utils.ByteArray; @@ -49,16 +50,23 @@ public class RocksDbDataSourceImplTest { */ @AfterClass public static void destroy() { + String directory = Args.getInstance().getStorage().getDbDirectory(); Args.clearParam(); if (FileUtil.deleteDir(new File(dbPath))) { logger.info("Release resources successful."); } else { logger.info("Release resources failure."); } + + if (FileUtil.deleteDir(new File(dbPath + directory))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } } - @Before - public void initDb() { + @BeforeClass + public static void initDb() { Args.setParam(new String[]{"--output-directory", dbPath}, "config-test-dbbackup.conf"); dataSourceTest = new RocksDbDataSourceImpl(dbPath + File.separator, "test_rocksDb"); } diff --git a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java index dfd2e6fc364..1ad57367fdd 100644 --- a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java +++ b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java @@ -1,6 +1,10 @@ package org.tron.core.actuator.utils; +import com.google.protobuf.ByteString; import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import lombok.extern.slf4j.Slf4j; import org.junit.AfterClass; import org.junit.Assert; @@ -9,10 +13,12 @@ import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; +import org.tron.common.utils.ByteArray; import org.tron.common.utils.FileUtil; import org.tron.common.utils.ForkController; import org.tron.core.Constant; import org.tron.core.config.DefaultConfig; +import org.tron.core.config.Parameter.ForkBlockVersionEnum; import org.tron.core.config.args.Args; import org.tron.core.db.Manager; import org.tron.core.exception.ContractValidateException; @@ -83,7 +89,7 @@ public void validProposalTypeCheck() throws ContractValidateException { public void validateCheck() { ProposalUtil actuatorUtil = new ProposalUtil(); DynamicPropertiesStore dynamicPropertiesStore = null; - ForkController forkUtils = null; + ForkController forkUtils = ForkController.instance(); long invalidValue = -1; try { @@ -299,6 +305,56 @@ public void validateCheck() { + "before [ALLOW_TVM_TRANSFER_TRC10] can be proposed", e.getMessage()); } - } + forkUtils.init(dbManager.getChainBaseManager()); + long maintenanceTimeInterval = forkUtils.getManager().getDynamicPropertiesStore() + .getMaintenanceTimeInterval(); + long hardForkTime = + ((ForkBlockVersionEnum.VERSION_4_0_1.getHardForkTime() - 1) / maintenanceTimeInterval + 1) + * maintenanceTimeInterval; + forkUtils.getManager().getDynamicPropertiesStore() + .saveLatestBlockHeaderTimestamp(hardForkTime + 1); + byte[] stats = new byte[27]; + Arrays.fill(stats, (byte) 1); + forkUtils.getManager().getDynamicPropertiesStore() + .statsByVersion(ForkBlockVersionEnum.VERSION_4_0_1.getValue(), stats); + ByteString address = ByteString + .copyFrom(ByteArray.fromHexString("a0ec6525979a351a54fa09fea64beb4cce33ffbb7a")); + List w = new ArrayList<>(); + w.add(address); + forkUtils.getManager().getWitnessScheduleStore().saveActiveWitnesses(w); + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_SHIELDED_TRC20_TRANSACTION + .getCode(), 2); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals("This value[ALLOW_SHIELDED_TRC20_TRANSACTION] is only allowed" + + " to be 1 or 0", e.getMessage()); + } + + hardForkTime = + ((ForkBlockVersionEnum.VERSION_4_3.getHardForkTime() - 1) / maintenanceTimeInterval + 1) + * maintenanceTimeInterval; + forkUtils.getManager().getDynamicPropertiesStore() + .saveLatestBlockHeaderTimestamp(hardForkTime + 1); + forkUtils.getManager().getDynamicPropertiesStore() + .statsByVersion(ForkBlockVersionEnum.VERSION_4_3.getValue(), stats); + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, ProposalType.FREE_NET_LIMIT + .getCode(), -1); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals("Bad chain parameter value, valid range is [0,100_000]", + e.getMessage()); + } + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.TOTAL_NET_LIMIT.getCode(), -1); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals("Bad chain parameter value, valid range is [0, 1_000_000_000_000L]", + e.getMessage()); + } + } } diff --git a/framework/src/test/java/org/tron/core/capsule/AccountCapsuleTest.java b/framework/src/test/java/org/tron/core/capsule/AccountCapsuleTest.java index 1558139ab73..e0a9e188b06 100644 --- a/framework/src/test/java/org/tron/core/capsule/AccountCapsuleTest.java +++ b/framework/src/test/java/org/tron/core/capsule/AccountCapsuleTest.java @@ -29,7 +29,6 @@ import org.tron.protos.Protocol.Vote; import org.tron.protos.contract.AssetIssueContractOuterClass.AssetIssueContract; -@Ignore public class AccountCapsuleTest { private static final String dbPath = "output_accountCapsule_test"; diff --git a/framework/src/test/java/org/tron/core/capsule/utils/AssetUtilTest.java b/framework/src/test/java/org/tron/core/capsule/utils/AssetUtilTest.java new file mode 100644 index 00000000000..11e77097baa --- /dev/null +++ b/framework/src/test/java/org/tron/core/capsule/utils/AssetUtilTest.java @@ -0,0 +1,139 @@ +/* + * java-tron is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * java-tron is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.tron.core.capsule.utils; + +import com.google.common.collect.Lists; +import com.google.protobuf.ByteString; +import java.io.File; +import java.util.List; +import java.util.Random; +import lombok.extern.slf4j.Slf4j; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Test; +import org.tron.common.application.TronApplicationContext; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.FileUtil; +import org.tron.core.Constant; +import org.tron.core.capsule.AccountAssetCapsule; +import org.tron.core.capsule.AccountCapsule; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.db.Manager; +import org.tron.core.store.AccountAssetStore; +import org.tron.protos.Protocol; + + + + +@Slf4j +public class AssetUtilTest { + + private static String dbPath = "output_AssetUtil_test"; + private static Manager dbManager; + private static TronApplicationContext context; + + static { + Args.setParam(new String[]{"-d", dbPath, "-w"}, Constant.TEST_CONF); + context = new TronApplicationContext(DefaultConfig.class); + dbManager = context.getBean(Manager.class); + } + + @AfterClass + public static void removeDb() { + Args.clearParam(); + FileUtil.deleteDir(new File(dbPath)); + } + + public static byte[] randomBytes(int length) { + //generate the random number + byte[] result = new byte[length]; + new Random().nextBytes(result); + return result; + } + + private static AccountCapsule createAccount() { + com.google.protobuf.ByteString accountName = + com.google.protobuf.ByteString.copyFrom(randomBytes(16)); + com.google.protobuf.ByteString address = + ByteString.copyFrom(randomBytes(32)); + Protocol.AccountType accountType = Protocol.AccountType.forNumber(1); + AccountCapsule accountCapsule = new AccountCapsule(accountName, address, accountType); + accountCapsule.addAssetV2(ByteArray.fromString(String.valueOf(1)), 1000L); + Protocol.Account build = accountCapsule.getInstance().toBuilder() + .addAllFrozenSupply(getFrozenList()) + .build(); + accountCapsule.setInstance(build); + + return accountCapsule; + } + + private static AccountCapsule createAccount2() { + AccountAssetStore accountAssetStore = dbManager.getAccountAssetStore(); + com.google.protobuf.ByteString accountName = + com.google.protobuf.ByteString.copyFrom(randomBytes(16)); + com.google.protobuf.ByteString address = ByteString.copyFrom(randomBytes(32)); + Protocol.AccountType accountType = Protocol.AccountType.forNumber(1); + AccountCapsule accountCapsule = new AccountCapsule(accountName, address, accountType); + Protocol.AccountAsset accountAsset = + Protocol.AccountAsset.newBuilder() + .setAddress(accountCapsule.getInstance().getAddress()) + .setAssetIssuedID(accountCapsule.getAssetIssuedID()) + .setAssetIssuedName(accountCapsule.getAssetIssuedName()) + .build(); + accountAssetStore.put(accountCapsule.createDbKey(), + new AccountAssetCapsule( + accountAsset)); + return accountCapsule; + } + + @Test + public void testGetAsset() { + AccountCapsule account = createAccount(); + Protocol.AccountAsset asset = AssetUtil.getAsset(account.getInstance()); + Assert.assertNotNull(asset); + } + + @Test + public void testImport() { + AccountCapsule account = createAccount2(); + Protocol.Account asset = AssetUtil.importAsset(account.getInstance()); + Assert.assertNotNull(asset); + } + + @Test + public void tetGetFrozen() { + AccountCapsule account = createAccount2(); + Protocol.Account build = account.getInstance().toBuilder() + .addAllFrozenSupply(getFrozenList()) + .build(); + account.setInstance(build); + Assert.assertNotNull(account.getFrozenSupplyList()); + } + + private static List getFrozenList() { + List frozenList = Lists.newArrayList(); + for (int i = 0; i < 3; i++) { + Protocol.Account.Frozen newFrozen = Protocol.Account.Frozen.newBuilder() + .setFrozenBalance(i * 1000 + 1) + .setExpireTime(1000) + .build(); + frozenList.add(newFrozen); + } + return frozenList; + } + +} diff --git a/framework/src/test/java/org/tron/core/config/args/StorageTest.java b/framework/src/test/java/org/tron/core/config/args/StorageTest.java index f8086cc6f11..c025acc4ea0 100644 --- a/framework/src/test/java/org/tron/core/config/args/StorageTest.java +++ b/framework/src/test/java/org/tron/core/config/args/StorageTest.java @@ -80,9 +80,9 @@ public void getOptions() { Assert.assertTrue(options.verifyChecksums()); Assert.assertEquals(CompressionType.SNAPPY, options.compressionType()); Assert.assertEquals(4 * 1024, options.blockSize()); - Assert.assertEquals(10 * 1024 * 1024, options.writeBufferSize()); - Assert.assertEquals(10 * 1024 * 1024L, options.cacheSize()); - Assert.assertEquals(100, options.maxOpenFiles()); + Assert.assertEquals(64 * 1024 * 1024, options.writeBufferSize()); + Assert.assertEquals(32 * 1024 * 1024L, options.cacheSize()); + Assert.assertEquals(5000, options.maxOpenFiles()); } } diff --git a/framework/src/test/java/org/tron/core/db/EnergyPriceHistoryLoaderTest.java b/framework/src/test/java/org/tron/core/db/EnergyPriceHistoryLoaderTest.java new file mode 100644 index 00000000000..7700dbdead2 --- /dev/null +++ b/framework/src/test/java/org/tron/core/db/EnergyPriceHistoryLoaderTest.java @@ -0,0 +1,184 @@ +package org.tron.core.db; + +import static org.tron.core.store.DynamicPropertiesStore.DEFAULT_ENERGY_PRICE_HISTORY; +import static org.tron.core.utils.ProposalUtil.ProposalType.ALLOW_CREATION_OF_CONTRACTS; +import static org.tron.core.utils.ProposalUtil.ProposalType.ASSET_ISSUE_FEE; +import static org.tron.core.utils.ProposalUtil.ProposalType.ENERGY_FEE; +import static org.tron.core.utils.ProposalUtil.ProposalType.MAX_FEE_LIMIT; +import static org.tron.core.utils.ProposalUtil.ProposalType.TRANSACTION_FEE; +import static org.tron.core.utils.ProposalUtil.ProposalType.WITNESS_127_PAY_PER_BLOCK; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.tron.common.application.TronApplicationContext; +import org.tron.common.utils.FileUtil; +import org.tron.core.ChainBaseManager; +import org.tron.core.Constant; +import org.tron.core.capsule.ProposalCapsule; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.db.api.EnergyPriceHistoryLoader; +import org.tron.core.store.ProposalStore; +import org.tron.protos.Protocol.Proposal; +import org.tron.protos.Protocol.Proposal.State; + + +@Slf4j +public class EnergyPriceHistoryLoaderTest { + + private static ChainBaseManager chainBaseManager; + private static TronApplicationContext context; + private static String dbPath = "output-EnergyPriceHistoryLoaderTest-test"; + private static long t1 = 1542607200000L; + private static long price1 = 20; + private static long t3 = 1544724000000L; + private static long price3 = 10; + private static long t4 = 1606240800000L; + private static long price4 = 40; + private static long t5 = 1613044800000L; + private static long price5 = 140L; + + static { + Args.setParam(new String[] {"--output-directory", dbPath}, Constant.TEST_CONF); + context = new TronApplicationContext(DefaultConfig.class); + } + + @BeforeClass + public static void init() { + chainBaseManager = context.getBean(ChainBaseManager.class); + } + + @AfterClass + public static void destroy() { + Args.clearParam(); + context.destroy(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + } + + public void initDB() { + t1 = 1542607200000L; + price1 = 20; + initProposal(ENERGY_FEE.getCode(), t1, price1, State.APPROVED); + + long t2 = 1543168800000L; + long price2 = 11; + initProposal(ENERGY_FEE.getCode(), t2, price2, State.DISAPPROVED); + + t3 = 1544724000000L; + price3 = 10; + initProposal(ENERGY_FEE.getCode(), t3, price3, State.APPROVED); + + t4 = 1606240800000L; + price4 = 40; + initProposal(ENERGY_FEE.getCode(), t4, price4, State.APPROVED); + + t5 = 1613044800000L; + price5 = 140L; + Map parameters = new HashMap<>(); + parameters.put(TRANSACTION_FEE.getCode(), 140L); + parameters.put(ENERGY_FEE.getCode(), price5); + parameters.put(MAX_FEE_LIMIT.getCode(), 5000000000L); + initProposal(parameters, t5, State.APPROVED); + + long t6 = 1629700950000L; + long price6 = 420; + initProposal(ENERGY_FEE.getCode(), t6, price6, State.DISAPPROVED); + + initProposal(ALLOW_CREATION_OF_CONTRACTS.getCode(), 1539259200000L, 1, State.APPROVED); + + parameters = new HashMap<>(); + parameters.put(ASSET_ISSUE_FEE.getCode(), 48000000L); + parameters.put(WITNESS_127_PAY_PER_BLOCK.getCode(), 128000000L); + initProposal(parameters, 1572609600000L, State.CANCELED); + } + + private static void initProposal(long code, long timestamp, long price, State state) { + long id = chainBaseManager.getDynamicPropertiesStore().getLatestProposalNum() + 1; + + Proposal proposal = Proposal.newBuilder().putParameters(code, price) + .setExpirationTime(timestamp) + .setState(state) + .setProposalId(id) + .build(); + ProposalCapsule proposalCapsule = new ProposalCapsule(proposal); + + chainBaseManager.getProposalStore().put(proposalCapsule.createDbKey(), proposalCapsule); + chainBaseManager.getDynamicPropertiesStore().saveLatestProposalNum(id); + } + + private static void initProposal(Map parameters, long timestamp, State state) { + long id = chainBaseManager.getDynamicPropertiesStore().getLatestProposalNum() + 1; + + Proposal proposal = Proposal.newBuilder().putAllParameters(parameters) + .setExpirationTime(timestamp) + .setState(state) + .setProposalId(id) + .build(); + ProposalCapsule proposalCapsule = new ProposalCapsule(proposal); + + chainBaseManager.getProposalStore().put(proposalCapsule.createDbKey(), proposalCapsule); + chainBaseManager.getDynamicPropertiesStore().saveLatestProposalNum(id); + } + + @Test + public void testLoader() { + if (chainBaseManager == null) { + init(); + } + EnergyPriceHistoryLoader loader = new EnergyPriceHistoryLoader(chainBaseManager); + + initDB(); + + String preEnergyPriceHistory = + chainBaseManager.getDynamicPropertiesStore().getEnergyPriceHistory(); + String expectedRes = preEnergyPriceHistory + "," + t1 + ":" + price1 + + "," + t3 + ":" + price3 + + "," + t4 + ":" + price4 + + "," + t5 + ":" + price5; + + loader.getEnergyProposals(); + String historyStr = loader.parseProposalsToStr(); + + Assert.assertEquals(expectedRes, historyStr); + } + + @Test + public void testProposalEmpty() { + if (chainBaseManager == null) { + init(); + } + + // clean DB firstly + ProposalStore proposalStore = chainBaseManager.getProposalStore(); + proposalStore.forEach( + bytesCapsuleEntry -> proposalStore + .delete(bytesCapsuleEntry.getKey())); + chainBaseManager.getDynamicPropertiesStore().saveEnergyPriceHistoryDone(0); + + String preEnergyPriceHistory = + chainBaseManager.getDynamicPropertiesStore().getEnergyPriceHistory(); + Assert.assertEquals(DEFAULT_ENERGY_PRICE_HISTORY, preEnergyPriceHistory); + + // loader work + EnergyPriceHistoryLoader loader = new EnergyPriceHistoryLoader(chainBaseManager); + loader.doWork(); + + // check result + String afterEnergyPriceHistory = + chainBaseManager.getDynamicPropertiesStore().getEnergyPriceHistory(); + Assert.assertEquals(DEFAULT_ENERGY_PRICE_HISTORY, afterEnergyPriceHistory); + Assert.assertEquals(1L, + chainBaseManager.getDynamicPropertiesStore().getEnergyPriceHistoryDone()); + } +} diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index 5b4f60d2e36..645a1543fb2 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -231,23 +231,6 @@ public void GetterInstanceTest() { } - - @Test - public void pushBlockInvalidSignature() { - // invalid witness address cause invalid signature - String invalidWitness = "bcab94c3e0c9214fb4ac7ff9d7d5a937d1f40031f"; - blockCapsule2.setWitness(invalidWitness); - try { - dbManager.pushBlock(blockCapsule2); - Assert.assertTrue(false); - } catch (BadBlockException e) { - Assert.assertEquals("The signature is not validated", e.getMessage()); - } catch (Exception e) { - Assert.assertFalse(e instanceof Exception); - } - } - - @Test public void getHeadTest() { try { diff --git a/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java b/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java index 7f4c5426781..dcb899dde19 100644 --- a/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java +++ b/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java @@ -7,7 +7,7 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; -import org.testng.annotations.Test; +import org.junit.Test; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; @@ -155,7 +155,5 @@ public void test() { Assert.assertEquals( 30000000L, accountCapsule.getLatestAssetOperationTimeMapV2().get("1000001").longValue()); } - - removeDb(); } } diff --git a/framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java b/framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java new file mode 100644 index 00000000000..7c9d2f5ba23 --- /dev/null +++ b/framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java @@ -0,0 +1,112 @@ +package org.tron.core.jsonrpc; + +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getMethodSign; +import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.parseEnergyFee; + +import org.bouncycastle.util.encoders.Hex; +import org.junit.Assert; +import org.junit.Test; +import org.tron.common.crypto.Hash; +import org.tron.common.runtime.vm.DataWord; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ByteUtil; +import org.tron.common.utils.Commons; +import org.tron.core.services.jsonrpc.CallArguments; + + +public class JsonRpcTest { + + public void generateCallParameterWIthMethodAndParam() { + String ownerAddress = "TXvRyjomvtNWSKvNouTvAedRGD4w9RXLZD"; + String usdjAddress = "TLBaRhANQoJFTqre9Nf1mjuwNWjCJeYqUL"; // nile udsj address + + byte[] addressData = Commons.decodeFromBase58Check(ownerAddress); + byte[] addressDataWord = new byte[32]; + System.arraycopy(Commons.decodeFromBase58Check(ownerAddress), 0, addressDataWord, + 32 - addressData.length, addressData.length); + String data = getMethodSign("balanceOf(address)") + Hex.toHexString(addressDataWord); + + CallArguments transactionCall = new CallArguments(); + transactionCall.from = ByteArray.toHexString(Commons.decodeFromBase58Check(ownerAddress)); + transactionCall.to = ByteArray.toHexString(Commons.decodeFromBase58Check(usdjAddress)); + transactionCall.data = data; + + StringBuffer sb = new StringBuffer("{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":["); + sb.append(transactionCall); + sb.append(", \"latest\"],\"id\":1}"); + + System.out.println(sb.toString()); + } + + public void generateCallParameterWithMethod() { + String ownerAddress = "TRXPT6Ny7EFvTPv7mFUqaFUST39WUZ4zzz"; + String usdjAddress = "TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf"; // nile udsj address + + byte[] addressData = Commons.decodeFromBase58Check(ownerAddress); + byte[] addressDataWord = new byte[32]; + System.arraycopy(Commons.decodeFromBase58Check(ownerAddress), 0, addressDataWord, + 32 - addressData.length, addressData.length); + String data = getMethodSign("name()"); + + CallArguments transactionCall = new CallArguments(); + transactionCall.from = ByteArray.toHexString(Commons.decodeFromBase58Check(ownerAddress)); + transactionCall.to = ByteArray.toHexString(Commons.decodeFromBase58Check(usdjAddress)); + transactionCall.data = data; + + StringBuffer sb = new StringBuffer("{\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":["); + sb.append(transactionCall); + sb.append(", \"latest\"],\"id\":1}"); + + System.out.println(sb.toString()); + } + + private String generateStorageParameter() { + // nile contract:TXEphLzyv5jFwvjzwMok9UoehaSn294ZhN + String contractAddress = "41E94EAD5F4CA072A25B2E5500934709F1AEE3C64B"; + + // nile:TXvRyjomvtNWSKvNouTvAedRGD4w9RXLZD + String sendAddress = "41F0CC5A2A84CD0F68ED1667070934542D673ACBD8"; + String index = "01"; + byte[] byte1 = new DataWord(new DataWord(sendAddress).getLast20Bytes()).getData(); + byte[] byte2 = new DataWord(new DataWord(index).getLast20Bytes()).getData(); + byte[] byte3 = ByteUtil.merge(byte1, byte2); + String position = ByteArray.toJsonHex(Hash.sha3(byte3)); + + StringBuffer sb = new StringBuffer( + "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getStorageAt\",\"params\":[\"0x"); + sb.append(contractAddress + "\",\""); + sb.append(position + "\","); + sb.append("\"latest\"],\"id\":1}"); + return sb.toString(); + } + + private String constructData(String functionSelector, String parameter) { + String data = getMethodSign(functionSelector) + parameter; + return data; + } + + @Test + public void testConstructData() { + String expectedData = + "07211ef7000000000000000000000000000000000000000000000000000000000000000" + + "3000000000000000000000000000000000000000000000000000000000000000100" + + "000000000000000000000000000000000000000000000000000000000f4240"; + + String functionSelector = "get_dy_underlying(int128,int128,uint256)"; + String parameter = "000000000000000000000000000000000000000000000000000000000" + + "00000030000000000000000000000000000000000000000000000000000000000000001" + + "00000000000000000000000000000000000000000000000000000000000f4240"; + Assert.assertEquals(expectedData, constructData(functionSelector, parameter)); + } + + @Test + public void testGetEnergyPrice() { + String energyPriceHistory = + "0:100,1542607200000:20,1544724000000:10,1606240800000:40,1613044800000:140"; + Assert.assertEquals(100L, parseEnergyFee(1542607100000L, energyPriceHistory)); + Assert.assertEquals(20L, parseEnergyFee(1542607210000L, energyPriceHistory)); + Assert.assertEquals(10L, parseEnergyFee(1544724100000L, energyPriceHistory)); + Assert.assertEquals(40L, parseEnergyFee(1606240810000L, energyPriceHistory)); + Assert.assertEquals(140L, parseEnergyFee(1613044810000L, energyPriceHistory)); + } +} diff --git a/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java b/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java index f788c31cfca..10faf6e19ca 100644 --- a/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java +++ b/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java @@ -1,13 +1,15 @@ package org.tron.core.services; +import static org.tron.core.utils.ProposalUtil.ProposalType.ENERGY_FEE; import static org.tron.core.utils.ProposalUtil.ProposalType.WITNESS_127_PAY_PER_BLOCK; import java.io.File; import java.util.HashSet; import java.util.Set; -import org.junit.After; +import lombok.extern.slf4j.Slf4j; +import org.junit.AfterClass; import org.junit.Assert; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.tron.common.application.TronApplicationContext; import org.tron.common.utils.FileUtil; @@ -20,14 +22,15 @@ import org.tron.core.utils.ProposalUtil.ProposalType; import org.tron.protos.Protocol.Proposal; +@Slf4j public class ProposalServiceTest { - private TronApplicationContext context; - private Manager manager; - private String dbPath = "output_proposal_test"; + private static TronApplicationContext context; + private static Manager manager; + private static String dbPath = "output_proposal_test"; - @Before - public void init() { + @BeforeClass + public static void init() { Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF); context = new TronApplicationContext(DefaultConfig.class); manager = context.getBean(Manager.class); @@ -63,11 +66,32 @@ public void test() { } } + @Test + public void testUpdateEnergyFee() { + String preHistory = manager.getDynamicPropertiesStore().getEnergyPriceHistory(); + + long newPrice = 500; + Proposal proposal = Proposal.newBuilder().putParameters(ENERGY_FEE.getCode(), newPrice).build(); + ProposalCapsule proposalCapsule = new ProposalCapsule(proposal); + boolean result = ProposalService.process(manager, proposalCapsule); + Assert.assertTrue(result); - @After - public void removeDb() { + long currentPrice = manager.getDynamicPropertiesStore().getEnergyFee(); + Assert.assertEquals(currentPrice, newPrice); + + String currentHistory = manager.getDynamicPropertiesStore().getEnergyPriceHistory(); + Assert.assertEquals(preHistory + "," + proposalCapsule.getExpirationTime() + ":" + newPrice, + currentHistory); + } + + @AfterClass + public static void removeDb() { Args.clearParam(); context.destroy(); - FileUtil.deleteDir(new File(dbPath)); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } } -} +} \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/services/filter/HttpApiAccessFilterTest.java b/framework/src/test/java/org/tron/core/services/filter/HttpApiAccessFilterTest.java new file mode 100644 index 00000000000..4a288b4402c --- /dev/null +++ b/framework/src/test/java/org/tron/core/services/filter/HttpApiAccessFilterTest.java @@ -0,0 +1,156 @@ +package org.tron.core.services.filter; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tron.common.application.Application; +import org.tron.common.application.ApplicationFactory; +import org.tron.common.application.TronApplicationContext; +import org.tron.common.utils.FileUtil; +import org.tron.core.Constant; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.services.http.FullNodeHttpApiService; +import org.tron.core.services.interfaceOnPBFT.http.PBFT.HttpApiOnPBFTService; +import org.tron.core.services.interfaceOnSolidity.http.solidity.HttpApiOnSolidityService; + +public class HttpApiAccessFilterTest { + + private static final Logger logger = LoggerFactory.getLogger("Test"); + + private static TronApplicationContext context; + private static Application appTest; + private static CloseableHttpClient httpClient = HttpClients.createDefault(); + private static String dbPath = "output_http_api_access_filter_test"; + + /** + * init dependencies. + */ + @BeforeClass + public static void init() { + Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF); + Args.getInstance().setFullNodeAllowShieldedTransactionArgs(false); + context = new TronApplicationContext(DefaultConfig.class); + appTest = ApplicationFactory.create(context); + + FullNodeHttpApiService httpApiService = context + .getBean(FullNodeHttpApiService.class); + HttpApiOnSolidityService httpApiOnSolidityService = context + .getBean(HttpApiOnSolidityService.class); + HttpApiOnPBFTService httpApiOnPBFTService = context + .getBean(HttpApiOnPBFTService.class); + + appTest.addService(httpApiService); + appTest.addService(httpApiOnSolidityService); + appTest.addService(httpApiOnPBFTService); + appTest.initServices(Args.getInstance()); + appTest.startServices(); + appTest.startup(); + } + + /** + * destroy the context. + */ + @AfterClass + public static void destroy() { + Args.clearParam(); + appTest.shutdownServices(); + appTest.shutdown(); + context.destroy(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + } + + @Test + public void testHttpFilter() { + List disabledApiList = new ArrayList<>(); + disabledApiList.add("getaccount"); + disabledApiList.add("getnowblock"); + + List emptyList = Collections.emptyList(); + + List patterns = new ArrayList<>(); + patterns.add("/walletsolidity/"); + patterns.add("/walletpbft/"); + patterns.add("/wallet/"); + + int httpPort; + String ip = "127.0.0.1"; + for (String api : disabledApiList) { + for (String pattern : patterns) { + String urlPath = pattern + api; + if (urlPath.contains("/walletsolidity")) { + httpPort = Args.getInstance().getSolidityHttpPort(); + } else if (urlPath.contains("/walletpbft")) { + httpPort = Args.getInstance().getPBFTHttpPort(); + } else { + httpPort = Args.getInstance().getFullNodeHttpPort(); + } + + String url = String.format("http://%s:%d%s", ip, httpPort, urlPath); + + Args.getInstance().setDisabledApiList(disabledApiList); + String response = sendGetRequest(url); + Assert.assertEquals("{\"Error\":\"this API is unavailable due to config\"}", + response); + + Args.getInstance().setDisabledApiList(emptyList); + int statusCode = getReuqestCode(url); + Assert.assertEquals(HttpStatus.SC_OK, statusCode); + } + } + } + + private String sendGetRequest(String url) { + HttpGet request = new HttpGet(url); + request.setHeader("User-Agent", "Java client"); + HttpResponse response = null; + try { + response = httpClient.execute(request); + BufferedReader rd = new BufferedReader( + new InputStreamReader(response.getEntity().getContent())); + StringBuffer result = new StringBuffer(); + String line; + while ((line = rd.readLine()) != null) { + result.append(line); + } + return result.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + private int getReuqestCode(String url) { + HttpGet request = new HttpGet(url); + request.setHeader("User-Agent", "Java client"); + HttpResponse response = null; + + try { + response = httpClient.execute(request); + return response.getStatusLine().getStatusCode(); + } catch (IOException e) { + e.printStackTrace(); + } + + return 0; + } +} diff --git a/framework/src/test/java/org/tron/core/services/filter/RpcApiAccessInterceptorTest.java b/framework/src/test/java/org/tron/core/services/filter/RpcApiAccessInterceptorTest.java new file mode 100644 index 00000000000..c3ef7265f65 --- /dev/null +++ b/framework/src/test/java/org/tron/core/services/filter/RpcApiAccessInterceptorTest.java @@ -0,0 +1,169 @@ +package org.tron.core.services.filter; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tron.api.GrpcAPI; +import org.tron.api.WalletGrpc; +import org.tron.api.WalletSolidityGrpc; +import org.tron.common.application.Application; +import org.tron.common.application.ApplicationFactory; +import org.tron.common.application.TronApplicationContext; +import org.tron.common.utils.FileUtil; +import org.tron.core.Constant; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.services.RpcApiService; +import org.tron.core.services.interfaceOnPBFT.RpcApiServiceOnPBFT; +import org.tron.core.services.interfaceOnSolidity.RpcApiServiceOnSolidity; + +public class RpcApiAccessInterceptorTest { + + private static final Logger logger = LoggerFactory.getLogger("Test"); + + private static TronApplicationContext context; + + private static WalletGrpc.WalletBlockingStub blockingStubFull = null; + private static WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubSolidity = null; + private static WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubPBFT = null; + private static Application appTest; + + private static String dbPath = "output_rpc_api_access_filter_test"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + /** + * init logic. + */ + @BeforeClass + public static void init() { + Args.setParam(new String[] {"-d", dbPath}, Constant.TEST_CONF); + String fullNode = String.format("%s:%d", Args.getInstance().getNodeDiscoveryBindIp(), + Args.getInstance().getRpcPort()); + String solidityNode = String.format("%s:%d", Args.getInstance().getNodeDiscoveryBindIp(), + Args.getInstance().getRpcOnSolidityPort()); + String pBFTNode = String.format("%s:%d", Args.getInstance().getNodeDiscoveryBindIp(), + Args.getInstance().getRpcOnPBFTPort()); + + ManagedChannel channelFull = ManagedChannelBuilder.forTarget(fullNode) + .usePlaintext() + .build(); + ManagedChannel channelpBFT = ManagedChannelBuilder.forTarget(pBFTNode) + .usePlaintext() + .build(); + ManagedChannel channelSolidity = ManagedChannelBuilder.forTarget(solidityNode) + .usePlaintext() + .build(); + + context = new TronApplicationContext(DefaultConfig.class); + + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + blockingStubSolidity = WalletSolidityGrpc.newBlockingStub(channelSolidity); + blockingStubPBFT = WalletSolidityGrpc.newBlockingStub(channelpBFT); + + RpcApiService rpcApiService = context.getBean(RpcApiService.class); + RpcApiServiceOnSolidity rpcApiServiceOnSolidity = + context.getBean(RpcApiServiceOnSolidity.class); + RpcApiServiceOnPBFT rpcApiServiceOnPBFT = context.getBean(RpcApiServiceOnPBFT.class); + + appTest = ApplicationFactory.create(context); + appTest.addService(rpcApiService); + appTest.addService(rpcApiServiceOnSolidity); + appTest.addService(rpcApiServiceOnPBFT); + appTest.initServices(Args.getInstance()); + appTest.startServices(); + appTest.startup(); + } + + /** + * destroy the context. + */ + @AfterClass + public static void destroy() { + Args.clearParam(); + appTest.shutdownServices(); + appTest.shutdown(); + context.destroy(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + } + + @Test + public void testAccessDisabledFullNode() { + List disabledApiList = new ArrayList<>(); + disabledApiList.add("getaccount"); + disabledApiList.add("getblockbynum"); + Args.getInstance().setDisabledApiList(disabledApiList); + + final GrpcAPI.NumberMessage message = GrpcAPI.NumberMessage.newBuilder().setNum(0).build(); + thrown.expect(StatusRuntimeException.class); + thrown.expectMessage("this API is unavailable due to config"); + blockingStubFull.getBlockByNum(message); + } + + @Test + public void testAccessDisabledSolidityNode() { + List disabledApiList = new ArrayList<>(); + disabledApiList.add("getaccount"); + disabledApiList.add("getblockbynum"); + Args.getInstance().setDisabledApiList(disabledApiList); + + final GrpcAPI.NumberMessage message = GrpcAPI.NumberMessage.newBuilder().setNum(0).build(); + thrown.expect(StatusRuntimeException.class); + thrown.expectMessage("this API is unavailable due to config"); + blockingStubSolidity.getBlockByNum(message); + } + + @Test + public void testAccessDisabledPBFTNode() { + List disabledApiList = new ArrayList<>(); + disabledApiList.add("getaccount"); + disabledApiList.add("getblockbynum"); + Args.getInstance().setDisabledApiList(disabledApiList); + + final GrpcAPI.NumberMessage message = GrpcAPI.NumberMessage.newBuilder().setNum(0).build(); + thrown.expect(StatusRuntimeException.class); + thrown.expectMessage("this API is unavailable due to config"); + blockingStubPBFT.getBlockByNum(message); + } + + @Test + public void testAccessNoDisabled() { + Args.getInstance().setDisabledApiList(Collections.emptyList()); + + final GrpcAPI.NumberMessage message = GrpcAPI.NumberMessage.newBuilder().setNum(0).build(); + Assert.assertNotNull(blockingStubFull.getBlockByNum(message)); + Assert.assertNotNull(blockingStubSolidity.getBlockByNum(message)); + Assert.assertNotNull(blockingStubPBFT.getBlockByNum(message)); + } + + @Test + public void testAccessDisabledNotIncluded() { + List disabledApiList = new ArrayList<>(); + disabledApiList.add("getaccount"); + Args.getInstance().setDisabledApiList(disabledApiList); + + final GrpcAPI.NumberMessage message = GrpcAPI.NumberMessage.newBuilder().setNum(0).build(); + Assert.assertNotNull(blockingStubFull.getBlockByNum(message)); + Assert.assertNotNull(blockingStubSolidity.getBlockByNum(message)); + Assert.assertNotNull(blockingStubPBFT.getBlockByNum(message)); + } + +} + diff --git a/framework/src/test/java/org/tron/program/DBConvertTest.java b/framework/src/test/java/org/tron/program/DBConvertTest.java new file mode 100644 index 00000000000..7b3f797d627 --- /dev/null +++ b/framework/src/test/java/org/tron/program/DBConvertTest.java @@ -0,0 +1,116 @@ +package org.tron.program; + +import static org.fusesource.leveldbjni.JniDBFactory.factory; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import org.iq80.leveldb.DB; +import org.iq80.leveldb.Options; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.FileUtil; +import org.tron.common.utils.MarketOrderPriceComparatorForLevelDB; +import org.tron.core.capsule.MarketOrderIdListCapsule; +import org.tron.core.capsule.utils.MarketUtils; + +public class DBConvertTest { + + + private static final String INPUT_DIRECTORY = "output-directory/convert-database/"; + private static final String OUTPUT_DIRECTORY = "output-directory/convert-database-dest/"; + private static final String ACCOUNT = "account"; + private static final String MARKET = "market_pair_price_to_order"; + + + @BeforeClass + public static void init() throws IOException { + if (new File(INPUT_DIRECTORY).mkdirs()) { + initDB(new File(INPUT_DIRECTORY,ACCOUNT)); + initDB(new File(INPUT_DIRECTORY,MARKET)); + } + } + + private static void initDB(File file) throws IOException { + Options dbOptions = DBConvert.newDefaultLevelDbOptions(); + if (file.getName().contains("market_pair_price_to_order")) { + dbOptions.comparator(new MarketOrderPriceComparatorForLevelDB()); + try (DB db = factory.open(file,dbOptions)) { + + byte[] sellTokenID1 = ByteArray.fromString("100"); + byte[] buyTokenID1 = ByteArray.fromString("200"); + byte[] pairPriceKey1 = MarketUtils.createPairPriceKey( + sellTokenID1, + buyTokenID1, + 1000L, + 2001L + ); + byte[] pairPriceKey2 = MarketUtils.createPairPriceKey( + sellTokenID1, + buyTokenID1, + 1000L, + 2002L + ); + byte[] pairPriceKey3 = MarketUtils.createPairPriceKey( + sellTokenID1, + buyTokenID1, + 1000L, + 2003L + ); + + MarketOrderIdListCapsule capsule1 = new MarketOrderIdListCapsule(ByteArray.fromLong(1), + ByteArray.fromLong(1)); + MarketOrderIdListCapsule capsule2 = new MarketOrderIdListCapsule(ByteArray.fromLong(2), + ByteArray.fromLong(2)); + MarketOrderIdListCapsule capsule3 = new MarketOrderIdListCapsule(ByteArray.fromLong(3), + ByteArray.fromLong(3)); + + //Use out-of-order insertion,key in store should be 1,2,3 + db.put(pairPriceKey1, capsule1.getData()); + db.put(pairPriceKey2, capsule2.getData()); + db.put(pairPriceKey3, capsule3.getData()); + } + + } else { + try (DB db = factory.open(file,dbOptions)) { + for (int i = 0; i < 100; i++) { + byte[] bytes = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8); + db.put(bytes, bytes); + } + } + } + + } + + @AfterClass + public static void destroy() { + FileUtil.deleteDir(new File(INPUT_DIRECTORY)); + FileUtil.deleteDir(new File(OUTPUT_DIRECTORY)); + } + + @Test + public void testRun() { + String[] args = new String[] { INPUT_DIRECTORY, OUTPUT_DIRECTORY }; + Assert.assertEquals(0, DBConvert.run(args)); + } + + @Test + public void testNotExist() { + String[] args = new String[] {OUTPUT_DIRECTORY + File.separator + UUID.randomUUID(), + OUTPUT_DIRECTORY}; + Assert.assertEquals(404, DBConvert.run(args)); + } + + @Test + public void testEmpty() { + File file = new File(OUTPUT_DIRECTORY + File.separator + UUID.randomUUID()); + file.mkdirs(); + file.deleteOnExit(); + String[] args = new String[] {file.toString(), OUTPUT_DIRECTORY}; + Assert.assertEquals(0, DBConvert.run(args)); + } +} diff --git a/framework/src/test/java/stest/tron/wallet/common/client/utils/HttpMethed.java b/framework/src/test/java/stest/tron/wallet/common/client/utils/HttpMethed.java index 47e541ec572..b3cad3f11dd 100644 --- a/framework/src/test/java/stest/tron/wallet/common/client/utils/HttpMethed.java +++ b/framework/src/test/java/stest/tron/wallet/common/client/utils/HttpMethed.java @@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; @@ -417,6 +418,21 @@ public static HttpResponse deleteProposal(String httpNode, byte[] ownerAddress, /** * constructor. */ + public static HttpResponse getEnergyPric(String httpNode) { + try { + final String requestUrl = "http://" + httpNode + "/wallet/getenergyprices"; + response = createConnect(requestUrl); + } catch (Exception e) { + e.printStackTrace(); + httppost.releaseConnection(); + return null; + } + return response; + } + /** + * constructor. + */ + public static HttpResponse getChainParameters(String httpNode) { try { final String requestUrl = "http://" + httpNode + "/wallet/getchainparameters"; @@ -1414,6 +1430,22 @@ public static HttpResponse listNodes(String httpNode) { return response; } + + /** + * constructor. + */ + public static HttpResponse getStatsInfo(String httpNode) { + try { + String requestUrl = "http://" + httpNode + "/monitor/getstatsinfo"; + response = createConnectForGet(requestUrl); + } catch (Exception e) { + e.printStackTrace(); + httppost.releaseConnection(); + return null; + } + return response; + } + /** * constructor. */ @@ -2021,6 +2053,9 @@ public static Long getBalance(String httpNode, byte[] queryAddress) { responseContent = HttpMethed.parseResponseContent(response); //HttpMethed.printJsonContent(responseContent); //httppost.releaseConnection(); + if (!responseContent.containsKey("balance")) { + return 0L; + } return Long.parseLong(responseContent.get("balance").toString()); } @@ -2731,6 +2766,30 @@ public static HttpResponse createConnect(String url, JsonObject requestBody) { return response; } + + /** + * constructor. + */ + public static HttpResponse createConnectForGet(String url) { + try { + httpClient.getParams() + .setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectionTimeout); + httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, soTimeout); + HttpGet httppost; + httppost = new HttpGet(url); + httppost.setHeader("Content-type", "application/json; charset=utf-8"); + httppost.setHeader("Connection", "Close"); + + logger.info(httppost.toString()); + response = httpClient.execute(httppost); + } catch (Exception e) { + e.printStackTrace(); + httppost.releaseConnection(); + return null; + } + return response; + } + /** * constructor. */ @@ -3082,6 +3141,24 @@ public static HttpResponse generateAddress(String httpNode) { return response; } + /** + * constructor. + */ + public static HttpResponse getTransactionCountByBlocknum(String httpNode, long blocknum) { + try { + String requestUrl = + "http://" + httpNode + "/wallet/gettransactioncountbyblocknum"; + JsonObject userBaseObj2 = new JsonObject(); + userBaseObj2.addProperty("num", blocknum); + response = createConnect(requestUrl, userBaseObj2); + } catch (Exception e) { + e.printStackTrace(); + httppost.releaseConnection(); + return null; + } + return response; + } + /** * constructor. @@ -3196,6 +3273,24 @@ public static HttpResponse easyTransferAssetByPrivate(String httpNode, String pr } + /** + * constructor. + */ + public static HttpResponse getContractInfo(String httpNode, String contractAddress) { + try { + String requestUrl = "http://" + httpNode + "/wallet/getcontractinfo"; + JsonObject userBaseObj2 = new JsonObject(); + userBaseObj2.addProperty("value", contractAddress); + response = createConnect(requestUrl, userBaseObj2); + } catch (Exception e) { + e.printStackTrace(); + httppost.releaseConnection(); + return null; + } + return response; + } + + /** * constructor. */ @@ -5213,11 +5308,11 @@ public static HttpResponse getTransactionListFromPending(String httpNode) { /** * constructor. */ - public static HttpResponse getTransactionFromPending(String httpNode,String txid) { + public static HttpResponse getTransactionFromPending(String httpNode, String txid) { try { String requestUrl = "http://" + httpNode + "/wallet/gettransactionfrompending"; JsonObject userBaseObj2 = new JsonObject(); - userBaseObj2.addProperty("value",txid); + userBaseObj2.addProperty("value", txid); response = createConnect(requestUrl, userBaseObj2); } catch (Exception e) { e.printStackTrace(); diff --git a/framework/src/test/java/stest/tron/wallet/common/client/utils/JsonRpcBase.java b/framework/src/test/java/stest/tron/wallet/common/client/utils/JsonRpcBase.java new file mode 100644 index 00000000000..55ede39790c --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/common/client/utils/JsonRpcBase.java @@ -0,0 +1,384 @@ +package stest.tron.wallet.common.client.utils; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.protobuf.ByteString; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Status; +import io.netty.util.internal.StringUtil; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Optional; +// import java.util.*; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.bouncycastle.util.encoders.Hex; +import org.testng.Assert; +import org.testng.annotations.BeforeSuite; +import org.tron.api.GrpcAPI; +import org.tron.api.GrpcAPI.BytesMessage; +import org.tron.api.GrpcAPI.EmptyMessage; +import org.tron.api.GrpcAPI.Note; +import org.tron.api.GrpcAPI.ShieldedTRC20Parameters; +import org.tron.api.GrpcAPI.TransactionExtention; +import org.tron.api.WalletGrpc; +import org.tron.api.WalletSolidityGrpc; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ByteUtil; +import org.tron.common.utils.Commons; +import org.tron.core.Wallet; +import org.tron.core.exception.ZksnarkException; +import org.tron.core.services.http.Util; +import org.tron.core.zen.address.DiversifierT; +import org.tron.protos.Protocol.TransactionInfo; +import org.tron.protos.contract.ShieldContract; +import stest.tron.wallet.common.client.Configuration; +import stest.tron.wallet.common.client.Parameter.CommonConstant; + +@Slf4j +public class JsonRpcBase { + + public final String foundationAccountKey = + Configuration.getByPath("testng.conf").getString("foundationAccount.key1"); + public final byte[] foundationAccountAddress = PublicMethed.getFinalAddress(foundationAccountKey); + + public static final String jsonRpcOwnerKey = + Configuration.getByPath("testng.conf").getString("defaultParameter.jsonRpcOwnerKey"); + public static final byte[] jsonRpcOwnerAddress = PublicMethed.getFinalAddress(jsonRpcOwnerKey); + public static final String jsonRpcOwnerAddressString = + PublicMethed.getAddressString(jsonRpcOwnerKey); + + public static String jsonRpcNode = + Configuration.getByPath("testng.conf").getStringList("jsonRpcNode.ip.list").get(0); + public static String httpFullNode = + Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list").get(0); + public static String ethHttpsNode = + Configuration.getByPath("testng.conf").getStringList("ethHttpsNode.host.list").get(0); + + public ManagedChannel channelFull = null; + public WalletGrpc.WalletBlockingStub blockingStubFull = null; + public ManagedChannel channelSolidity = null; + public ManagedChannel channelPbft = null; + + public WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubSolidity = null; + public WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubPbft = null; + public String fullnode = + Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list").get(0); + + public static long maxFeeLimit = + Configuration.getByPath("testng.conf").getLong("defaultParameter.maxFeeLimit"); + public static String trc20AddressByteString; + public static String trc20AddressHex; + public static String contractAddressFrom58; + public static String contractAddressFromHex; + public static ByteString shieldAddressByteString; + public static byte[] shieldAddressByte; + public static String shieldAddress; + public static String deployTrc20Txid; + public static String deployShieldTxid; + public static String mint = "mint(uint256,bytes32[9],bytes32[2],bytes32[21])"; + public static String transfer = + "transfer(bytes32[10][],bytes32[2][],bytes32[9][],bytes32[2],bytes32[21][])"; + public static String burn = + "burn(bytes32[10],bytes32[2],uint256,bytes32[2],address," + + "bytes32[3],bytes32[9][],bytes32[21][])"; + public Wallet wallet = new Wallet(); + static HttpResponse response; + static HttpPost httppost; + static JSONObject responseContent; + public static Integer scalingFactorLogarithm = 0; + public static Long totalSupply = 1000000000000L; + public static String name = "jsonrpc-test"; + public static String jsonRpcAssetId; + public static Integer blockNum; + public static Integer blockNumForTrc20; + public static String blockNumHex; + public static String blockId; + public static String txid; + public static String trc20Txid; + + /** constructor. */ + @BeforeSuite(enabled = true, description = "Deploy json rpc test case resource") + public void deployJsonRpcUseResource() throws Exception { + Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET); + channelFull = ManagedChannelBuilder.forTarget(fullnode).usePlaintext(true).build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + Assert.assertTrue( + PublicMethed.sendcoin( + jsonRpcOwnerAddress, + 2048000000L, + foundationAccountAddress, + foundationAccountKey, + blockingStubFull)); + if (PublicMethed.queryAccount(jsonRpcOwnerAddress, blockingStubFull).getAssetV2Count() == 0L) { + Assert.assertTrue( + PublicMethed.sendcoin( + jsonRpcOwnerAddress, + 2048000000L, + foundationAccountAddress, + foundationAccountKey, + blockingStubFull)); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + // Create a new Asset Issue + Assert.assertTrue( + PublicMethed.createAssetIssue( + jsonRpcOwnerAddress, + name, + totalSupply, + 1, + 1, + System.currentTimeMillis() + 5000, + System.currentTimeMillis() + 1000000000, + 1, + "description", + "urlurlurl", + 2000L, + 2000L, + 1L, + 1L, + jsonRpcOwnerKey, + blockingStubFull)); + + PublicMethed.waitProduceNextBlock(blockingStubFull); + } + + response = HttpMethed.getAccount(httpFullNode, jsonRpcOwnerAddress); + responseContent = HttpMethed.parseResponseContent(response); + jsonRpcAssetId = responseContent.getString("asset_issued_ID"); + + deployContract(); + triggerContract(); + deployTrc20Contract(); + } + + /** constructor. */ + public void deployContract() throws Exception { + final Long beforeTokenBalance = + PublicMethed.getAssetBalanceByAssetId( + ByteString.copyFromUtf8(jsonRpcAssetId), jsonRpcOwnerKey, blockingStubFull); + + JsonObject param = new JsonObject(); + param.addProperty("from", ByteArray.toHexString(jsonRpcOwnerAddress)); + param.addProperty("name", "transferTokenContract"); + param.addProperty("gas", "0x245498"); + String filePath = "./src/test/resources/soliditycode/contractTrcToken001.sol"; + String contractName = "tokenTest"; + HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + String code = retMap.get("byteCode").toString(); + String abi = retMap.get("abI").toString(); + + param.addProperty("abi", abi); + param.addProperty("data", code); + param.addProperty("consumeUserResourcePercent", 100); + param.addProperty("originEnergyLimit", 11111111111111L); + param.addProperty("value", "0x1f4"); + param.addProperty("tokenId", Long.valueOf(jsonRpcAssetId)); + param.addProperty("tokenValue", 1); + JsonArray params = new JsonArray(); + params.add(param); + JsonObject requestBody = getJsonRpcBody("buildTransaction", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String transactionString = responseContent.getJSONObject("result").getString("transaction"); + String transactionSignString = + HttpMethed.gettransactionsign(httpFullNode, transactionString, jsonRpcOwnerKey); + + responseContent = HttpMethed.parseStringContent(transactionString); + final String txid = responseContent.getString("txID"); + + response = HttpMethed.broadcastTransaction(httpFullNode, transactionSignString); + org.junit.Assert.assertTrue(HttpMethed.verificationResult(response)); + + HttpMethed.waitToProduceOneBlock(httpFullNode); + Long afterTokenBalance = + PublicMethed.getAssetBalanceByAssetId( + ByteString.copyFromUtf8(jsonRpcAssetId), jsonRpcOwnerKey, blockingStubFull); + + org.junit.Assert.assertEquals(beforeTokenBalance - afterTokenBalance, 1L); + + logger.info(txid); + response = HttpMethed.getTransactionById(httpFullNode, txid); + responseContent = HttpMethed.parseResponseContent(response); + HttpMethed.printJsonContent(responseContent); + org.junit.Assert.assertTrue(!responseContent.getString("contract_address").isEmpty()); + contractAddressFrom58 = responseContent.getString("contract_address"); + } + + /** constructor. */ + public void triggerContract() throws Exception { + final Long beforeTokenBalance = + PublicMethed.getAssetBalanceByAssetId( + ByteString.copyFromUtf8(jsonRpcAssetId), foundationAccountKey, blockingStubFull); + final Long beforeBalance = HttpMethed.getBalance(httpFullNode, jsonRpcOwnerAddress); + JsonObject param = new JsonObject(); + param.addProperty("from", "0x" + ByteArray.toHexString(jsonRpcOwnerAddress).substring(2)); + param.addProperty("to", "0x" + contractAddressFrom58); + + String addressParam = + "000000000000000000000000" + + ByteArray.toHexString(foundationAccountAddress).substring(2); // [0,3) + + String tokenIdParam = + "00000000000000000000000000000000000000000000000000000000000" + + Integer.toHexString(Integer.valueOf(jsonRpcAssetId)); + + String tokenValueParam = "0000000000000000000000000000000000000000000000000000000000000001"; + String paramString = addressParam + tokenIdParam + tokenValueParam; + + String selector = "TransferTokenTo(address,trcToken,uint256)"; + param.addProperty("data", "0x" + Util.parseMethod(selector, paramString)); + param.addProperty("gas", "0x245498"); + param.addProperty("value", "0x1389"); + param.addProperty("tokenId", Long.valueOf(jsonRpcAssetId)); + param.addProperty("tokenValue", 1); + JsonArray params = new JsonArray(); + params.add(param); + JsonObject requestBody = getJsonRpcBody("buildTransaction", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String transactionString = responseContent.getJSONObject("result").getString("transaction"); + logger.info("transactionString : " + transactionString); + String transactionSignString = + HttpMethed.gettransactionsign(httpFullNode, transactionString, jsonRpcOwnerKey); + + responseContent = HttpMethed.parseStringContent(transactionString); + txid = responseContent.getString("txID"); + + response = HttpMethed.broadcastTransaction(httpFullNode, transactionSignString); + logger.info("response:" + response); + HttpMethed.verificationResult(response); + org.junit.Assert.assertTrue(HttpMethed.verificationResult(response)); + + HttpMethed.waitToProduceOneBlock(httpFullNode); + Long afterTokenBalance = + PublicMethed.getAssetBalanceByAssetId( + ByteString.copyFromUtf8(jsonRpcAssetId), foundationAccountKey, blockingStubFull); + Long afterBalance = HttpMethed.getBalance(httpFullNode, jsonRpcOwnerAddress); + + org.junit.Assert.assertEquals(beforeTokenBalance - afterTokenBalance, -1L); + org.junit.Assert.assertTrue(beforeBalance - afterBalance >= 5000); + + blockNum = + (int) (PublicMethed.getTransactionInfoById(txid, blockingStubFull).get().getBlockNumber()); + PublicMethed.waitProduceNextBlock(blockingStubFull); + response = HttpMethed.getBlockByNum(httpFullNode, blockNum); + org.junit.Assert.assertEquals(response.getStatusLine().getStatusCode(), 200); + responseContent = HttpMethed.parseResponseContent(response); + HttpMethed.printJsonContent(responseContent); + blockId = responseContent.get("blockID").toString(); + } + + /** constructor. */ + public void deployTrc20Contract() throws InterruptedException { + String contractName = "shieldTrc20Token"; + + String abi = Configuration.getByPath("testng.conf").getString("abi.abi_shieldTrc20Token"); + String code = Configuration.getByPath("testng.conf").getString("code.code_shieldTrc20Token"); + String constructorStr = "constructor(uint256,string,string)"; + String data = totalSupply.toString() + "," + "\"TokenTRC20\"" + "," + "\"zen20\""; + logger.info("data:" + data); + deployTrc20Txid = + PublicMethed.deployContractWithConstantParame( + contractName, + abi, + code, + constructorStr, + data, + "", + maxFeeLimit, + 0L, + 100, + null, + jsonRpcOwnerKey, + jsonRpcOwnerAddress, + blockingStubFull); + + PublicMethed.waitProduceNextBlock(blockingStubFull); + logger.info(deployTrc20Txid); + Optional infoById = + PublicMethed.getTransactionInfoById(deployTrc20Txid, blockingStubFull); + + trc20AddressHex = ByteArray.toHexString(infoById.get().getContractAddress().toByteArray()); + byte[] trc20Address = infoById.get().getContractAddress().toByteArray(); + + String selector = "transfer(address,uint256)"; + String addressParam = + "000000000000000000000000" + + ByteArray.toHexString(foundationAccountAddress).substring(2); // [0,3) + String transferValueParam = "0000000000000000000000000000000000000000000000000000000000000001"; + String paramString = addressParam + transferValueParam; + trc20Txid = + PublicMethed.triggerContract( + trc20Address, + selector, + paramString, + true, + 0, + maxFeeLimit, + "0", + 0, + jsonRpcOwnerAddress, + jsonRpcOwnerKey, + blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + blockNumForTrc20 = + (int) + (PublicMethed.getTransactionInfoById(trc20Txid, blockingStubFull) + .get() + .getBlockNumber()); + } + + /** constructor. */ + public static HttpResponse getEthHttps(String ethHttpsNode, JsonObject jsonRpcObject) { + try { + String requestUrl = "https://" + ethHttpsNode + "/v3/dfb752dd45204b8daae74249f4653584"; + response = HttpMethed.createConnect(requestUrl, jsonRpcObject); + } catch (Exception e) { + e.printStackTrace(); + httppost.releaseConnection(); + return null; + } + return response; + } + + /** constructor. */ + public static HttpResponse getJsonRpc(String jsonRpcNode, JsonObject jsonRpcObject) { + try { + String requestUrl = "http://" + jsonRpcNode + "/jsonrpc"; + response = HttpMethed.createConnect(requestUrl, jsonRpcObject); + } catch (Exception e) { + e.printStackTrace(); + httppost.releaseConnection(); + return null; + } + return response; + } + + /** constructor. */ + public static JsonObject getJsonRpcBody(String method) { + return getJsonRpcBody(method, new JsonArray(), 1); + } + + /** constructor. */ + public static JsonObject getJsonRpcBody(String method, JsonArray params) { + return getJsonRpcBody(method, params, 1); + } + + /** constructor. */ + public static JsonObject getJsonRpcBody(String method, JsonArray params, Integer id) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("jsonrpc", "2.0"); + jsonObject.addProperty("method", method); + jsonObject.add("params", params); + jsonObject.addProperty("id", id); + + return jsonObject; + } +} diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset001.java index 55c11bb04c3..16eb4ae33e4 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset001.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset001.java @@ -148,14 +148,14 @@ void marketSellAssetTest002() { .marketSellAssetGetResposne(testAddress, testKey, assetAccountId001, sellTokenQuantity, assetAccountId002, buyTokenQuantity, blockingStubFull); Assert.assertEquals(ByteArray.toStr(resposne.getMessage().toByteArray()), - "contract validate error : SellToken balance is not enough !"); + "Contract validate error : SellToken balance is not enough !"); Assert.assertEquals(resposne.getCode(), response_code.CONTRACT_VALIDATE_ERROR); resposne = PublicMethed .marketSellAssetGetResposne(testAddress, testKey, assetAccountId001, 0, assetAccountId002, buyTokenQuantity, blockingStubFull); Assert.assertEquals(ByteArray.toStr(resposne.getMessage().toByteArray()), - "contract validate error : token quantity must greater than zero"); + "Contract validate error : token quantity must greater than zero"); Assert.assertEquals(resposne.getCode(), response_code.CONTRACT_VALIDATE_ERROR); Account account = PublicMethed @@ -174,35 +174,35 @@ void marketSellAssetTest003() { .marketSellAssetGetResposne(testAddress001, testKey001, "xxxx".getBytes(), sellTokenQuantity, assetAccountId002, buyTokenQuantity, blockingStubFull); Assert.assertEquals(ByteArray.toStr(resposne.getMessage().toByteArray()), - "contract validate error : sellTokenId is not a valid number"); + "Contract validate error : sellTokenId is not a valid number"); Assert.assertEquals(resposne.getCode(), response_code.CONTRACT_VALIDATE_ERROR); resposne = PublicMethed .marketSellAssetGetResposne(testAddress001, testKey001, assetAccountId001, sellTokenQuantity, "xxx".getBytes(), buyTokenQuantity, blockingStubFull); Assert.assertEquals(ByteArray.toStr(resposne.getMessage().toByteArray()), - "contract validate error : buyTokenId is not a valid number"); + "Contract validate error : buyTokenId is not a valid number"); Assert.assertEquals(resposne.getCode(), response_code.CONTRACT_VALIDATE_ERROR); resposne = PublicMethed .marketSellAssetGetResposne(testAddress001, testKey001, "10001039999".getBytes(), sellTokenQuantity, assetAccountId002, buyTokenQuantity, blockingStubFull); Assert.assertEquals(ByteArray.toStr(resposne.getMessage().toByteArray()), - "contract validate error : No sellTokenId !"); + "Contract validate error : No sellTokenId !"); Assert.assertEquals(resposne.getCode(), response_code.CONTRACT_VALIDATE_ERROR); resposne = PublicMethed .marketSellAssetGetResposne(testAddress001, testKey001, assetAccountId001, sellTokenQuantity, "10001039999".getBytes(), buyTokenQuantity, blockingStubFull); Assert.assertEquals(ByteArray.toStr(resposne.getMessage().toByteArray()), - "contract validate error : No buyTokenId !"); + "Contract validate error : No buyTokenId !"); Assert.assertEquals(resposne.getCode(), response_code.CONTRACT_VALIDATE_ERROR); resposne = PublicMethed .marketSellAssetGetResposne(testAddress001, testKey001, assetAccountId001, sellTokenQuantity, assetAccountId001, buyTokenQuantity, blockingStubFull); Assert.assertEquals(ByteArray.toStr(resposne.getMessage().toByteArray()), - "contract validate error : cannot exchange same tokens"); + "Contract validate error : cannot exchange same tokens"); Assert.assertEquals(resposne.getCode(), response_code.CONTRACT_VALIDATE_ERROR); long afterBalance = PublicMethed.queryAccount(testAddress002, blockingStubFull).getBalance(); diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset002.java b/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset002.java index 95082986179..d145a540f20 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset002.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset002.java @@ -203,7 +203,7 @@ void marketSellAssetTest002() { // get order Message and RemainSellTokenQuantity MarketOrder order001 = PublicMethed .getMarketOrderById(orderId, blockingStubFull).get(); - Assert.assertEquals(order001.getSellTokenQuantityRemain(),sellTokenQuantity); + Assert.assertEquals(order001.getSellTokenQuantityRemain(), sellTokenQuantity); Map afterAsset001 = PublicMethed.queryAccount(testAddress001, blockingStubFull) .getAssetV2Map(); @@ -238,7 +238,7 @@ void marketSellAssetTest002() { // get order Message and RemainSellTokenQuantity order001 = PublicMethed .getMarketOrderById(orderId, blockingStubFull).get(); - Assert.assertEquals(order001.getSellTokenQuantityRemain(),0); + Assert.assertEquals(order001.getSellTokenQuantityRemain(), 0); afterAsset001 = PublicMethed.queryAccount(testAddress001, blockingStubFull) .getAssetV2Map(); @@ -340,7 +340,7 @@ void marketSellAssetTest004() { tokenId = orderList.get().getOrders(0).getSellTokenId().toByteArray(); sellTokenQuantity001 = orderList.get().getOrders(0).getSellTokenQuantityRemain(); - String txid = PublicMethed.marketCancelOrder(testAddress001,testKey001,orderId001, + String txid = PublicMethed.marketCancelOrder(testAddress001, testKey001, orderId001, blockingStubFull); PublicMethed.waitProduceNextBlock(blockingStubFull); Assert.assertNotNull(txid); @@ -365,8 +365,8 @@ void marketSellAssetTest004() { PublicMethed.waitProduceNextBlock(blockingStubFull); Assert.assertNotNull(response); Assert.assertEquals(response.getCode(), response_code.CONTRACT_VALIDATE_ERROR); - Assert.assertEquals(ByteArray.toStr(response.getMessage().toByteArray()), - "contract validate error : Order is not active!"); + Assert.assertEquals(ByteArray.toStr(response.getMessage().toByteArray()).toLowerCase(), + "contract validate error : Order is not active!".toLowerCase()); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset003.java b/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset003.java index 51cdc78d824..fb7e2898dd2 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset003.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/assetmarket/MarketSellAsset003.java @@ -63,21 +63,23 @@ public void beforeClass() { PublicMethed.printAddress(testKey001); PublicMethed.printAddress(testKey002); - Assert.assertTrue(PublicMethed.sendcoin(testAddress001,20000_000000L,foundationAddress001, - foundationKey001,blockingStubFull)); - Assert.assertTrue(PublicMethed.sendcoin(testAddress002,20000_000000L,foundationAddress001, - foundationKey001,blockingStubFull)); + Assert.assertTrue(PublicMethed.sendcoin(testAddress001, 20000_000000L, foundationAddress001, + foundationKey001, blockingStubFull)); + Assert.assertTrue(PublicMethed.sendcoin(testAddress002, 20000_000000L, foundationAddress001, + foundationKey001, blockingStubFull)); PublicMethed.waitProduceNextBlock(blockingStubFull); Long start = System.currentTimeMillis() + 5000; Long end = System.currentTimeMillis() + 1000000000; - Assert.assertTrue(PublicMethed.createAssetIssue(testAddress001,name,10000_000000L,1,1,start, - end,1,description,url,10000L,10000L,1L, 1L,testKey001,blockingStubFull)); + Assert.assertTrue(PublicMethed.createAssetIssue(testAddress001, name, 10000_000000L, + 1, 1, start, end, 1, description, url, 10000L, + 10000L, 1L, 1L, testKey001, blockingStubFull)); start = System.currentTimeMillis() + 5000; end = System.currentTimeMillis() + 1000000000; - Assert.assertTrue(PublicMethed.createAssetIssue(testAddress002,name,10000_000000L,1,1,start, - end,1,description,url,10000L,10000L,1L, 1L,testKey002,blockingStubFull)); + Assert.assertTrue(PublicMethed.createAssetIssue(testAddress002, name, 10000_000000L, + 1, 1, start, end, 1, description, url, 10000L, + 10000L, 1L, 1L, testKey002, blockingStubFull)); PublicMethed.waitProduceNextBlock(blockingStubFull); assetAccountId001 = PublicMethed.queryAccount(testAddress001, blockingStubFull) @@ -88,11 +90,11 @@ public void beforeClass() { } - @Test(enabled = true,description = "CancelOrder") + @Test(enabled = true, description = "CancelOrder") void marketCancelAssetTest001() { - String txid = PublicMethed.marketSellAsset(testAddress001,testKey001,assetAccountId001,100, - trx,50,blockingStubFull); + String txid = PublicMethed.marketSellAsset(testAddress001, testKey001, assetAccountId001, 100, + trx, 50, blockingStubFull); PublicMethed.waitProduceNextBlock(blockingStubFull); Optional transaction = PublicMethed .getTransactionById(txid, blockingStubFull); @@ -104,7 +106,7 @@ void marketCancelAssetTest001() { PublicMethed.waitProduceNextBlock(blockingStubFull); Assert.assertTrue(orderList.get().getOrdersCount() > 0); byte[] orderId = orderList.get().getOrders(0).getOrderId().toByteArray(); - txid = PublicMethed.marketCancelOrder(testAddress001,testKey001,orderId,blockingStubFull); + txid = PublicMethed.marketCancelOrder(testAddress001, testKey001, orderId, blockingStubFull); PublicMethed.waitProduceNextBlock(blockingStubFull); transaction = PublicMethed @@ -117,11 +119,11 @@ void marketCancelAssetTest001() { } - @Test(enabled = true,description = "Cancel a cancelled order ") + @Test(enabled = true, description = "Cancel a cancelled order ") void marketCancelAssetTest002() { - String txid = PublicMethed.marketSellAsset(testAddress001,testKey001,assetAccountId001,100, - trx,50,blockingStubFull); + String txid = PublicMethed.marketSellAsset(testAddress001, testKey001, assetAccountId001, 100, + trx, 50, blockingStubFull); PublicMethed.waitProduceNextBlock(blockingStubFull); Optional transaction = PublicMethed .getTransactionById(txid, blockingStubFull); @@ -133,7 +135,7 @@ void marketCancelAssetTest002() { PublicMethed.waitProduceNextBlock(blockingStubFull); Assert.assertTrue(orderList.get().getOrdersCount() > 0); byte[] orderId = orderList.get().getOrders(0).getOrderId().toByteArray(); - txid = PublicMethed.marketCancelOrder(testAddress001,testKey001,orderId,blockingStubFull); + txid = PublicMethed.marketCancelOrder(testAddress001, testKey001, orderId, blockingStubFull); PublicMethed.waitProduceNextBlock(blockingStubFull); transaction = PublicMethed @@ -143,8 +145,9 @@ void marketCancelAssetTest002() { .getMarketOrderByAccount(testAddress001, blockingStubFull); Assert.assertTrue(orderList.get().getOrdersCount() == 0); - Assert.assertEquals(PublicMethed.marketCancelOrder(testAddress001,testKey001,orderId, - blockingStubFull),"contract validate error : Order is not active!"); + Assert.assertEquals(PublicMethed.marketCancelOrder(testAddress001, testKey001, orderId, + blockingStubFull).toLowerCase(), + "contract validate error : Order is not active!".toLowerCase()); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpRateLimite001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpRateLimite001.java index de48777db11..90c46bb4ab6 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpRateLimite001.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpRateLimite001.java @@ -17,19 +17,19 @@ @Slf4j public class HttpRateLimite001 { - private final String testKey002 = Configuration.getByPath("testng.conf") - .getString("foundationAccount.key1"); + private final String testKey002 = + Configuration.getByPath("testng.conf").getString("foundationAccount.key1"); private final byte[] fromAddress = PublicMethed.getFinalAddress(testKey002); private JSONObject responseContent; private HttpResponse response; - private String httpnode = Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list") - .get(0); - private String httpSoliditynode = Configuration.getByPath("testng.conf") - .getStringList("httpnode.ip.list").get(3); - private String realHttpSoliditynode = Configuration.getByPath("testng.conf") - .getStringList("httpnode.ip.list").get(2); - private String httpPbftNode = Configuration.getByPath("testng.conf") - .getStringList("httpnode.ip.list").get(4); + private String httpnode = + Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list").get(0); + private String httpSoliditynode = + Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list").get(3); + private String realHttpSoliditynode = + Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list").get(2); + private String httpPbftNode = + Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list").get(4); @BeforeSuite public void beforeSuite() { @@ -37,17 +37,11 @@ public void beforeSuite() { Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET); } - /** - * constructor. - */ - + /** constructor. */ @BeforeClass - public void beforeClass() { - } + public void beforeClass() {} - /** - * constructor. - */ + /** constructor. */ @Test(enabled = true, description = "Rate limit QpsStrategy for ListWitness interface") public void test1QpsStrategyForListWitnessInterface() { Long startTimeStamp = System.currentTimeMillis(); @@ -60,9 +54,7 @@ public void test1QpsStrategyForListWitnessInterface() { Assert.assertTrue(endTimesStap - startTimeStamp > 4000); } - /** - * constructor. - */ + /** constructor. */ @Test(enabled = true, description = "Rate limit IpQpsStrategy for ListNodes interface") public void test2IpQpsStrategyForListNodesInterface() { Long startTimeStamp = System.currentTimeMillis(); @@ -75,11 +67,12 @@ public void test2IpQpsStrategyForListNodesInterface() { Assert.assertTrue(endTimesStap - startTimeStamp > 4000); } - /** - * constructor. - */ - @Test(enabled = true, description = "Rate limit IpQpsStrategy for GetBlockByLatestNumOnSolidity " - + "interface on fullnode's solidity service") + /** constructor. */ + @Test( + enabled = true, + description = + "Rate limit IpQpsStrategy for GetBlockByLatestNumOnSolidity " + + "interface on fullnode's solidity service") public void test3IpQpsStrategyForGetBlockByLatestNumOnSolidityInterface() { Long startTimeStamp = System.currentTimeMillis(); Integer repeatTimes = 0; @@ -92,11 +85,11 @@ public void test3IpQpsStrategyForGetBlockByLatestNumOnSolidityInterface() { Assert.assertTrue(endTimesStap - startTimeStamp > 4000); } - /** - * constructor. - */ - @Test(enabled = true, description = "Rate limit QpsStrategy for getBlockByNum " - + "interface on fullnode's solidity service") + /** constructor. */ + @Test( + enabled = true, + description = + "Rate limit QpsStrategy for getBlockByNum " + "interface on fullnode's solidity service") public void test4QpsStrategyForgetBlockByNumResourceInterfaceOnFullnodeSolidityService() { Long startTimeStamp = System.currentTimeMillis(); Integer repeatTimes = 0; @@ -109,8 +102,12 @@ public void test4QpsStrategyForgetBlockByNumResourceInterfaceOnFullnodeSolidityS Assert.assertTrue(endTimesStap - startTimeStamp > 4000); } - @Test(enabled = false, description = "Rate limit QpsStrategy for " - + "getTransactionsFromThisFromSolidity " + "interface on real solidity") + @Test( + enabled = false, + description = + "Rate limit QpsStrategy for " + + "getTransactionsFromThisFromSolidity " + + "interface on real solidity") public void test6QpsStrategyForgetTransactionsToThisFromSolidity() { Long startTimeStamp = System.currentTimeMillis(); Integer repeatTimes = 0; @@ -123,12 +120,17 @@ public void test6QpsStrategyForgetTransactionsToThisFromSolidity() { Assert.assertTrue(endTimesStap - startTimeStamp > 4000); } + @Test(enabled = true, description = "Verify getstatsinfo Interface has been disabled") + public void test7GetStatsInfo() { + response = HttpMethed.getStatsInfo(httpnode); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("responseContent:" + responseContent); + String resultForGetstatsinfo = responseContent.getString("Error"); + logger.info("resultForGetstatsinfo:" + resultForGetstatsinfo); + Assert.assertEquals(resultForGetstatsinfo, "this API is unavailable due to config"); + } - /** - * constructor. - */ - + /** constructor. */ @AfterClass - public void shutdown() throws InterruptedException { - } -} \ No newline at end of file + public void shutdown() throws InterruptedException {} +} diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpTestProposal001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpTestProposal001.java index e9d30c5079e..8fdaa8ddaa3 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpTestProposal001.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/http/HttpTestProposal001.java @@ -16,23 +16,21 @@ public class HttpTestProposal001 { private static Integer proposalId; - private final String testKey002 = Configuration.getByPath("testng.conf") - .getString("foundationAccount.key1"); + private final String testKey002 = + Configuration.getByPath("testng.conf").getString("foundationAccount.key1"); private final byte[] fromAddress = PublicMethed.getFinalAddress(testKey002); - private final String witnessKey001 = Configuration.getByPath("testng.conf") - .getString("witness.key1"); + private final String witnessKey001 = + Configuration.getByPath("testng.conf").getString("witness.key1"); private final byte[] witness1Address = PublicMethed.getFinalAddress(witnessKey001); - private final String witnessKey002 = Configuration.getByPath("testng.conf") - .getString("witness.key2"); + private final String witnessKey002 = + Configuration.getByPath("testng.conf").getString("witness.key2"); private final byte[] witness2Address = PublicMethed.getFinalAddress(witnessKey002); - private String httpnode = Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list") - .get(0); + private String httpnode = + Configuration.getByPath("testng.conf").getStringList("httpnode.ip.list").get(0); private JSONObject responseContent; private HttpResponse response; - /** - * constructor. - */ + /** constructor. */ @Test(enabled = true, description = "Create proposal by http") public void test1CreateProposal() { HttpMethed.waitToProduceOneBlock(httpnode); @@ -41,9 +39,7 @@ public void test1CreateProposal() { HttpMethed.waitToProduceOneBlock(httpnode); } - /** - * * constructor. * - */ + /** * constructor. * */ @Test(enabled = true, description = "List proposals by http") public void test2ListProposals() { response = HttpMethed.listProposals(httpnode); @@ -54,30 +50,26 @@ public void test2ListProposals() { proposalId = jsonArray.size(); } - /** - * constructor. - */ + /** constructor. */ @Test(enabled = true, description = "GetProposalById by http") public void test3GetExchangeById() { response = HttpMethed.getProposalById(httpnode, proposalId); responseContent = HttpMethed.parseResponseContent(response); HttpMethed.printJsonContent(responseContent); Assert.assertTrue(responseContent.getInteger("proposal_id") == proposalId); - Assert.assertEquals(responseContent.getString("proposer_address"), - ByteArray.toHexString(witness1Address)); + Assert.assertEquals( + responseContent.getString("proposer_address"), ByteArray.toHexString(witness1Address)); } - /** - * constructor. - */ + /** constructor. */ @Test(enabled = true, description = "Approval proposal by http") public void test4ApprovalProposal() { - response = HttpMethed - .approvalProposal(httpnode, witness1Address, proposalId, true, witnessKey001); + response = + HttpMethed.approvalProposal(httpnode, witness1Address, proposalId, true, witnessKey001); Assert.assertTrue(HttpMethed.verificationResult(response)); HttpMethed.waitToProduceOneBlock(httpnode); - response = HttpMethed - .approvalProposal(httpnode, witness2Address, proposalId, true, witnessKey002); + response = + HttpMethed.approvalProposal(httpnode, witness2Address, proposalId, true, witnessKey002); Assert.assertTrue(HttpMethed.verificationResult(response)); HttpMethed.waitToProduceOneBlock(httpnode); response = HttpMethed.getProposalById(httpnode, proposalId); @@ -87,10 +79,7 @@ public void test4ApprovalProposal() { Assert.assertTrue(jsonArray.size() == 2); } - - /** - * * constructor. * - */ + /** * constructor. * */ @Test(enabled = true, description = "Get paginated proposal list by http") public void test5GetPaginatedProposalList() { @@ -103,9 +92,7 @@ public void test5GetPaginatedProposalList() { Assert.assertTrue(jsonArray.size() == 1); } - /** - * constructor. - */ + /** constructor. */ @Test(enabled = true, description = "Delete proposal by http") public void test6DeleteProposal() { response = HttpMethed.deleteProposal(httpnode, witness1Address, proposalId, witnessKey001); @@ -117,32 +104,41 @@ public void test6DeleteProposal() { Assert.assertEquals(responseContent.getString("state"), "CANCELED"); } - - /** - * constructor. - */ + /** constructor. */ @Test(enabled = true, description = "Get chain parameters by http") public void test7GetChainParameters() { response = HttpMethed.getChainParameters(httpnode); HttpMethed.waitToProduceOneBlock(httpnode); responseContent = HttpMethed.parseResponseContent(response); HttpMethed.printJsonContent(responseContent); - Assert.assertEquals("getMaintenanceTimeInterval", + Assert.assertEquals( + "getMaintenanceTimeInterval", responseContent.getJSONArray("chainParameter").getJSONObject(0).get("key")); - Assert.assertEquals(300000, - responseContent.getJSONArray("chainParameter").getJSONObject(0).get("value")); - Assert.assertEquals("getCreateAccountFee", + Assert.assertEquals( + 300000, responseContent.getJSONArray("chainParameter").getJSONObject(0).get("value")); + Assert.assertEquals( + "getCreateAccountFee", responseContent.getJSONArray("chainParameter").getJSONObject(2).get("key")); - Assert.assertEquals(100000, - responseContent.getJSONArray("chainParameter").getJSONObject(2).get("value")); + Assert.assertEquals( + 100000, responseContent.getJSONArray("chainParameter").getJSONObject(2).get("value")); + } + /** constructor. */ + + @Test(enabled = true, description = "Get energy price by http") + public void test8GetEnergyPrice() { + response = HttpMethed.getEnergyPric(httpnode); + HttpMethed.waitToProduceOneBlock(httpnode); + responseContent = HttpMethed.parseResponseContent(response); + HttpMethed.printJsonContent(responseContent); + String prices = responseContent.getString("prices"); + String expectPrices = "0:100"; + logger.info("prices:" + prices); + Assert.assertEquals(prices, expectPrices); } - /** - * constructor. - */ + /** constructor. */ @AfterClass public void shutdown() throws InterruptedException { HttpMethed.disConnect(); } } - diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/Accounts001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/Accounts001.java new file mode 100644 index 00000000000..5f1ddf3e4ae --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/Accounts001.java @@ -0,0 +1,1135 @@ +package stest.tron.wallet.dailybuild.jsonrpc; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.grpc.ManagedChannelBuilder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpResponse; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.tron.api.GrpcAPI; +import org.tron.api.WalletGrpc; +import org.tron.common.utils.ByteArray; +import org.tron.protos.Protocol.Block; +import stest.tron.wallet.common.client.utils.HttpMethed; +import stest.tron.wallet.common.client.utils.JsonRpcBase; +import stest.tron.wallet.common.client.utils.PublicMethed; + +@Slf4j +public class Accounts001 extends JsonRpcBase { + private JSONObject responseContent; + private HttpResponse response; + String realGasPrice; + String bid = null; + int indexNum = 0; + String indexHex = null; + JSONObject result = null; + String transacionHash = null; + String blockHash = null; + String blockNumHex = null; + String parentHash = null; + String txTrieRoot = null; + String witnessAddress = null; + String feeLimit = null; + String accountStateRoot = null; + + List transactionIdList = null; + long size = 0; + long gas = 0; + long blockTimeStamp = 0; + long gasPriceFromHttp = 0; + + /** constructor. */ + @BeforeClass(enabled = true) + public void beforeClass() { + channelFull = ManagedChannelBuilder.forTarget(fullnode).usePlaintext(true).build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + } + + @Test(enabled = true, description = "Json rpc api of eth_accounts") + public void test01JsonRpcApiTestForEthAccounts() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_accounts", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + List result = new ArrayList(); + logger.info(String.valueOf(result)); + Assert.assertEquals(responseContent.get("result"), result); + } + + @Test(enabled = true, description = "Json rpc api of eth_blockNumber") + public void test02JsonRpcApiTestForEthBlockNumber() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_blockNumber", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + responseContent.get("result"); + String blockNum = responseContent.getString("result").substring(2); + int blocknumFromJsonRpcNode = Integer.parseInt(blockNum, 16); + response = HttpMethed.getNowBlock(httpFullNode); + responseContent = HttpMethed.parseResponseContent(response); + int blocknumFromHttp = + responseContent + .getJSONObject("block_header") + .getJSONObject("raw_data") + .getInteger("number"); + logger.info("blocknumFromJsonRpcNode:" + blocknumFromJsonRpcNode); + logger.info("blocknumFromHttp:" + blocknumFromHttp); + Assert.assertTrue(Math.abs(blocknumFromJsonRpcNode - blocknumFromHttp) <= 3); + } + + @Test(enabled = true, description = "Json rpc api of eth_call") + public void test03JsonRpcApiTestForEthCall() throws Exception { + JsonObject param = new JsonObject(); + HttpMethed.waitToProduceOneBlock(httpFullNode); + param.addProperty("from", ByteArray.toHexString(jsonRpcOwnerAddress)); + param.addProperty("to", trc20AddressHex); + param.addProperty("gas", "0"); + param.addProperty("gasPrice", "0"); + param.addProperty("value", "0"); + param.addProperty("data", "0x06fdde03"); + JsonArray params = new JsonArray(); + params.add(param); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_call", params); + logger.info("params:" + params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String dataResult = responseContent.getString("result"); + Assert.assertEquals( + "0x000000000000000000000000000000000000000000000000000" + + "00000000000200000000000000000000000000000000000000000" + + "00000000000000000000000a546f6b656e5452433230000000000" + + "00000000000000000000000000000000000", + dataResult); + } + + @Test(enabled = true, description = "Json rpc api of eth_chainId") + public void test04JsonRpcApiTestForEthChainId() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_chainId", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + responseContent.get("result"); + String blockIdFromJsonRpcNode = responseContent.get("result").toString().substring(2); + response = HttpMethed.getBlockByNum(httpFullNode, 0); + responseContent = HttpMethed.parseResponseContent(response); + String blockIdFromHttp = responseContent.getString("blockID").substring(56); + logger.info("blockIdFromJsonRpcNode:" + blockIdFromJsonRpcNode); + logger.info("blockIdFromHttp:" + blockIdFromHttp); + Assert.assertEquals(blockIdFromJsonRpcNode, blockIdFromHttp); + } + + @Test(enabled = true, description = "Json rpc api of eth_coinbase") + public void test05JsonRpcApiTestForEthCoinbase() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_coinbase", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + + Assert.assertEquals( + "0x410be88a918d74d0dfd71dc84bd4abf036d0562991", responseContent.getString("result")); + } + + @Test(enabled = true, description = "Json rpc api of eth_estimateGas") + public void test06JsonRpcApiTestForEthEstimateGas() throws Exception { + JsonObject param = new JsonObject(); + param.addProperty("from", ByteArray.toHexString(jsonRpcOwnerAddress)); + param.addProperty("to", trc20AddressHex); + param.addProperty("gas", "0x0"); + param.addProperty("gasPrice", "0x0"); + param.addProperty("value", "0x0"); + param.addProperty("data", "0x1249c58b"); + JsonArray params = new JsonArray(); + params.add(param); + JsonObject requestBody = getJsonRpcBody("eth_estimateGas", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String dataResult = responseContent.getString("result"); + Assert.assertEquals("0x147", dataResult); + } + + @Test(enabled = true, description = "Json rpc api of eth_gasPrice") + public void test07JsonRpcApiTestForEthGasPrice() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_gasPrice", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + responseContent.get("result"); + String gasPrice = responseContent.get("result").toString().substring(2); + long gasPriceFromJsonrpc = Long.parseLong(gasPrice, 16); + logger.info(String.valueOf(gasPriceFromJsonrpc)); + response = HttpMethed.getChainParameter(httpFullNode); + responseContent = HttpMethed.parseResponseContent(response); + JSONArray temp; + temp = responseContent.getJSONArray("chainParameter"); + for (int i = 0; i < temp.size(); i++) { + if (temp.getJSONObject(i).get("key").equals("getEnergyFee")) { + gasPriceFromHttp = temp.getJSONObject(i).getLong("value"); + } + } + logger.info("gasPriceFromHttp:" + gasPriceFromHttp); + Assert.assertEquals(gasPriceFromJsonrpc, gasPriceFromHttp); + } + + @Test(enabled = true, description = "Json rpc api of eth_getBalance") + public void test08JsonRpcApiTestForEthGetBalance() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x415624C12E308B03A1A6B21D9B86E3942FAC1AB92B"); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_getBalance", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String balance = responseContent.getString("result").substring(2); + Long balance1 = Long.parseLong(balance, 16); + Long balance2 = HttpMethed.getBalance(httpFullNode, foundationAccountAddress); + logger.info(balance1.toString()); + logger.info(balance2.toString()); + Assert.assertEquals(balance1, balance2); + } + + @Test(enabled = true, description = "Json rpc api of eth_getBlockTransactionCountByNumber") + public void test09JsonRpcApiTestForEthGetBlockTransactionCountByNum() throws Exception { + response = HttpMethed.getNowBlock(httpFullNode); + responseContent = HttpMethed.parseResponseContent(response); + JsonArray params = new JsonArray(); + params.add("earliest"); + JsonObject requestBody = getJsonRpcBody("eth_getBlockTransactionCountByNumber", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String transactionNum = responseContent.getString("result").substring(2); + int transactionNum1 = Integer.parseInt(transactionNum, 16); + logger.info(String.valueOf(transactionNum1)); + response = HttpMethed.getTransactionCountByBlocknum(httpFullNode, 0); + responseContent = HttpMethed.parseResponseContent(response); + int transactionNum2 = responseContent.getInteger("count"); + logger.info(String.valueOf(transactionNum2)); + Assert.assertEquals(transactionNum1, transactionNum2); + } + + @Test(enabled = true, description = "Json rpc api of eth_getCode") + public void test10JsonRpcApiTestForEthGetCode() throws Exception { + + JsonArray params = new JsonArray(); + params.add(contractAddressFrom58); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_getCode", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String codeFromJsonRpc = responseContent.getString("result").substring(2); + logger.info(codeFromJsonRpc); + response = HttpMethed.getContractInfo(httpFullNode, contractAddressFrom58); + logger.info("13contractAddressFrom58:" + contractAddressFrom58); + responseContent = HttpMethed.parseResponseContent(response); + String codeFromHttp = responseContent.getString("runtimecode"); + logger.info(codeFromHttp); + Assert.assertEquals(codeFromJsonRpc, codeFromHttp); + } + + @Test(enabled = true, description = "Json rpc api of eth_getStorageAt") + public void test11JsonRpcApiTestForEthGetStorageAt01() throws Exception { + + JsonArray params = new JsonArray(); + params.add(contractAddressFrom58); + params.add("0x0"); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_getStorageAt", params); + logger.info("requestBody:" + requestBody); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("11responseContent:" + responseContent); + String result = responseContent.getString("result").substring(2); + long resultExpect = Long.parseLong(result, 16); + logger.info("result:" + resultExpect); + Assert.assertEquals("1234", String.valueOf(resultExpect)); + } + + @Test(enabled = true, description = "Json rpc api of eth_getStorageAt") + public void test12JsonRpcApiTestForEthGetStorageAt02() throws Exception { + + String address = + "000000000000000000000000" + ByteArray.toHexString(jsonRpcOwnerAddress).substring(2); + String str = address + "0000000000000000000000000000000000000000000000000000000000000001"; + logger.info("str:" + str); + JsonArray paramsForSha3 = new JsonArray(); + paramsForSha3.add(str); + JsonObject requestBodyForSha3 = getJsonRpcBody("web3_sha3", paramsForSha3); + logger.info("requestBodyForSha3:" + requestBodyForSha3); + response = getJsonRpc(jsonRpcNode, requestBodyForSha3); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("responseContent:" + responseContent); + String resultForSha3 = responseContent.getString("result"); + logger.info("resultForSha3:" + resultForSha3); + JsonArray params = new JsonArray(); + params.add(contractAddressFrom58); + params.add(resultForSha3); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_getStorageAt", params); + logger.info("requestBody:" + requestBody); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("12responseContent:" + responseContent); + String result = responseContent.getString("result").substring(2); + logger.info("12result:" + result); + logger.info("mapResult:" + Integer.parseInt(result, 16)); + Assert.assertEquals("5678", String.valueOf(Integer.parseInt(result, 16))); + } + + @Test(enabled = true, description = "Json rpc api of eth_getTransactionByBlockNumberAndIndex") + public void test13JsonRpcApiTestForEthGetTransactionByBlockNumberAndIndex() throws Exception { + logger.info("15blockNum:" + blockNum); + blockNumHex = "0x" + Integer.toHexString(blockNum); + logger.info("blockNumHex:" + blockNumHex); + JsonArray params = new JsonArray(); + params.add(blockNumHex); + indexNum = 0; + response = HttpMethed.getBlockByNum(httpFullNode, blockNum); + responseContent = HttpMethed.parseResponseContent(response); + parentHash = + responseContent + .getJSONObject("block_header") + .getJSONObject("raw_data") + .getString("parentHash"); + txTrieRoot = + responseContent + .getJSONObject("block_header") + .getJSONObject("raw_data") + .getString("txTrieRoot"); + witnessAddress = + responseContent + .getJSONObject("block_header") + .getJSONObject("raw_data") + .getString("witness_address"); + feeLimit = + responseContent + .getJSONArray("transactions") + .getJSONObject(0) + .getJSONObject("raw_data") + .getString("fee_limit"); + logger.info(feeLimit); + + JSONObject getBlockByNumResult = null; + for (int i = 0; i < responseContent.getJSONArray("transactions").size(); i++) { + if (txid.equals( + responseContent.getJSONArray("transactions").getJSONObject(i).getString("txID"))) { + indexNum = i; + getBlockByNumResult = responseContent.getJSONArray("transactions").getJSONObject(i); + bid = responseContent.getString("blockID"); + break; + } + } + transactionIdList = new ArrayList<>(); + if (responseContent.getJSONArray("transactions").size() > 0) { + for (int i = 0; i < responseContent.getJSONArray("transactions").size(); i++) { + transactionIdList.add( + "0x" + responseContent.getJSONArray("transactions").getJSONObject(i).getString("txID")); + } + } + logger.info("15transactionIdList:" + transactionIdList); + logger.info(String.valueOf(indexNum)); + indexHex = "0x" + Integer.toHexString(indexNum); + logger.info("indexHex:" + indexHex); + params.add(indexHex); + JsonObject requestBody = getJsonRpcBody("eth_getTransactionByBlockNumberAndIndex", params); + logger.info("13requestBody:" + requestBody); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + result = responseContent.getJSONObject("result"); + logger.info("13 result" + result); + Map jsonrpcResult = new HashMap(); + for (Map.Entry entry : result.entrySet()) { + jsonrpcResult.put(entry.getKey(), entry.getValue()); + } + transacionHash = jsonrpcResult.get("hash").toString(); + logger.info("transactionHash:" + transacionHash); + blockHash = jsonrpcResult.get("blockHash").toString(); + logger.info("jsonrpcResult:" + jsonrpcResult); + response = HttpMethed.getTransactionInfoByBlocknum(httpFullNode, blockNum); + logger.info("response:" + response); + List responseContent1 = HttpMethed.parseResponseContentArray(response); + logger.info("responseContent1:" + responseContent1); + blockTimeStamp = responseContent1.get(0).getLong("blockTimeStamp"); + // long gas = 0; + for (int i = 0; i < responseContent1.size(); i++) { + if (responseContent1.get(i).getString("id").equals(transactionIdList.get(0).substring(2))) { + gas = responseContent1.get(i).getJSONObject("receipt").getLong("energy_usage_total"); + logger.info("gas:" + gas); + break; + } + } + + Assert.assertEquals(jsonrpcResult.get("gas").toString(), "0x" + Long.toHexString(gas)); + Assert.assertNull(jsonrpcResult.get("nonce")); + Assert.assertEquals( + jsonrpcResult.get("hash").toString(), "0x" + getBlockByNumResult.getString("txID")); + Assert.assertEquals(jsonrpcResult.get("blockHash").toString(), "0x" + bid); + Assert.assertEquals(jsonrpcResult.get("blockNumber").toString(), blockNumHex); + Assert.assertEquals(jsonrpcResult.get("transactionIndex").toString(), indexHex); + Assert.assertEquals( + jsonrpcResult.get("from").toString(), + "0x" + + getBlockByNumResult + .getJSONObject("raw_data") + .getJSONArray("contract") + .getJSONObject(0) + .getJSONObject("parameter") + .getJSONObject("value") + .getString("owner_address") + .substring(2)); + Assert.assertEquals( + jsonrpcResult.get("to").toString(), + "0x" + + getBlockByNumResult + .getJSONObject("raw_data") + .getJSONArray("contract") + .getJSONObject(0) + .getJSONObject("parameter") + .getJSONObject("value") + .getString("contract_address") + .substring(2)); + // Assert.assertEquals(jsonrpcResult.get("gasPrice").toString(),realGasPrice); + Assert.assertEquals(jsonrpcResult.get("value").toString(), "0x1389"); + String data; + if (getBlockByNumResult.getJSONObject("raw_data").getString("data") == null) { + data = "0x"; + } else { + data = getBlockByNumResult.getJSONObject("raw_data").getString("data").substring(2); + } + Assert.assertEquals(jsonrpcResult.get("input").toString(), data); + + long temp = Long.parseLong(getBlockByNumResult.getString("signature").substring(130, 131), 16); + long v = Long.parseLong(getBlockByNumResult.getString("signature").substring(130, 132), 16); + if (temp < 27) { + v += 27; + } + Assert.assertEquals(Long.parseLong(jsonrpcResult.get("v").toString().substring(2), 16), v); + Assert.assertEquals( + jsonrpcResult.get("r").toString().substring(2), + getBlockByNumResult.getString("signature").substring(2, 66)); + Assert.assertEquals( + jsonrpcResult.get("s").toString().substring(2), + getBlockByNumResult.getString("signature").substring(66, 130)); + } + + @Test(enabled = true, description = "Json rpc api of eth_getBlockTransactionCountByHash") + public void test14JsonRpcApiTestForEthGetBlockTransactionCountByHash() throws Exception { + logger.info("blockNum:" + blockNum); + JsonArray params = new JsonArray(); + params.add(blockHash); + logger.info("blockHash:" + blockHash); + JsonObject requestBody = getJsonRpcBody("eth_getBlockTransactionCountByHash", params); + logger.info("requestBody:" + requestBody); + HttpMethed.waitToProduceOneBlock(httpFullNode); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("responseContent:" + responseContent); + String transactionNum = responseContent.getString("result").substring(2); + int transactionNumFromJsonRpcNode = Integer.parseInt(transactionNum, 16); + logger.info("transactionNumFromJsonRpcNode:" + transactionNumFromJsonRpcNode); + response = HttpMethed.getTransactionCountByBlocknum(httpFullNode, blockNum); + responseContent = HttpMethed.parseResponseContent(response); + int transactionNumFromHttp = responseContent.getInteger("count"); + logger.info("transactionNumFromHttp:" + transactionNumFromHttp); + Assert.assertEquals(transactionNumFromHttp, transactionNumFromJsonRpcNode); + } + + @Test(enabled = true, description = "Json rpc api of eth_getBlockTransactionCountByNumber") + public void test15JsonRpcApiTestForEthGetBlockTransactionCountByNum() throws Exception { + JsonArray params = new JsonArray(); + params.add(blockNum); + logger.info(String.valueOf(blockNum)); + JsonObject requestBody = getJsonRpcBody("eth_getBlockTransactionCountByNumber", params); + logger.info("requestBody:" + requestBody); + response = getJsonRpc(jsonRpcNode, requestBody); + logger.info("response:" + response); + HttpMethed.waitToProduceOneBlock(httpFullNode); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("responseContent:" + responseContent); + String transactionNum = responseContent.getString("result").substring(2); + int transactionNum1 = Integer.parseInt(transactionNum, 16); + logger.info(String.valueOf(transactionNum1)); + response = HttpMethed.getTransactionCountByBlocknum(httpFullNode, blockNum); + responseContent = HttpMethed.parseResponseContent(response); + int transactionNum2 = responseContent.getInteger("count"); + logger.info(String.valueOf(transactionNum2)); + Assert.assertEquals(transactionNum1, transactionNum2); + } + + @Test(enabled = true, description = "Json rpc api of eth_getTransactionByBlockHashAndIndex") + public void test16JsonRpcApiTestForEthGetTransactionByBlockHashAndIndex() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x" + bid); + params.add(indexHex); + logger.info("indexHex:" + indexHex); + JsonObject requestBody = getJsonRpcBody("eth_getTransactionByBlockHashAndIndex", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + JSONObject resultForGetTransactionByBlockHashAndIndex = responseContent.getJSONObject("result"); + Assert.assertEquals(result, resultForGetTransactionByBlockHashAndIndex); + } + + @Test(enabled = true, description = "Json rpc api of eth_getTransactionByHash") + public void test17JsonRpcApiTestForEthGetTransactionByHash() throws Exception { + JsonArray params = new JsonArray(); + params.add(transacionHash); + JsonObject requestBody = getJsonRpcBody("eth_getTransactionByHash", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + JSONObject result1 = responseContent.getJSONObject("result"); + Assert.assertEquals(result, result1); + } + + @Test(enabled = true, description = "Json rpc api of eth_getTransactionReceipt") + public void test18JsonRpcApiTestForEthGetTransactionReceipt() throws Exception { + JsonArray params = new JsonArray(); + Thread.sleep(6000); + params.add(trc20Txid); + JsonObject requestBody = getJsonRpcBody("eth_getTransactionReceipt", params); + logger.info("requestBody:" + requestBody); + response = getJsonRpc(jsonRpcNode, requestBody); + logger.info("response:" + response); + responseContent = HttpMethed.parseResponseContent(response); + JSONObject resultFromTransactionReceipt = responseContent.getJSONObject("result"); + logger.info("resultFromTransactionReceipt:" + resultFromTransactionReceipt); + JSONArray logs = resultFromTransactionReceipt.getJSONArray("logs"); + logger.info("logs:" + logs); + logger.info("result:" + resultFromTransactionReceipt.toString()); + response = HttpMethed.getBlockByNum(httpFullNode, blockNumForTrc20); + responseContent = HttpMethed.parseResponseContent(response); + int index = 0; + for (int i = 0; i < responseContent.getJSONArray("transactions").size(); i++) { + if (trc20Txid.equals( + responseContent.getJSONArray("transactions").getJSONObject(i).getString("txID"))) { + index = i; + break; + } + } + + JsonArray paramsForTransactionByBlockNumberAndIndex = new JsonArray(); + paramsForTransactionByBlockNumberAndIndex.add("0x" + Integer.toHexString(blockNumForTrc20)); + paramsForTransactionByBlockNumberAndIndex.add("0x" + Integer.toHexString(index)); + JsonObject requestBody1 = + getJsonRpcBody( + "eth_getTransactionByBlockNumberAndIndex", paramsForTransactionByBlockNumberAndIndex); + response = getJsonRpc(jsonRpcNode, requestBody1); + logger.info("requestBody1:" + requestBody1); + responseContent = HttpMethed.parseResponseContent(response); + JSONObject resultFromTransactionByBlockNumberAndIndex = responseContent.getJSONObject("result"); + logger.info( + "resultFromTransactionByBlockNumberAndIndex:" + resultFromTransactionByBlockNumberAndIndex); + Assert.assertEquals( + resultFromTransactionReceipt.getString("blockHash"), + resultFromTransactionByBlockNumberAndIndex.getString("blockHash")); + Assert.assertEquals( + resultFromTransactionReceipt.getString("blockNumber"), + resultFromTransactionByBlockNumberAndIndex.getString("blockNumber")); + Assert.assertEquals( + resultFromTransactionReceipt.getString("transactionIndex"), + resultFromTransactionByBlockNumberAndIndex.getString("transactionIndex")); + Assert.assertEquals( + resultFromTransactionReceipt.getString("transactionHash"), "0x" + trc20Txid); + Assert.assertEquals( + resultFromTransactionReceipt.getString("from"), + resultFromTransactionByBlockNumberAndIndex.getString("from")); + Assert.assertEquals( + resultFromTransactionReceipt.getString("to"), + resultFromTransactionByBlockNumberAndIndex.getString("to")); + logger.info("effectiveGasPrice:" + resultFromTransactionReceipt.getString("effectiveGasPrice")); + logger.info("gasPriceFromHttp:" + Long.toHexString(gasPriceFromHttp)); + Assert.assertEquals( + resultFromTransactionReceipt.getString("effectiveGasPrice"), + "0x" + Long.toHexString(gasPriceFromHttp)); + /* Assert.assertEquals( + resultFromTransactionReceipt.getString("contractAddress").substring(2), + trc20AddressHex.substring(2));*/ + Assert.assertNull(resultFromTransactionReceipt.getString("contractAddress")); + Assert.assertEquals( + resultFromTransactionReceipt.getString("logsBloom"), + "0x000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000"); + Assert.assertEquals("0x1", resultFromTransactionReceipt.getString("status")); + Assert.assertEquals("0x0", resultFromTransactionReceipt.getString("type")); + logger.info("gas:" + resultFromTransactionByBlockNumberAndIndex.getString("gas")); + Assert.assertEquals( + resultFromTransactionReceipt.getString("gasUsed"), + resultFromTransactionByBlockNumberAndIndex.getString("gas")); + Assert.assertEquals( + resultFromTransactionReceipt.getString("cumulativeGasUsed"), + resultFromTransactionByBlockNumberAndIndex.getString("gas")); + Assert.assertEquals( + logs.getJSONObject(0).getString("logIndex"), "0x" + Integer.toHexString(index)); + Assert.assertEquals(logs.getJSONObject(0).getString("removed"), "false"); + Assert.assertEquals( + logs.getJSONObject(0).getString("blockHash"), + resultFromTransactionReceipt.getString("blockHash")); + Assert.assertEquals( + logs.getJSONObject(0).getString("blockNumber"), + resultFromTransactionReceipt.getString("blockNumber")); + Assert.assertEquals( + logs.getJSONObject(0).getString("transactionIndex"), + resultFromTransactionReceipt.getString("transactionIndex")); + Assert.assertEquals( + logs.getJSONObject(0).getString("transactionHash"), + resultFromTransactionReceipt.getString("transactionHash")); + Assert.assertEquals( + logs.getJSONObject(0).getString("address"), resultFromTransactionReceipt.getString("to")); + response = HttpMethed.getTransactionInfoByBlocknum(httpFullNode, blockNumForTrc20); + List responseContent1 = HttpMethed.parseResponseContentArray(response); + logger.info("responseContent1:" + responseContent1); + + response = HttpMethed.getBlockByNum(httpFullNode, blockNumForTrc20); + responseContent = HttpMethed.parseResponseContent(response); + Assert.assertEquals( + logs.getJSONObject(0).getString("data").substring(2), + responseContent1.get(index).getJSONArray("log").getJSONObject(0).getString("data")); + + Assert.assertEquals( + logs.getJSONObject(0).getString("topics").replace("0x", ""), + responseContent1.get(index).getJSONArray("log").getJSONObject(0).getString("topics")); + } + + @Test(enabled = true, description = "Json rpc api of eth_getUncleByBlockHashAndIndex") + public void test19JsonRpcApiTestForEthGetUncleByBlockHashAndIndex() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x0000000000f9cc56243898cbe88685678855e07f51c5af91322c225ce3693868"); + params.add("0x"); + JsonObject requestBody = getJsonRpcBody("eth_getUncleByBlockHashAndIndex", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + logger.info(result); + Assert.assertNull(result); + } + + @Test(enabled = true, description = "Json rpc api of eth_getUncleByBlockNumberAndIndex") + public void test20JsonRpcApiTestForEthGetUncleByBlockNumberAndIndex() throws Exception { + JsonArray params = new JsonArray(); + params.add("0xeb82f0"); + params.add("0x"); + JsonObject requestBody = getJsonRpcBody("eth_getUncleByBlockNumberAndIndex", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + logger.info(result); + Assert.assertNull(result); + } + + @Test(enabled = true, description = "Json rpc api of eth_getUncleCountByBlockHash") + public void test21JsonRpcApiTestForEthGetUncleCountByBlockHash() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x0000000000f9cc56243898cbe88685678855e07f51c5af91322c225ce3693868"); + JsonObject requestBody = getJsonRpcBody("eth_getUncleCountByBlockHash", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + logger.info(result); + Assert.assertEquals(result, "0x0"); + } + + @Test(enabled = true, description = "Json rpc api of eth_getUncleCountByBlockNumber") + public void test22JsonRpcApiTestForEthGetUncleCountByBlockNumber() throws Exception { + JsonArray params = new JsonArray(); + params.add("eth_getUncleCountByBlockNumber"); + JsonObject requestBody = getJsonRpcBody("eth_getUncleCountByBlockNumber", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + logger.info(result); + Assert.assertEquals(result, "0x0"); + } + + @Test(enabled = true, description = "Json rpc api of eth_getWork") + public void test23JsonRpcApiTestForEthGetWork() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_getWork", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + int resultLen = result.length(); + String resultFromJsonRpcNode = result.substring(4, resultLen - 12); + response = HttpMethed.getNowBlock(httpFullNode); + responseContent = HttpMethed.parseResponseContent(response); + String resultFromHttp = responseContent.getString("blockID"); + logger.info("resultFromJsonRpcNode:" + resultFromJsonRpcNode); + logger.info("resultFromHttp:" + resultFromHttp); + Assert.assertEquals(resultFromJsonRpcNode, resultFromHttp); + } + + @Test(enabled = true, description = "Json rpc api of eth_hashrate") + public void test24JsonRpcApiTestForEthHashRate() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_hashrate", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + logger.info(result); + Assert.assertEquals("0x0", result); + } + + @Test(enabled = true, description = "Json rpc api of eth_mining") + public void test25JsonRpcApiTestForEthMining() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_mining", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + logger.info(result); + Assert.assertEquals(result, "true"); + } + + @Test(enabled = true, description = "Json rpc api of eth_protocolVersion") + public void test26JsonRpcApiTestForEthProtocolVersion() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_protocolVersion", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String protocolVersion = responseContent.getString("result").substring(2); + Long protocolVersion1 = Long.parseLong(protocolVersion, 16); + response = HttpMethed.getNowBlock(httpFullNode); + responseContent = HttpMethed.parseResponseContent(response); + Long protocolVersion2 = + responseContent.getJSONObject("block_header").getJSONObject("raw_data").getLong("version"); + logger.info(protocolVersion1.toString()); + logger.info(protocolVersion2.toString()); + Assert.assertEquals(protocolVersion1, protocolVersion2); + } + + @Test(enabled = true, description = "Json rpc api of eth_syncing") + public void test27JsonRpcApiTestForEthSyncing() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_syncing", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + JSONObject temp = responseContent.getJSONObject("result"); + logger.info(temp.toString()); + Assert.assertTrue(temp.containsKey("startingBlock")); + Assert.assertTrue(temp.containsKey("currentBlock")); + Assert.assertTrue(temp.containsKey("highestBlock")); + } + + @Test(enabled = true, description = "Json rpc api of net_listening") + public void test28JsonRpcApiTestForNetListening() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("net_listening", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + Boolean temp = responseContent.getBoolean("result"); + logger.info(temp.toString()); + response = HttpMethed.getNodeInfo(httpFullNode); + responseContent = HttpMethed.parseResponseContent(response); + boolean expect = false; + int num = responseContent.getInteger("activeConnectCount"); + if (num >= 1) { + expect = true; + } + Assert.assertEquals(temp, expect); + } + + @Test(enabled = true, description = "Json rpc api of net_peerCount") + public void test29JsonRpcApiTestForNetPeerCount() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("net_peerCount", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + logger.info(result); + Assert.assertNotNull(result); + } + + @Test(enabled = true, description = "Json rpc api of net_version") + public void test30JsonRpcApiTestForEthVersion() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("net_version", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String firstBlockHashFromJsonRpc = responseContent.getString("result").substring(2); + response = HttpMethed.getBlockByNum(httpFullNode, 0); + responseContent = HttpMethed.parseResponseContent(response); + String firstBlockHashFromHttp = responseContent.getString("blockID").substring(56); + logger.info("firstBlockHashFromJsonRpc" + firstBlockHashFromJsonRpc); + logger.info("firstBlockHashFromHttp" + firstBlockHashFromHttp); + Assert.assertEquals(firstBlockHashFromJsonRpc, firstBlockHashFromHttp); + } + + @Test(enabled = true, description = "Json rpc api of web3_clientVersion") + public void test31JsonRpcApiTestForWeb3ClientVersion() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("web3_clientVersion", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String result = responseContent.getString("result"); + List resultList = new ArrayList<>(); + for (String str : result.split("/")) { + resultList.add(str); + } + Assert.assertEquals(resultList.size(), 5); + Assert.assertEquals(resultList.get(0), "TRON"); + Assert.assertEquals(resultList.get(1).substring(0, 1), "v"); + Assert.assertEquals(resultList.get(2), "Linux"); + Assert.assertEquals(resultList.get(3), "Java1.8"); + Assert.assertEquals(resultList.get(4).substring(0, 11), "GreatVoyage"); + } + + @Test(enabled = true, description = "Json rpc api of web3_sha3") + public void test32JsonRpcApiTestForWeb3Sha3() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x08"); + JsonObject requestBody1 = getJsonRpcBody("web3_sha3", params); + response = getEthHttps(ethHttpsNode, requestBody1); + responseContent = HttpMethed.parseResponseContent(response); + String result1 = responseContent.getString("result"); + JsonObject requestBody2 = getJsonRpcBody("web3_sha3", params); + response = getJsonRpc(jsonRpcNode, requestBody2); + responseContent = HttpMethed.parseResponseContent(response); + String result2 = responseContent.getString("result"); + Assert.assertEquals(result1, result2); + } + + @Test(enabled = true, description = "Json rpc api of eth_compileLLL") + public void test33JsonRpcApiTestForEthCompileLll() throws Exception { + JsonArray params = new JsonArray(); + params.add("(returnlll (suicide (caller)))"); + JsonObject requestBody1 = getJsonRpcBody("eth_compileLLL", params); + response = getJsonRpc(jsonRpcNode, requestBody1); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals(errorMessage, "the method eth_compileLLL does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_compileSerpent") + public void test34JsonRpcApiTestForEthCompileSerpent() throws Exception { + JsonArray params = new JsonArray(); + params.add("/* some serpent */"); + JsonObject requestBody = getJsonRpcBody("eth_compileSerpent", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_compileSerpent does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_compileSolidity") + public void test35JsonRpcApiTestForEthCompileSolidity() throws Exception { + JsonArray params = new JsonArray(); + params.add("contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"); + JsonObject requestBody = getJsonRpcBody("eth_compileSolidity", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_compileSolidity does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_getCompilers") + public void test36JsonRpcApiTestForEthCompileSolidity() throws Exception { + JsonArray params = new JsonArray(); + JsonObject requestBody = getJsonRpcBody("eth_getCompilers", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_getCompilers does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_getTransactionCount") + public void test37JsonRpcApiTestForEthGetTransactionCount() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x407d73d8a49eeb85d32cf465507dd71d507100c1"); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_getTransactionCount", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_getTransactionCount does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_sendRawTransaction") + public void test38JsonRpcApiTestForEthSendRawTransaction() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x234"); + JsonObject requestBody = getJsonRpcBody("eth_sendRawTransaction", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_sendRawTransaction does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_sendTransaction") + public void test39JsonRpcApiTestForEthSendTransaction() throws Exception { + JsonArray params = new JsonArray(); + JsonObject temp = new JsonObject(); + params.add(temp); + temp.addProperty("from", "0xb60e8dd61c5d32be8058bb8eb970870f07233155"); + temp.addProperty("to", "0xd46e8dd67c5d32be8058bb8eb970870f07244567"); + temp.addProperty("gas", "0x76c0"); + temp.addProperty("gasPrice", "0x9184e72a000"); + temp.addProperty( + "data", + "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"); + temp.addProperty("value", "0x9184e72a"); + + JsonObject requestBody = getJsonRpcBody("eth_sendTransaction", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_sendTransaction does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_sign") + public void test40JsonRpcApiTestForEthSign() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x9b2055d370f73ec7d8a03e965129118dc8f5bf83"); + params.add("0xdeadbeaf"); + JsonObject requestBody = getJsonRpcBody("eth_sign", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals(errorMessage, "the method eth_sign does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_signTransaction") + public void test41JsonRpcApiTestForEthSignTransaction() throws Exception { + JsonArray params = new JsonArray(); + JsonObject temp = new JsonObject(); + params.add(temp); + temp.addProperty( + "data", + "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"); + temp.addProperty("from", "0xb60e8dd61c5d32be8058bb8eb970870f07233155"); + temp.addProperty("gas", "0x76c0"); + temp.addProperty("gasPrice", "0x9184e72a000"); + temp.addProperty("to", "0xd46e8dd67c5d32be8058bb8eb970870f07244567"); + temp.addProperty("value", "0x9184e72a"); + + JsonObject requestBody = getJsonRpcBody("eth_signTransaction", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_signTransaction does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_submitWork") + public void test42JsonRpcApiTestForEthSubmitWork() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x0000000000000001"); + params.add("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"); + params.add("0xD1GE5700000000000000000000000000D1GE5700000000000000000000000000"); + JsonObject requestBody = getJsonRpcBody("eth_submitWork", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals(errorMessage, "the method eth_submitWork does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of parity_nextNonce") + public void test43JsonRpcApiTestForParityNextNonce() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x9b2055d370f73ec7d8a03e965129118dc8f5bf83"); + JsonObject requestBody = getJsonRpcBody("parity_nextNonce", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method parity_nextNonce does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_submitHashrate") + public void test44JsonRpcApiTestForEthSubmitHashrate() throws Exception { + JsonArray params = new JsonArray(); + params.add("0x0000000000000000000000000000000000000000000000000000000000500000"); + params.add("0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c"); + JsonObject requestBody = getJsonRpcBody("eth_submitHashrate", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String errorMessage = responseContent.getJSONObject("error").getString("message"); + Assert.assertEquals( + errorMessage, "the method eth_submitHashrate does not exist/is not available"); + } + + @Test(enabled = true, description = "Json rpc api of eth_getBlockByHash params is false") + public void test45JsonRpcApiTestForEthGetBlockByHash() throws Exception { + response = HttpMethed.getBlockByNum(httpFullNode, blockNum); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("45getBlockByNumFromHttp:" + responseContent); + accountStateRoot = + responseContent + .getJSONObject("block_header") + .getJSONObject("raw_data") + .getString("accountStateRoot"); + JsonArray params = new JsonArray(); + params.add(blockHash); + params.add(false); + JsonObject requestBody = getJsonRpcBody("eth_getBlockByHash", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + JSONObject getBlockByHashResult = responseContent.getJSONObject("result"); + + Assert.assertNull(getBlockByHashResult.getString("nonce")); + Assert.assertNull(getBlockByHashResult.getString("sha3Uncles")); + Assert.assertNull(getBlockByHashResult.getString("receiptsRoot")); + Assert.assertNull(getBlockByHashResult.getString("difficulty")); + Assert.assertNull(getBlockByHashResult.getString("totalDifficulty")); + Assert.assertNull(getBlockByHashResult.getString("extraData")); + Assert.assertNull(getBlockByHashResult.getString("baseFeePerGas")); + Assert.assertNull(getBlockByHashResult.getString("mixHash")); + Assert.assertEquals(getBlockByHashResult.getString("uncles"), new ArrayList<>().toString()); + Assert.assertEquals(getBlockByHashResult.getString("stateRoot"), "0x" + accountStateRoot); + + Assert.assertEquals( + getBlockByHashResult.getString("logsBloom"), + "0x00000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000"); + Assert.assertEquals(getBlockByHashResult.getString("number"), blockNumHex); + Assert.assertEquals(getBlockByHashResult.getString("hash"), "0x" + bid); + Assert.assertEquals(getBlockByHashResult.getString("parentHash"), "0x" + parentHash); + Assert.assertEquals(getBlockByHashResult.getString("transactionsRoot"), "0x" + txTrieRoot); + Assert.assertEquals(getBlockByHashResult.getString("miner"), "0x" + witnessAddress); + Assert.assertEquals(getBlockByHashResult.getString("gasUsed"), "0x" + Long.toHexString(gas)); + Assert.assertEquals( + String.valueOf(Long.parseLong(getBlockByHashResult.getString("gasLimit").substring(2), 16)), + feeLimit); + Assert.assertEquals( + Long.parseLong(getBlockByHashResult.getString("timestamp").substring(2), 16), + blockTimeStamp); + final GrpcAPI.NumberMessage message = + GrpcAPI.NumberMessage.newBuilder().setNum(blockNum).build(); + HttpMethed.waitToProduceOneBlock(httpFullNode); + Block block = blockingStubFull.getBlockByNum(message); + logger.info("sizeFromJrpc:" + block.getSerializedSize()); + logger.info( + "sizeFromJsonRPc:" + + Long.parseLong(getBlockByHashResult.getString("size").substring(2), 16)); + size = block.getSerializedSize(); + Assert.assertEquals( + Long.parseLong(getBlockByHashResult.getString("size").substring(2), 16), + block.getSerializedSize()); + + Long.parseLong(getBlockByHashResult.getString("timestamp").substring(2), 16); + JSONArray transactionId = getBlockByHashResult.getJSONArray("transactions"); + List transactionIdListFromGetBlockByHash = new ArrayList<>(); + if (transactionId.size() > 0) { + for (int i = 0; i < transactionId.size(); i++) { + transactionIdListFromGetBlockByHash.add(transactionId.get(i).toString()); + } + } + Assert.assertEquals(transactionIdListFromGetBlockByHash, transactionIdList); + } + + @Test(enabled = true, description = "Json rpc api of eth_getBlockByNumber params is true") + public void test46JsonRpcApiTestForEthGetBlockByNumber() throws Exception { + + JsonArray params = new JsonArray(); + params.add(blockNumHex); + logger.info("46blockNumHex:" + blockNumHex); + params.add(true); + JsonObject requestBody = getJsonRpcBody("eth_getBlockByNumber", params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + JSONObject getBlockByNumberResult = responseContent.getJSONObject("result"); + logger.info("getBlockByHashResult:" + getBlockByNumberResult); + + Assert.assertNull(getBlockByNumberResult.getString("nonce")); + Assert.assertNull(getBlockByNumberResult.getString("sha3Uncles")); + Assert.assertNull(getBlockByNumberResult.getString("receiptsRoot")); + Assert.assertNull(getBlockByNumberResult.getString("difficulty")); + Assert.assertNull(getBlockByNumberResult.getString("totalDifficulty")); + Assert.assertNull(getBlockByNumberResult.getString("extraData")); + Assert.assertNull(getBlockByNumberResult.getString("baseFeePerGas")); + Assert.assertNull(getBlockByNumberResult.getString("mixHash")); + Assert.assertEquals(getBlockByNumberResult.getString("uncles"), new ArrayList<>().toString()); + Assert.assertEquals(getBlockByNumberResult.getString("stateRoot"), "0x" + accountStateRoot); + Assert.assertEquals( + getBlockByNumberResult.getString("logsBloom"), + "0x00000000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000"); + Assert.assertEquals(getBlockByNumberResult.getString("number"), blockNumHex); + Assert.assertEquals(getBlockByNumberResult.getString("hash"), "0x" + bid); + Assert.assertEquals(getBlockByNumberResult.getString("parentHash"), "0x" + parentHash); + Assert.assertEquals(getBlockByNumberResult.getString("transactionsRoot"), "0x" + txTrieRoot); + Assert.assertEquals(getBlockByNumberResult.getString("miner"), "0x" + witnessAddress); + Assert.assertEquals(getBlockByNumberResult.getString("gasUsed"), "0x" + Long.toHexString(gas)); + Assert.assertEquals( + String.valueOf( + Long.parseLong(getBlockByNumberResult.getString("gasLimit").substring(2), 16)), + feeLimit); + Assert.assertEquals( + Long.parseLong(getBlockByNumberResult.getString("timestamp").substring(2), 16), + blockTimeStamp); + logger.info("size:" + size); + Assert.assertEquals( + Long.parseLong(getBlockByNumberResult.getString("size").substring(2), 16), size); + + JSONArray transactionsList = getBlockByNumberResult.getJSONArray("transactions"); + logger.info("transactionsList:" + transactionsList); + List transactionInfoListFromGetBlockByHash = new ArrayList<>(); + if (transactionsList.size() > 0) { + for (int i = 0; i < transactionsList.size(); i++) { + transactionInfoListFromGetBlockByHash.add(transactionsList.get(i).toString()); + } + } + List transactionInfoListFromTransactionByBlockNumberAndIndex = new ArrayList<>(); + for (int i = 0; i < transactionsList.size(); i++) { + JsonArray paramsForEthGetTransactionByBlockNumberAndIndex = new JsonArray(); + paramsForEthGetTransactionByBlockNumberAndIndex.add(blockNumHex); + String index = "0x" + Integer.toHexString(i); + logger.info("index:" + index); + paramsForEthGetTransactionByBlockNumberAndIndex.add(index); + logger.info( + "paramsForEthGetTransactionByBlockNumberAndIndex:" + + paramsForEthGetTransactionByBlockNumberAndIndex); + JsonObject requestBodyForTransactionByBlockNumberAndIndex = + getJsonRpcBody( + "eth_getTransactionByBlockNumberAndIndex", + paramsForEthGetTransactionByBlockNumberAndIndex); + response = getJsonRpc(jsonRpcNode, requestBodyForTransactionByBlockNumberAndIndex); + responseContent = HttpMethed.parseResponseContent(response); + logger.info("responseContent:" + responseContent); + result = responseContent.getJSONObject("result"); + logger.info("result:" + result); + transactionInfoListFromTransactionByBlockNumberAndIndex.add(result.toString()); + } + Assert.assertEquals( + transactionInfoListFromGetBlockByHash, + transactionInfoListFromTransactionByBlockNumberAndIndex); + } + + /** constructor. */ + @AfterClass + public void shutdown() throws InterruptedException { + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } +} diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/BuildTransaction001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/BuildTransaction001.java new file mode 100644 index 00000000000..0521f094147 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/BuildTransaction001.java @@ -0,0 +1,121 @@ +package stest.tron.wallet.dailybuild.jsonrpc; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.protobuf.ByteString; +import io.grpc.ManagedChannelBuilder; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpResponse; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.tron.api.WalletGrpc; +import org.tron.common.crypto.ECKey; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; +import stest.tron.wallet.common.client.utils.HttpMethed; +import stest.tron.wallet.common.client.utils.JsonRpcBase; +import stest.tron.wallet.common.client.utils.PublicMethed; + + + +@Slf4j + +public class BuildTransaction001 extends JsonRpcBase { + + JSONArray jsonRpcReceives = new JSONArray(); + //String txid; + private JSONObject responseContent; + private HttpResponse response; + String transactionString; + String transactionSignString; + + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] receiverAddress = ecKey1.getAddress(); + final String receiverKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + + /** + * constructor. + */ + @BeforeClass(enabled = true) + public void beforeClass() { + channelFull = ManagedChannelBuilder.forTarget(fullnode) + .usePlaintext(true) + .build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + } + + + + @Test(enabled = true, description = "Json rpc api of buildTransaction for transfer trx") + public void test01JsonRpcApiTestOfBuildTransactionForTransferTrx() throws Exception { + final Long beforeRecevierBalance = HttpMethed.getBalance(httpFullNode, receiverAddress); + + + JsonObject param = new JsonObject(); + param.addProperty("from", ByteArray.toHexString(jsonRpcOwnerAddress)); + param.addProperty("to", ByteArray.toHexString(receiverAddress)); + param.addProperty("value", "0x1"); + JsonArray params = new JsonArray(); + params.add(param); + JsonObject requestBody = getJsonRpcBody("buildTransaction",params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + transactionString = responseContent.getJSONObject("result").getString("transaction"); + transactionSignString = HttpMethed.gettransactionsign(httpFullNode, transactionString, + jsonRpcOwnerKey); + response = HttpMethed.broadcastTransaction(httpFullNode, transactionSignString); + Assert.assertTrue(HttpMethed.verificationResult(response)); + + HttpMethed.waitToProduceOneBlock(httpFullNode); + Long afterRecevierBalance = HttpMethed.getBalance(httpFullNode, receiverAddress); + + Assert.assertEquals(afterRecevierBalance - beforeRecevierBalance,1L); + + } + + @Test(enabled = true, description = "Json rpc api of buildTransaction for transfer trc10") + public void test02JsonRpcApiTestOfBuildTransactionForTransferTrc10() throws Exception { + PublicMethed.waitProduceNextBlock(blockingStubFull); + final Long beforeTokenBalance = PublicMethed.getAssetBalanceByAssetId(ByteString + .copyFromUtf8(jsonRpcAssetId), receiverKey, blockingStubFull); + JsonObject param = new JsonObject(); + param.addProperty("from", ByteArray.toHexString(jsonRpcOwnerAddress)); + param.addProperty("to", ByteArray.toHexString(receiverAddress)); + param.addProperty("tokenId", Long.valueOf(jsonRpcAssetId)); + param.addProperty("tokenValue", 1); + JsonArray params = new JsonArray(); + params.add(param); + JsonObject requestBody = getJsonRpcBody("buildTransaction",params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + transactionString = responseContent.getJSONObject("result").getString("transaction"); + transactionSignString = HttpMethed.gettransactionsign(httpFullNode, transactionString, + jsonRpcOwnerKey); + response = HttpMethed.broadcastTransaction(httpFullNode, transactionSignString); + Assert.assertTrue(HttpMethed.verificationResult(response)); + + HttpMethed.waitToProduceOneBlock(httpFullNode); + Long afterTokenBalance = PublicMethed.getAssetBalanceByAssetId(ByteString + .copyFromUtf8(jsonRpcAssetId), receiverKey, blockingStubFull); + + Assert.assertEquals(afterTokenBalance - beforeTokenBalance,1L); + + } + + /** + * constructor. + */ + @AfterClass + public void shutdown() throws InterruptedException { + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + + +} diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/EthSmartContract001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/EthSmartContract001.java new file mode 100644 index 00000000000..aee3436aed9 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/EthSmartContract001.java @@ -0,0 +1,80 @@ +package stest.tron.wallet.dailybuild.jsonrpc; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.protobuf.ByteString; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpResponse; +import org.junit.Assert; +import org.testng.annotations.Test; +import org.tron.common.crypto.ECKey; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; +import stest.tron.wallet.common.client.utils.HttpMethed; +import stest.tron.wallet.common.client.utils.JsonRpcBase; +import stest.tron.wallet.common.client.utils.PublicMethed; +import stest.tron.wallet.common.client.utils.ZenTrc20Base; + + +@Slf4j + +public class EthSmartContract001 extends JsonRpcBase { + private JSONObject responseContent; + private HttpResponse response; + + @Test(enabled = true, description = "Json rpc api of eth_call") + public void test01JsonRpcApiTestForEthCall() throws Exception { + JsonObject param = new JsonObject(); + param.addProperty("from", ByteArray.toHexString(jsonRpcOwnerAddress)); + param.addProperty("to", trc20AddressHex); + param.addProperty("gas", "0"); + param.addProperty("gasPrice", "0"); + param.addProperty("value", "0"); + param.addProperty("data", "0x06fdde03"); + JsonArray params = new JsonArray(); + params.add(param); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_call",params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String dataResult = responseContent.getString("result"); + Assert.assertEquals(dataResult,"0x000000000000000000000000000000000000000000000000000" + + "0000000000020000000000000000000000000000000000000000000000000000000000000000a546f6b65" + + "6e545243323000000000000000000000000000000000000000000000"); + } + + + @Test(enabled = true, description = "Json rpc api of eth_estimateGas") + public void test02JsonRpcApiTestForEthEstimateGas() throws Exception { + JsonObject param = new JsonObject(); + param.addProperty("from", ByteArray.toHexString(jsonRpcOwnerAddress)); + param.addProperty("to", trc20AddressHex); + param.addProperty("gas", "0x0"); + param.addProperty("gasPrice", "0x0"); + param.addProperty("value", "0x0"); + param.addProperty("data", "0x1249c58b"); + JsonArray params = new JsonArray(); + params.add(param); + JsonObject requestBody = getJsonRpcBody("eth_estimateGas",params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String dataResult = responseContent.getString("result"); + Assert.assertEquals(dataResult,"0x147"); + } + + + @Test(enabled = true, description = "Json rpc api of eth_getCode") + public void test03JsonRpcApiTestForEthGetCode() throws Exception { + JsonArray params = new JsonArray(); + params.add(trc20AddressHex); + params.add("latest"); + JsonObject requestBody = getJsonRpcBody("eth_getCode",params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + String dataResult = responseContent.getString("result"); + Assert.assertTrue(dataResult.length() > 1000L); + } + +} diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/GetBlock001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/GetBlock001.java new file mode 100644 index 00000000000..ee30990dd65 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/jsonrpc/GetBlock001.java @@ -0,0 +1,69 @@ +package stest.tron.wallet.dailybuild.jsonrpc; + +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.grpc.ManagedChannelBuilder; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpResponse; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.tron.api.WalletGrpc; +import org.tron.common.utils.ByteArray; +import stest.tron.wallet.common.client.utils.HttpMethed; +import stest.tron.wallet.common.client.utils.JsonRpcBase; + + +@Slf4j + +public class GetBlock001 extends JsonRpcBase { + private JSONObject responseContent; + private HttpResponse response; + + + /** + * constructor. + */ + @BeforeClass(enabled = true) + public void beforeClass() { + channelFull = ManagedChannelBuilder.forTarget(fullnode) + .usePlaintext(true) + .build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + } + + + + + @Test(enabled = true, description = "Json rpc api of eth_getBlockByHash") + public void test01JsonRpcApiTestForEthGetBlockByHash() throws Exception { + JsonArray params = new JsonArray(); + params.add(blockId); + params.add("true"); + JsonObject requestBody = getJsonRpcBody("eth_getBlockByHash",params); + response = getJsonRpc(jsonRpcNode, requestBody); + responseContent = HttpMethed.parseResponseContent(response); + + Assert.assertEquals(Integer.toHexString(blockNum), responseContent.getJSONObject("result") + .getString("number").substring(2)); + Assert.assertEquals(blockId, responseContent.getJSONObject("result").getString("hash") + .substring(2)); + Assert.assertTrue(responseContent.getJSONObject("result") + .getJSONArray("transactions").size() >= 1); + } + + + /** + * constructor. + */ + @AfterClass + public void shutdown() throws InterruptedException { + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + +} diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/multisign/MultiSign31.java b/framework/src/test/java/stest/tron/wallet/dailybuild/multisign/MultiSign31.java index 468cba915cc..7aa7403c631 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/multisign/MultiSign31.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/multisign/MultiSign31.java @@ -255,8 +255,8 @@ public void testMultiUpdatepermissions_35() { Assert .assertThat(returnResult1.getCode().toString(), containsString("SIGERROR")); Assert - .assertThat(returnResult1.getMessage().toStringUtf8(), - containsString("validate signature error Permission denied")); + .assertThat(returnResult1.getMessage().toStringUtf8().toLowerCase(), + containsString("validate signature error: permission denied".toLowerCase())); Transaction transaction2 = PublicMethed .addTransactionSign(transaction1, sendAccountKey3, blockingStubFull); TransactionSignWeight transactionSignWeight1 = PublicMethedForMutiSign @@ -275,7 +275,7 @@ public void testMultiUpdatepermissions_35() { .broadcastTransaction1(transaction2, blockingStubFull); logger.info("returnResult2:" + returnResult2); Assert - .assertThat(returnResult2.getCode().toString(), containsString("DUP_TRANSACTION_ERROR")); + .assertThat(returnResult2.getCode().toString(), containsString("SIGERROR")); Account test001AddressAccount3 = PublicMethed.queryAccount(test001Address, blockingStubFull); long balance3 = test001AddressAccount3.getBalance(); logger.info("balance3:" + balance3); @@ -466,7 +466,7 @@ public void testMultiUpdatepermissions_37() { .broadcastTransaction1(transaction2, blockingStubFull); logger.info("returnResult2:" + returnResult2); Assert - .assertThat(returnResult2.getCode().toString(), containsString("DUP_TRANSACTION_ERROR")); + .assertThat(returnResult2.getCode().toString(), containsString("SIGERROR")); Account test001AddressAccount3 = PublicMethed.queryAccount(test001Address, blockingStubFull); long balance3 = test001AddressAccount3.getBalance(); Assert.assertEquals(balance2, balance3); @@ -558,7 +558,7 @@ public void testMultiUpdatepermissions_38() { .broadcastTransaction1(transaction2, blockingStubFull); logger.info("returnResult2:" + returnResult2); Assert - .assertThat(returnResult2.getCode().toString(), containsString("DUP_TRANSACTION_ERROR")); + .assertThat(returnResult2.getCode().toString(), containsString("SIGERROR")); Account test001AddressAccount3 = PublicMethed.queryAccount(test001Address, blockingStubFull); long balance3 = test001AddressAccount3.getBalance(); Assert.assertEquals(balance3, balance2); diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken003.java b/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken003.java index 9fdafd94f68..ee46fba9c39 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken003.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken003.java @@ -152,7 +152,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); Assert - .assertEquals("contract validate error : No asset !", response.getMessage().toStringUtf8()); + .assertEquals("contract validate error : No asset !".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // deployer didn't have any such token fakeTokenId = assetAccountUser.toStringUtf8(); @@ -164,8 +165,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : assetBalance must greater than 0.", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : assetBalance must greater than 0.".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // deployer didn't have any Long.MAX_VALUE fakeTokenId = Long.toString(Long.MAX_VALUE); @@ -177,8 +178,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert - .assertEquals("contract validate error : No asset !", response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : No asset !".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // the tokenValue is not enough fakeTokenId = assetAccountDev.toStringUtf8(); @@ -190,8 +191,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : assetBalance is not sufficient.", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : assetBalance is not sufficient.".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // tokenid is -1 fakeTokenId = Long.toString(-1); @@ -201,8 +202,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); PublicMethed.waitProduceNextBlock(blockingStubFull); @@ -214,8 +215,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // tokenid is Long.MIN_VALUE fakeTokenId = Long.toString(Long.MIN_VALUE); @@ -225,8 +226,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); PublicMethed.waitProduceNextBlock(blockingStubFull); @@ -240,8 +241,9 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); Assert.assertEquals( - "contract validate error : invalid arguments with tokenValue = 100, tokenId = 0", - response.getMessage().toStringUtf8()); + ("contract validate error : invalid arguments " + + "with tokenValue = 100, tokenId = 0").toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // tokenvalue is less than 0 fakeTokenValue = -1L; @@ -253,8 +255,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenValue must be >= 0", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenValue must be >= 0".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); PublicMethed.waitProduceNextBlock(blockingStubFull); @@ -268,8 +270,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenValue must be >= 0", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenValue must be >= 0".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); String tokenId = Long.toString(-1); long tokenValue = 0; @@ -281,8 +283,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); PublicMethed.waitProduceNextBlock(blockingStubFull); @@ -296,8 +298,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); PublicMethed.waitProduceNextBlock(blockingStubFull); @@ -311,8 +313,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); accountResource = PublicMethed.getAccountResource(dev001Address, blockingStubFull); energyLimit = accountResource.getEnergyLimit(); diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken005.java b/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken005.java index 7d3b7d5fd79..8c60e5b0ff2 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken005.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/trctoken/ContractTrcToken005.java @@ -216,7 +216,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); Assert - .assertEquals("contract validate error : No asset !", response.getMessage().toStringUtf8()); + .assertEquals("contract validate error : No asset !".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // not have this tokenId tokenId = assetAccountId.toStringUtf8(); @@ -229,8 +230,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : Owner no asset!", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : Owner no asset!".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // tokenId is Long.MAX_VALUE tokenId = Long.toString(Long.MAX_VALUE); @@ -244,7 +245,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); Assert - .assertEquals("contract validate error : No asset !", response.getMessage().toStringUtf8()); + .assertEquals("contract validate error : No asset !".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); Assert.assertTrue(PublicMethed .transferAsset(user001Address, assetAccountId.toByteArray(), 10L, dev001Address, dev001Key, @@ -262,8 +264,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : assetBalance is not sufficient.", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : assetBalance is not sufficient.".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // tokenvalue is less than 0 tokenId = assetAccountId.toStringUtf8(); @@ -276,8 +278,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenValue must be >= 0", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenValue must be >= 0".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); tokenId = assetAccountId.toStringUtf8(); tokenValue = Long.MIN_VALUE; @@ -289,8 +291,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenValue must be >= 0", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenValue must be >= 0".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); /*PublicMethed .sendcoin(transferTokenContractAddress, 5000000, fromAddress, testKey002, blockingStubFull); @@ -307,8 +309,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // tokenId is long.min tokenId = Long.toString(Long.MIN_VALUE); @@ -321,8 +323,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); // tokenId is 0 tokenId = Long.toString(0); @@ -336,8 +338,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); Assert.assertEquals( - "contract validate error : invalid arguments with tokenValue = 10, tokenId = 0", - response.getMessage().toStringUtf8()); + "contract validate error : invalid arguments with tokenValue = 10, tokenId = 0" + .toLowerCase(), response.getMessage().toStringUtf8().toLowerCase()); /*PublicMethed .sendcoin(transferTokenContractAddress, 5000000, fromAddress, testKey002, blockingStubFull); @@ -353,8 +355,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); tokenId = Long.toString(-1); @@ -367,8 +369,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); tokenId = Long.toString(100_0000L); @@ -381,8 +383,8 @@ public void deployTransferTokenContract() { Assert.assertFalse(response.getResult()); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, response.getCode()); - Assert.assertEquals("contract validate error : tokenId must be > 1000000", - response.getMessage().toStringUtf8()); + Assert.assertEquals("contract validate error : tokenId must be > 1000000".toLowerCase(), + response.getMessage().toStringUtf8().toLowerCase()); accountResource = PublicMethed.getAccountResource(dev001Address, blockingStubFull); long devEnergyLimitAfter = accountResource.getEnergyLimit(); diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi001.java index 9da1f2b3227..5e90c5ca4cb 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi001.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi001.java @@ -234,7 +234,7 @@ public void testClearAbi004() { containsString("CONTRACT_VALIDATE_ERROR")); Assert .assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); } @@ -251,7 +251,7 @@ public void testClearAbi005() { Assert.assertThat(transactionExtention.getResult().getCode().toString(), containsString("CONTRACT_VALIDATE_ERROR")); Assert.assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); } @@ -266,7 +266,7 @@ public void testClearAbi006() { containsString("CONTRACT_VALIDATE_ERROR")); Assert .assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); byte[] fakeAddress1 = "412B5D3405B2D26767C9C09886D53DEAFF6EB718AC111".getBytes(); TransactionExtention transactionExtention1 = PublicMethed @@ -277,7 +277,7 @@ public void testClearAbi006() { containsString("CONTRACT_VALIDATE_ERROR")); Assert .assertThat(transactionExtention1.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi004.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi004.java index a7593980fe5..84d4a1531b6 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi004.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi004.java @@ -91,7 +91,7 @@ public void testClearAbi() { containsString("CONTRACT_VALIDATE_ERROR")); Assert .assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi006.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi006.java index dc7a211b21a..0a8b65a2232 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi006.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi006.java @@ -92,7 +92,7 @@ public void testClearAbi() { Assert.assertThat(transactionExtention.getResult().getCode().toString(), containsString("CONTRACT_VALIDATE_ERROR")); Assert.assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi007.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi007.java index 2e323a1251f..d3b5c957397 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi007.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/clearabi/ClearAbi007.java @@ -94,7 +94,7 @@ public void testClearAbi() { containsString("CONTRACT_VALIDATE_ERROR")); Assert .assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); byte[] fakeAddress1 = "412B5D3405B2D26767C9C09886D53DEAFF6EB718AC111".getBytes(); TransactionExtention transactionExtention1 = PublicMethed @@ -105,7 +105,7 @@ public void testClearAbi() { containsString("CONTRACT_VALIDATE_ERROR")); Assert .assertThat(transactionExtention1.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : Contract not exists")); + containsString("Contract validate error : Contract not exists")); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test003.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test003.java index cfff3570bc3..636bdacd4e8 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test003.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test003.java @@ -195,7 +195,7 @@ public void test02TriggerCreate2WithInvalidBytecode() { Assert.assertEquals(1, infoById.get().getResultValue()); Assert .assertThat(infoById.get().getResMessage().toStringUtf8(), - containsString("Not enough energy for 'SWAP1' operation executing")); + containsString("REVERT opcode executed")); } @Test(enabled = true, description = "Trigger create2 command with empty bytecode") diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test014.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test014.java index 164bb833da3..a7d270992b5 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test014.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test014.java @@ -329,7 +329,7 @@ public void test02TriggerCreate2ToDeployTestContractAgain() { Assert.assertEquals(1, infoById.get().getResultValue()); Assert .assertThat(infoById.get().getResMessage().toStringUtf8(), - containsString("Not enough energy for 'SWAP1' operation executing")); + containsString("REVERT opcode executed")); } // Istanbul change create2 algorithm diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test019.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test019.java index a7281fcf74d..0785bce1985 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test019.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test019.java @@ -253,7 +253,7 @@ public void testTriggerContract() { containsString("CONTRACT_VALIDATE_ERROR")); Assert .assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : No contract or not a valid smart contract")); + containsString("Contract validate error : No contract or not a valid smart contract")); txid = PublicMethed .triggerContract(contractAddress, diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test020.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test020.java index 8e58e3def0b..3637d1f4814 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test020.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test020.java @@ -516,7 +516,8 @@ public void testTriggerContract3() { } - @Test(enabled = true, description = "TriggerContract a constant function created by create2") + @Test(enabled = true, description = "TriggerContract a constant function created by create2" + + "can not create2 twice if salt type is string") public void testTriggerContract4() { Account info; AccountResourceMessage resourceInfo = PublicMethed.getAccountResource(contractExcAddress, @@ -630,11 +631,12 @@ public void testTriggerContract4() { Assert .assertThat(ByteArray .toStr(infoById2.get().getResMessage().toByteArray()), - containsString("Not enough energy")); + containsString("REVERT opcode executed")); } - @Test(enabled = true, description = "TriggerContract a constant function created by create2") + @Test(enabled = true, description = "TriggerContract a constant function created by create2" + + "can not create2 twice if salt type is string") public void testTriggerContract5() { Account info; @@ -750,11 +752,12 @@ public void testTriggerContract5() { Assert .assertThat(ByteArray .toStr(infoById2.get().getResMessage().toByteArray()), - containsString("Not enough energy")); + containsString("REVERT opcode executed")); } - @Test(enabled = true, description = "TriggerContract a constant function created by create2") + @Test(enabled = true, description = "TriggerContract a constant function created by create2" + + "can not create2 twice if salt type is string") public void testTriggerContract6() { Account info; @@ -872,7 +875,7 @@ public void testTriggerContract6() { Assert .assertThat(ByteArray .toStr(infoById2.get().getResMessage().toByteArray()), - containsString("Not enough energy")); + containsString("REVERT opcode executed")); } /** diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test024.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test024.java index bc9b4ba5f78..1f3898d153d 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test024.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/create2/Create2Test024.java @@ -258,7 +258,7 @@ public void test02TriggerTestContract() { Assert.assertEquals(infoById.get().getResultValue(), 1); Assert.assertEquals(infoById.get().getResult().toString(), "FAILED"); Assert.assertThat(ByteArray.toStr(infoById.get().getResMessage().toByteArray()), - containsString("Not enough energy for 'SWAP1' operation executing: ")); + containsString("REVERT opcode executed")); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/istanbul/ChainidAndSelfBalance001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/istanbul/ChainidAndSelfBalance001.java index b46c56d2ca4..f9770923984 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/istanbul/ChainidAndSelfBalance001.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/istanbul/ChainidAndSelfBalance001.java @@ -70,14 +70,15 @@ public void chainidTest001() { String methodStr = "getId()"; TransactionExtention returns = PublicMethed .triggerConstantContractForExtention(contractAddress, methodStr, "#", - false, 0, maxFeeLimit,"0",0, testAddress001, testKey001, blockingStubFull); + false, 0, maxFeeLimit, "0", 0, testAddress001, testKey001, blockingStubFull); String chainIdHex = ByteArray.toHexString(returns.getConstantResult(0).toByteArray()); BlockExtention blockZero = PublicMethed.getBlock2(0, blockingStubFull); - String blockZeroId = ByteArray.toHexString(blockZero.getBlockid().toByteArray()); + String tem = ByteArray.toHexString(blockZero.getBlockid().toByteArray()).substring(56); + String blockZeroId = "00000000000000000000000000000000000000000000000000000000" + tem; - Assert.assertEquals(chainIdHex,blockZeroId); + Assert.assertEquals(chainIdHex, blockZeroId); } /* @@ -98,7 +99,7 @@ public void getBalanceTest001() { Long contractBalance = PublicMethed .queryAccount(contractAddress, blockingStubFull).getBalance(); - Assert.assertEquals(contractBalance,getBalance); + Assert.assertEquals(contractBalance, getBalance); } @@ -116,7 +117,7 @@ public void getBalanceTest002() { Long contractBalance = PublicMethed .queryAccount(contractAddress, blockingStubFull).getBalance(); - Assert.assertEquals(contractBalance,getBalance); + Assert.assertEquals(contractBalance, getBalance); } @@ -132,7 +133,7 @@ public void getBalanceTest003() { Long accountBalance = PublicMethed .queryAccount(testFoundationAddress, blockingStubFull).getBalance(); - Assert.assertEquals(accountBalance,getBalance); + Assert.assertEquals(accountBalance, getBalance); } @@ -148,7 +149,7 @@ public void getBalanceTest004() { false, 0, maxFeeLimit, "", 0, testAddress001, testKey001, blockingStubFull); Long getBalance = ByteArray.toLong(returns.getConstantResult(0).toByteArray()); - Assert.assertEquals(0,getBalance.longValue()); + Assert.assertEquals(0, getBalance.longValue()); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/EthGrammer.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/EthGrammer.java new file mode 100644 index 00000000000..5633f0ff936 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/EthGrammer.java @@ -0,0 +1,539 @@ +package stest.tron.wallet.dailybuild.tvmnewcommand.newGrammar; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import java.util.HashMap; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import org.tron.api.GrpcAPI; +import org.tron.api.WalletGrpc; +import org.tron.common.crypto.ECKey; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; +import org.tron.core.Wallet; +import org.tron.protos.Protocol; +import org.tron.protos.contract.SmartContractOuterClass; +import stest.tron.wallet.common.client.Configuration; +import stest.tron.wallet.common.client.Parameter; +import stest.tron.wallet.common.client.utils.Base58; +import stest.tron.wallet.common.client.utils.PublicMethed; + + + +@Slf4j +public class EthGrammer { + + private final String testNetAccountKey = Configuration.getByPath("testng.conf") + .getString("foundationAccount.key2"); + private final byte[] testNetAccountAddress = PublicMethed.getFinalAddress(testNetAccountKey); + private final String witnessKey001 = Configuration.getByPath("testng.conf") + .getString("witness.key1"); + private final byte[] witness001Address = PublicMethed.getFinalAddress(witnessKey001); + byte[] contractC = null; + byte[] contractD = null; + byte[] create2Address; + String create2Str; + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] contractExcAddress = ecKey1.getAddress(); + String contractExcKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + private Long maxFeeLimit = Configuration.getByPath("testng.conf") + .getLong("defaultParameter.maxFeeLimit"); + private ManagedChannel channelFull = null; + private WalletGrpc.WalletBlockingStub blockingStubFull = null; + + private String fullnode = Configuration.getByPath("testng.conf") + .getStringList("fullnode.ip.list").get(0); + + @BeforeSuite + public void beforeSuite() { + Wallet wallet = new Wallet(); + Wallet.setAddressPreFixByte(Parameter.CommonConstant.ADD_PRE_FIX_BYTE_MAINNET); + } + + /** + * constructor. + */ + + @BeforeClass(enabled = true) + public void beforeClass() { + PublicMethed.printAddress(contractExcKey); + channelFull = ManagedChannelBuilder.forTarget(fullnode) + .usePlaintext(true) + .build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + + Assert.assertTrue(PublicMethed + .sendcoin(contractExcAddress, 300100_000_000L, + testNetAccountAddress, testNetAccountKey, blockingStubFull)); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + String filePath = "src/test/resources/soliditycode/EthGrammer.sol"; + String contractName = "C"; + HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + String code = retMap.get("byteCode").toString(); + String abi = retMap.get("abI").toString(); + contractC = PublicMethed.deployContract(contractName, abi, code, "", maxFeeLimit, + 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + SmartContractOuterClass.SmartContract smartContract = PublicMethed.getContract(contractC, + blockingStubFull); + Assert.assertNotNull(smartContract.getAbi()); + + contractName = "D"; + retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + code = retMap.get("byteCode").toString(); + abi = retMap.get("abI").toString(); + contractD = PublicMethed.deployContract(contractName, abi, code, "", maxFeeLimit, + 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + smartContract = PublicMethed.getContract(contractD, + blockingStubFull); + Assert.assertNotNull(smartContract.getAbi()); + } + + + @Test(enabled = true, description = "test get base fee value = commit.No 11 energy fee") + public void test01baseFee() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "baseFee()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long basefee = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("basefee: " + basefee); + long energyfee; + Protocol.ChainParameters chainParameters = blockingStubFull + .getChainParameters(GrpcAPI.EmptyMessage.newBuilder().build()); + Optional getChainParameters = Optional.ofNullable(chainParameters); + logger.info(Long.toString(getChainParameters.get().getChainParameterCount())); + String key = ""; + boolean flag = false; + for (Integer i = 0; i < getChainParameters.get().getChainParameterCount(); i++) { + key = getChainParameters.get().getChainParameter(i).getKey(); + if ("getEnergyFee".equals(key)) { + energyfee = getChainParameters.get().getChainParameter(i).getValue(); + logger.info("energyfee: " + energyfee); + Assert.assertEquals(basefee, energyfee); + flag = true; + } + } + Assert.assertTrue(flag); + } + + @Test(enabled = true, description = "test get gas price value = commit.No 11 energy fee") + public void test02GasPrice() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "gasPrice()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + } + + @Test(enabled = true, description = "get create2 address, test get base fee ") + public void test03BaseFeeFromCreate2() { + String methedStr = "deploy(uint256)"; + String argsStr = "1"; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + String create2Str = + "41" + ByteArray.toHexString(info.get().getContractResult(0).toByteArray()) + .substring(24); + logger.info("hex create2 address: " + create2Str); + create2Address = ByteArray.fromHexString(create2Str); + logger.info("create2Address: " + Base58.encode58Check(create2Address)); + + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(create2Address, + "baseFeeOnly()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long basefee = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("basefee: " + basefee); + long energyfee; + Protocol.ChainParameters chainParameters = blockingStubFull + .getChainParameters(GrpcAPI.EmptyMessage.newBuilder().build()); + Optional getChainParameters = Optional.ofNullable(chainParameters); + logger.info(Long.toString(getChainParameters.get().getChainParameterCount())); + String key = ""; + boolean flag = false; + for (Integer i = 0; i < getChainParameters.get().getChainParameterCount(); i++) { + key = getChainParameters.get().getChainParameter(i).getKey(); + if ("getEnergyFee".equals(key)) { + energyfee = getChainParameters.get().getChainParameter(i).getValue(); + logger.info("energyfee: " + energyfee); + Assert.assertEquals(basefee, energyfee); + flag = true; + } + } + Assert.assertTrue(flag); + + transactionExtention = PublicMethed + .triggerConstantContractForExtention(create2Address, + "gasPriceOnly()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long gasprice = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("gasprice: " + gasprice); + Assert.assertEquals(basefee, gasprice); + } + + @Test(enabled = true, description = "call can use 63/64 energy in new contract") + public void test04CallEnergy() { + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] transferToAddress = ecKey1.getAddress(); + String transferToKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + PublicMethed.printAddress(transferToKey); + + Long temMaxLimitFee = 200000000L; + String methedStr = "testCall(address,address)"; + String argsStr = "\"" + Base58.encode58Check(contractD) + "\"," + "\"" + + Base58.encode58Check(transferToAddress) + "\""; + String txid = PublicMethed.triggerContract(contractC, methedStr, argsStr, + false, 0, temMaxLimitFee, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Protocol.Account testAccount = + PublicMethed.queryAccountByAddress(transferToAddress, blockingStubFull); + logger.info("testAccount: " + testAccount.toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + Assert.assertTrue(info.get().getInternalTransactions(0).getRejected()); + Assert.assertTrue(info.get().getReceipt().getEnergyFee() < temMaxLimitFee); + } + + @Test(enabled = true, description = "create2 address call can use 63/64 energy in new contract") + public void test05Create2AddressCallEnergy() { + String methedStr = "deploy(uint256)"; + String argsStr = "2"; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + String create2Str = + "41" + ByteArray.toHexString(info.get().getContractResult(0).toByteArray()) + .substring(24); + logger.info("hex create2 address: " + create2Str); + create2Address = ByteArray.fromHexString(create2Str); + logger.info("create2Address: " + Base58.encode58Check(create2Address)); + + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] transferToAddress = ecKey1.getAddress(); + String transferToKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + PublicMethed.printAddress(transferToKey); + + Long temMaxLimitFee = 200000000L; + methedStr = "testCall(address,address)"; + argsStr = "\"" + Base58.encode58Check(contractD) + "\"," + "\"" + + Base58.encode58Check(transferToAddress) + "\""; + txid = PublicMethed.triggerContract(create2Address, methedStr, argsStr, + false, 0, temMaxLimitFee, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + info = PublicMethed.getTransactionInfoById(txid, blockingStubFull); + + Protocol.Account testAccount = + PublicMethed.queryAccountByAddress(transferToAddress, blockingStubFull); + Assert.assertEquals("", testAccount.toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + Assert.assertTrue(info.get().getInternalTransactions(0).getRejected()); + Assert.assertTrue(info.get().getReceipt().getEnergyFee() < temMaxLimitFee); + } + + @Test(enabled = true, description = "create2 address delegatecall " + + "can use 63/64 energy in new contract") + public void test06Create2AddressDelegateCallEnergy() { + String methedStr = "deploy(uint256)"; + String argsStr = "5"; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + String create2Str = + "41" + ByteArray.toHexString(info.get().getContractResult(0).toByteArray()) + .substring(24); + logger.info("hex create2 address: " + create2Str); + create2Address = ByteArray.fromHexString(create2Str); + logger.info("create2Address: " + Base58.encode58Check(create2Address)); + + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] transferToAddress = ecKey1.getAddress(); + String transferToKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + PublicMethed.printAddress(transferToKey); + + Long temMaxLimitFee = 200000000L; + methedStr = "testDelegateCall(address,address)"; + argsStr = "\"" + Base58.encode58Check(contractD) + "\"," + "\"" + + Base58.encode58Check(transferToAddress) + "\""; + txid = PublicMethed.triggerContract(create2Address, methedStr, argsStr, + false, 0, temMaxLimitFee, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + info = PublicMethed.getTransactionInfoById(txid, blockingStubFull); + + Protocol.Account testAccount = + PublicMethed.queryAccountByAddress(transferToAddress, blockingStubFull); + Assert.assertEquals("", testAccount.toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + Assert.assertTrue(info.get().getInternalTransactions(0).getRejected()); + Assert.assertTrue(info.get().getReceipt().getEnergyFee() < temMaxLimitFee); + } + + @Test(enabled = true, description = "create2 address this.function " + + "can use 63/64 energy in new contract") + public void test07Create2AddressCallFunctionEnergy() { + String methedStr = "deploy(uint256)"; + String argsStr = "6"; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + String create2Str = + "41" + ByteArray.toHexString(info.get().getContractResult(0).toByteArray()) + .substring(24); + logger.info("hex create2 address: " + create2Str); + create2Address = ByteArray.fromHexString(create2Str); + logger.info("create2Address: " + Base58.encode58Check(create2Address)); + + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] transferToAddress = ecKey1.getAddress(); + String transferToKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + PublicMethed.printAddress(transferToKey); + + Long temMaxLimitFee = 200000000L; + methedStr = "testCallFunctionInContract(address)"; + argsStr = "\"" + Base58.encode58Check(transferToAddress) + "\""; + txid = PublicMethed.triggerContract(create2Address, methedStr, argsStr, + false, 0, temMaxLimitFee, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + info = PublicMethed.getTransactionInfoById(txid, blockingStubFull); + + Protocol.Account testAccount = + PublicMethed.queryAccountByAddress(transferToAddress, blockingStubFull); + Assert.assertEquals("", testAccount.toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + Assert.assertTrue(info.get().getInternalTransactions(0).getRejected()); + Assert.assertTrue(info.get().getReceipt().getEnergyFee() < temMaxLimitFee); + } + + // + @Test(enabled = true, description = "test get Ripemd160 input is 123") + public void test08getRipemd160() { + String args = "\"123\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "getRipemd160(string)", args, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + String result = ByteArray.toHexString(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals("e3431a8e0adbf96fd140103dc6f63a3f8fa343ab000000000000000000000000", result); + } + + @Test(enabled = true, description = "test get Ripemd160 input is empty") + public void test09getRipemd160() { + String args = "\"\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "getRipemd160(string)", args, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + String result = ByteArray.toHexString(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals("9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000", result); + } + + @Test(enabled = true, description = "test get Ripemd160 input length is greater than 256") + public void test10getRipemd160() { + String args = "\"111111111111ddddddddddddd0x0000000000000000000000008b56a0602cc81fb0" + + "b99bce992b3198c0bab181ac111111111111ddddddddddddd0x0000000000000000000000008b56" + + "a0602cc81fb0b99bce992b3198c0bab181ac%^$#0000008b56a0602cc81fb0b99bce99" + + "2b3198c0bab181ac%^$#0000008b56a0602cc81fb0b99bce992b3198c0bab181ac%^$#\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "getRipemd160(string)", args, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + String result = ByteArray.toHexString(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals("173c283ebcbad0e1c623a5c0f6813cb663338369000000000000000000000000", result); + } + + @Test(enabled = true, description = "test get Ripemd160 input is string " + + "and do not convert to bytes") + public void test11getRipemd160Str() { + String args = "\"data\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "getRipemd160Str(string)", args, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + String result = ByteArray.toHexString(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals("cd43325b85172ca28e96785d0cb4832fd62cdf43000000000000000000000000", result); + } + + @Test(enabled = true, description = "test get Ripemd160 input is string and " + + "do not convert to bytes") + public void test12getRipemd160Str() { + String args = "\"000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "getRipemd160Str(string)", args, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + String result = ByteArray.toHexString(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals("efe2df697b79b5eb73a577251ce3911078811fa4000000000000000000000000", result); + } + + @Test(enabled = true, description = "test blake2f") + public void test13getBlak2f() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractC, + "callF()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + String result = ByteArray.toHexString(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals("ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac" + + "4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", + result); + + } + + @Test(enabled = true, description = "when call create2, stack depth will be checked" + + "if stack depth is greater than 64, then create command will revert" + + "but run environment can not compute so much, so the actual result is time out") + public void test14FixCreate2StackDepth() { + String methedStr = "fixCreate2StackDepth(uint256)"; + String argsStr = "123"; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + logger.info("transactionExtention: " + transactionExtention.toString()); + String message = ByteArray.toStr(transactionExtention.getResult().getMessage().toByteArray()); + Assert.assertTrue(message.contains("CPU timeout")); + /*int interCount = transactionExtention.getInternalTransactionsCount(); + int createCount = 0; + for(int i=0;i= 15 && createCount <= 64);*/ + } + + @Test(enabled = true, description = "when call create, stack depth will be checked." + + "if stack depth is greater than 64, then create command will revert" + + "but run environment can not compute so much, so the actual result is time out") + public void test15FixCreateStackDepth() { + + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + "fixCreateStackDepth()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + String message = ByteArray.toStr(transactionExtention.getResult().getMessage().toByteArray()); + logger.info("transactionExtention: " + transactionExtention.toString()); + Assert.assertTrue(message.contains("CPU timeout")); + /*int interCount = transactionExtention.getInternalTransactionsCount(); + int createCount = 0; + for(int i=0;i= 15 && createCount <= 64);*/ + + } + + @Test(enabled = false, description = "test max Energy Limit For trigger Constant contract") + public void test16MaxEnergyLimitForConstant() { + String methedStr = "transfer(address)"; + String argsStr = "\"" + Base58.encode58Check(testNetAccountAddress) + "\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + System.out.println("transactionExtention: " + transactionExtention.toString()); + } + + @Test(enabled = true, description = "commit NO.47 value can be 1e17 if commit No.63 opened") + public void test17Commit47Value() { + HashMap proposalMap = new HashMap(); + proposalMap.put(47L, 100000000000000000L); + org.testng.Assert.assertTrue(PublicMethed.createProposal(witness001Address, witnessKey001, + proposalMap, blockingStubFull)); + } + + + /** + * constructor. + */ + @AfterClass + public void shutdown() throws InterruptedException { + PublicMethed.freedResource(contractExcAddress, contractExcKey, + testNetAccountAddress, blockingStubFull); + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + + +} + diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/EthGrammer02.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/EthGrammer02.java new file mode 100644 index 00000000000..10b47c7793f --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/EthGrammer02.java @@ -0,0 +1,556 @@ +package stest.tron.wallet.dailybuild.tvmnewcommand.newGrammar; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import java.util.HashMap; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import org.tron.api.GrpcAPI; +import org.tron.api.WalletGrpc; +import org.tron.common.crypto.ECKey; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; +import org.tron.core.Wallet; +import org.tron.protos.Protocol; +import org.tron.protos.contract.SmartContractOuterClass; +import stest.tron.wallet.common.client.Configuration; +import stest.tron.wallet.common.client.Parameter; +import stest.tron.wallet.common.client.utils.PublicMethed; + + + +@Slf4j +public class EthGrammer02 { + + private final String testNetAccountKey = Configuration.getByPath("testng.conf") + .getString("foundationAccount.key2"); + private final byte[] testNetAccountAddress = PublicMethed.getFinalAddress(testNetAccountKey); + byte[] contractD = null; + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] contractExcAddress = ecKey1.getAddress(); + String contractExcKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + private Long maxFeeLimit = Configuration.getByPath("testng.conf") + .getLong("defaultParameter.maxFeeLimit"); + private ManagedChannel channelFull = null; + private WalletGrpc.WalletBlockingStub blockingStubFull = null; + + private String fullnode = Configuration.getByPath("testng.conf") + .getStringList("fullnode.ip.list").get(0); + + int salt = 11; + + @BeforeSuite + public void beforeSuite() { + Wallet wallet = new Wallet(); + Wallet.setAddressPreFixByte(Parameter.CommonConstant.ADD_PRE_FIX_BYTE_MAINNET); + } + + /** + * constructor. + */ + + @BeforeClass(enabled = true) + public void beforeClass() { + PublicMethed.printAddress(contractExcKey); + channelFull = ManagedChannelBuilder.forTarget(fullnode) + .usePlaintext(true) + .build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + + Assert.assertTrue(PublicMethed + .sendcoin(contractExcAddress, 300100_000_000L, + testNetAccountAddress, testNetAccountKey, blockingStubFull)); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + String filePath = "src/test/resources/soliditycode/EthGrammer02.sol"; + String contractName = "D"; + HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + String code = retMap.get("byteCode").toString(); + String abi = retMap.get("abI").toString(); + contractD = PublicMethed.deployContract(contractName, abi, code, "", maxFeeLimit, + 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + SmartContractOuterClass.SmartContract smartContract = PublicMethed.getContract(contractD, + blockingStubFull); + Assert.assertEquals(1, smartContract.getVersion()); + Assert.assertNotNull(smartContract.getAbi()); + } + + @Test(enabled = true, description = "can not deploy contract with bytecode ef") + public void test16forbiddenBytecodeStartWithEf() { + String code = "60ef60005360016000f3"; + String abi = "[{\"inputs\":[],\"stateMutability\":\"payable\",\"type\":\"constructor\"}]"; + String txid = PublicMethed.deployContractAndGetTransactionInfoById("test", + abi, code, "", maxFeeLimit, + 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + logger.info("info: " + info.get().toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.INVALID_CODE, + info.get().getReceipt().getResult()); + Assert.assertEquals("invalid code: must not begin with 0xef".toLowerCase(), + ByteArray.toStr(info.get().getResMessage().toByteArray()).toLowerCase()); + } + + @Test(enabled = true, description = "can not deploy contract with bytecode ef00") + public void test17forbiddenBytecodeStartWithEf() { + String code = "60ef60005360026000f3"; + String abi = "[{\"inputs\":[],\"stateMutability\":\"payable\",\"type\":\"constructor\"}]"; + String txid = PublicMethed.deployContractAndGetTransactionInfoById("test", + abi, code, "", maxFeeLimit, 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + logger.info("info: " + info.get().toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.INVALID_CODE, + info.get().getReceipt().getResult()); + Assert.assertEquals("invalid code: must not begin with 0xef".toLowerCase(), + ByteArray.toStr(info.get().getResMessage().toByteArray()).toLowerCase()); + } + + @Test(enabled = true, description = "can not deploy contract with bytecode ef0000") + public void test18forbiddenBytecodeStartWithEf() { + String code = "60ef60005360036000f3"; + String abi = "[{\"inputs\":[],\"stateMutability\":\"payable\",\"type\":\"constructor\"}]"; + String txid = PublicMethed.deployContractAndGetTransactionInfoById("test", abi, + code, "", maxFeeLimit, 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + logger.info("info: " + info.get().toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.INVALID_CODE, + info.get().getReceipt().getResult()); + Assert.assertEquals("invalid code: must not begin with 0xef".toLowerCase(), + ByteArray.toStr(info.get().getResMessage().toByteArray()).toLowerCase()); + } + + @Test(enabled = true, description = "can not deploy contract with bytecode" + + " ef00000000000000000000000000000000000000000000000000000000000000") + public void test19forbiddenBytecodeStartWithEf() { + String code = "60ef60005360206000f3"; + String abi = "[{\"inputs\":[],\"stateMutability\":\"payable\",\"type\":\"constructor\"}]"; + String txid = PublicMethed.deployContractAndGetTransactionInfoById("test", abi, + code, "", maxFeeLimit, 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + logger.info("info: " + info.get().toString()); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.INVALID_CODE, + info.get().getReceipt().getResult()); + Assert.assertEquals("invalid code: must not begin with 0xef".toLowerCase(), + ByteArray.toStr(info.get().getResMessage().toByteArray()).toLowerCase()); + } + + @Test(enabled = true, description = "can deploy contract with bytecode fe") + public void test20forbiddenBytecodeStartWithEf() { + String code = "60fe60005360016000f3"; + String abi = "[{\"inputs\":[],\"stateMutability\":\"payable\",\"type\":\"constructor\"}]"; + String txid = PublicMethed.deployContractAndGetTransactionInfoById("test", abi, + code, "", maxFeeLimit, 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + logger.info("info: " + info.get().toString()); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create with bytecode ef") + public void test21forbiddenBytecodeStartWithEf() { + String methedStr = "createDeployEf(bytes)"; + String argsStr = "\"0x60ef60005360016000f3\""; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create with bytecode ef00") + public void test22forbiddenBytecodeStartWithEf() { + String methedStr = "createDeployEf(bytes)"; + String argsStr = "\"0x60ef60005360026000f3\""; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create with bytecode ef0000") + public void test23forbiddenBytecodeStartWithEf() { + String methedStr = "createDeployEf(bytes)"; + String argsStr = "\"0x60ef60005360036000f3\""; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create with bytecode " + + "ef00000000000000000000000000000000000000000000000000000000000000") + public void test24forbiddenBytecodeStartWithEf() { + String methedStr = "createDeployEf(bytes)"; + String argsStr = "\"0x60ef60005360206000f3\""; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can deploy contract by create with bytecode fe") + public void test25forbiddenBytecodeStartWithEf() { + String methedStr = "createDeployEf(bytes)"; + String argsStr = "\"0x60fe60005360016000f3\""; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create2 with bytecode ef") + public void test26forbiddenBytecodeStartWithEf() { + String methedStr = "create2DeployEf(bytes,uint256)"; + String argsStr = "\"0x60ef60005360016000f3\"," + salt; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create2 with bytecode ef00") + public void test27forbiddenBytecodeStartWithEf() { + salt++; + String methedStr = "create2DeployEf(bytes,uint256)"; + String argsStr = "\"0x60ef60005360026000f3\"," + salt; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create2 with bytecode ef0000") + public void test28forbiddenBytecodeStartWithEf() { + salt++; + String methedStr = "create2DeployEf(bytes,uint256)"; + String argsStr = "\"0x60ef60005360036000f3\"," + salt; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not deploy contract by create2 with bytecode " + + "ef00000000000000000000000000000000000000000000000000000000000000") + public void test29forbiddenBytecodeStartWithEf() { + salt++; + String methedStr = "create2DeployEf(bytes,uint256)"; + String argsStr = "\"0x60ef60005360206000f3\"," + salt; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(1, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can deploy contract by create2 with bytecode fe") + public void test30forbiddenBytecodeStartWithEf() { + salt++; + String methedStr = "create2DeployEf(bytes,uint256)"; + String argsStr = "\"0x60fe60005360016000f3\"," + salt; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + } + + @Test(enabled = true, description = "can not sendcoin to contract") + public void test31forbiddenSendTrxToContract() { + Assert.assertFalse(PublicMethed + .sendcoin(contractD, 100_000_000L, + testNetAccountAddress, testNetAccountKey, blockingStubFull)); + } + + @Test(enabled = true, description = "db key can use high 16 bytes," + + "0x6162630000000000000000000000000000000000000000000000000000000000") + public void test32DbKeyUseHigh16Bytes() { + String slot = "0x6162630000000000000000000000000000000000000000000000000000000000"; + long value = 121; + String methedStr = "setSlot(bytes,uint256)"; + String argsStr = "\"" + slot + "\"," + value; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + methedStr = "getSlot(bytes)"; + argsStr = "\"" + slot + "\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long result = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("result: " + result); + Assert.assertEquals(value, result); + } + + @Test(enabled = true, description = "slot high 16bytes all f," + + "0xffffffffffffffffffffffffffffffff00000000000000000000000000000000") + public void test33DbKeyUseHigh16Bytes() { + String slot = "0xffffffffffffffffffffffffffffffff00000000000000000000000000000000"; + long value = 122; + String methedStr = "setSlot(bytes,uint256)"; + String argsStr = "\"" + slot + "\"," + value; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + methedStr = "getSlot(bytes)"; + argsStr = "\"" + slot + "\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long result = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("result: " + result); + Assert.assertEquals(value, result); + } + + @Test(enabled = true, description = "slot high 16bytes 1," + + " 0x0000000000000000000000000000000100000000000000000000000000000000") + public void test34DbKeyUseHigh16Bytes() { + String slot = "0x0000000000000000000000000000000100000000000000000000000000000000"; + long value = 123; + String methedStr = "setSlot(bytes,uint256)"; + String argsStr = "\"" + slot + "\"," + value; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + methedStr = "getSlot(bytes)"; + argsStr = "\"" + slot + "\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long result = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("result: " + result); + Assert.assertEquals(value, result); + } + + @Test(enabled = true, description = "slot high 16bytes all 0,low 16bytes 1." + + " 0x0000000000000000000000000000000000000000000000000000000000000001") + public void test35DbKeyUseHigh16Bytes() { + String slot = "0x0000000000000000000000000000000000000000000000000000000000000001"; + long value = 124; + String methedStr = "setSlot(bytes,uint256)"; + String argsStr = "\"" + slot + "\"," + value; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + methedStr = "getSlot(bytes)"; + argsStr = "\"" + slot + "\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long result = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("result: " + result); + Assert.assertEquals(value, result); + } + + @Test(enabled = true, description = "slot all 0," + + " 0x0000000000000000000000000000000000000000000000000000000000000000") + public void test36DbKeyUseHigh16BytesAllBytes0() { + String slot = "0x0000000000000000000000000000000000000000000000000000000000000000"; + long value = 125; + String methedStr = "setSlot(bytes,uint256)"; + String argsStr = "\"" + slot + "\"," + value; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + methedStr = "getSlot(bytes)"; + argsStr = "\"" + slot + "\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long result = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("result: " + result); + Assert.assertEquals(value, result); + } + + @Test(enabled = true, description = "slot all f," + + " 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + public void test37DbKeyUseHigh16BytesAllBytesF() { + String slot = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + long value = 126; + String methedStr = "setSlot(bytes,uint256)"; + String argsStr = "\"" + slot + "\"," + value; + String txid = PublicMethed.triggerContract(contractD, methedStr, argsStr, + false, 0, maxFeeLimit, contractExcAddress, + contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + Optional info = + PublicMethed.getTransactionInfoById(txid, blockingStubFull); + Assert.assertEquals(0, info.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + info.get().getReceipt().getResult()); + + methedStr = "getSlot(bytes)"; + argsStr = "\"" + slot + "\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + long result = ByteArray.toLong(transactionExtention.getConstantResult(0).toByteArray()); + logger.info("result: " + result); + Assert.assertEquals(value, result); + } + + @Test(enabled = true, description = "TransactionExtention has logs and internal_transactions") + public void test38ConstantLogEven() { + salt++; + String methedStr = "create2DeployEf(bytes,uint256)"; + String argsStr = "\"0x60fe60005360016000f3\"," + salt; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(contractD, + methedStr, argsStr, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals(1, transactionExtention.getLogsCount()); + Assert.assertEquals(1, transactionExtention.getInternalTransactionsCount()); + } + + /** + * constructor. + */ + @AfterClass + public void shutdown() throws InterruptedException { + PublicMethed.freedResource(contractExcAddress, contractExcKey, + testNetAccountAddress, blockingStubFull); + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + + +} + diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/FixbugTest086.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/FixbugTest086.java new file mode 100644 index 00000000000..cd31d1f6826 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/FixbugTest086.java @@ -0,0 +1,147 @@ +package stest.tron.wallet.dailybuild.tvmnewcommand.newGrammar; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import java.util.HashMap; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import org.tron.api.WalletGrpc; +import org.tron.common.crypto.ECKey; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; +import org.tron.core.Wallet; +import org.tron.protos.Protocol; +import org.tron.protos.contract.SmartContractOuterClass; +import stest.tron.wallet.common.client.Configuration; +import stest.tron.wallet.common.client.Parameter; +import stest.tron.wallet.common.client.utils.PublicMethed; + + + + +@Slf4j +public class FixbugTest086 { + + private final String testNetAccountKey = Configuration.getByPath("testng.conf") + .getString("foundationAccount.key2"); + private final byte[] testNetAccountAddress = PublicMethed.getFinalAddress(testNetAccountKey); + byte[] mapKeyContract = null; + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] contractExcAddress = ecKey1.getAddress(); + String contractExcKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + private Long maxFeeLimit = Configuration.getByPath("testng.conf") + .getLong("defaultParameter.maxFeeLimit"); + private ManagedChannel channelFull = null; + private WalletGrpc.WalletBlockingStub blockingStubFull = null; + + private String fullnode = Configuration.getByPath("testng.conf") + .getStringList("fullnode.ip.list").get(0); + + @BeforeSuite + public void beforeSuite() { + Wallet wallet = new Wallet(); + Wallet.setAddressPreFixByte(Parameter.CommonConstant.ADD_PRE_FIX_BYTE_MAINNET); + } + + /** + * constructor. + */ + + @BeforeClass(enabled = true) + public void beforeClass() { + PublicMethed.printAddress(contractExcKey); + channelFull = ManagedChannelBuilder.forTarget(fullnode) + .usePlaintext(true) + .build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + + Assert.assertTrue(PublicMethed + .sendcoin(contractExcAddress, 300100_000_000L, + testNetAccountAddress, testNetAccountKey, blockingStubFull)); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + String filePath = + "src/test/resources/soliditycode/abstractContractWithMapParamsConstructor.sol"; + String contractName = "Cat"; + HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + String code = retMap.get("byteCode").toString(); + String abi = retMap.get("abI").toString(); + mapKeyContract = PublicMethed.deployContract(contractName, abi, code, "", maxFeeLimit, + 0L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + SmartContractOuterClass.SmartContract smartContract = PublicMethed.getContract(mapKeyContract, + blockingStubFull); + Assert.assertNotNull(smartContract.getAbi()); + } + + + @Test(enabled = true, description = "abstract With Map Params") + public void test01ContractWithMapParams() { + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "getMapValue()", "#", false, + 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals(20, + ByteArray.toInt(transactionInfo.get().getContractResult(0).toByteArray())); + } + + + @Test(enabled = true, description = " super skip unimplemented in abstract contract") + public void test02SkipUnimplemented() { + String filePath = + "src/test/resources/soliditycode/super_skip_unimplemented_in_abstract_contract.sol"; + String contractName = "B"; + HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + String code = retMap.get("byteCode").toString(); + String abi = retMap.get("abI").toString(); + mapKeyContract = PublicMethed.deployContract(contractName, abi, code, "", maxFeeLimit, + 0L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + SmartContractOuterClass.SmartContract smartContract = PublicMethed.getContract(mapKeyContract, + blockingStubFull); + Assert.assertNotNull(smartContract.getAbi()); + + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "f()", "#", false, + 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals(42, + ByteArray.toInt(transactionInfo.get().getContractResult(0).toByteArray())); + } + + + /** + * constructor. + */ + @AfterClass + public void shutdown() throws InterruptedException { + PublicMethed.freedResource(contractExcAddress, contractExcKey, + testNetAccountAddress, blockingStubFull); + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + + +} + diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/FunctionArray2Storage086.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/FunctionArray2Storage086.java new file mode 100644 index 00000000000..9977fc94cc8 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/FunctionArray2Storage086.java @@ -0,0 +1,158 @@ +package stest.tron.wallet.dailybuild.tvmnewcommand.newGrammar; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import java.util.HashMap; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import org.tron.api.WalletGrpc; +import org.tron.common.crypto.ECKey; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; +import org.tron.core.Wallet; +import org.tron.protos.Protocol; +import org.tron.protos.contract.SmartContractOuterClass; +import stest.tron.wallet.common.client.Configuration; +import stest.tron.wallet.common.client.Parameter; +import stest.tron.wallet.common.client.utils.PublicMethed; + + + + +@Slf4j +public class FunctionArray2Storage086 { + + private final String testNetAccountKey = Configuration.getByPath("testng.conf") + .getString("foundationAccount.key2"); + private final byte[] testNetAccountAddress = PublicMethed.getFinalAddress(testNetAccountKey); + byte[] mapKeyContract = null; + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] contractExcAddress = ecKey1.getAddress(); + String contractExcKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + private Long maxFeeLimit = Configuration.getByPath("testng.conf") + .getLong("defaultParameter.maxFeeLimit"); + private ManagedChannel channelFull = null; + private WalletGrpc.WalletBlockingStub blockingStubFull = null; + + private String fullnode = Configuration.getByPath("testng.conf") + .getStringList("fullnode.ip.list").get(0); + + @BeforeSuite + public void beforeSuite() { + Wallet wallet = new Wallet(); + Wallet.setAddressPreFixByte(Parameter.CommonConstant.ADD_PRE_FIX_BYTE_MAINNET); + } + + /** + * constructor. + */ + + @BeforeClass(enabled = true) + public void beforeClass() { + PublicMethed.printAddress(contractExcKey); + channelFull = ManagedChannelBuilder.forTarget(fullnode) + .usePlaintext(true) + .build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + + Assert.assertTrue(PublicMethed + .sendcoin(contractExcAddress, 300100_000_000L, + testNetAccountAddress, testNetAccountKey, blockingStubFull)); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + String filePath = "src/test/resources/soliditycode/function_type_array_to_storage.sol"; + String contractName = "C"; + HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + String code = retMap.get("byteCode").toString(); + String abi = retMap.get("abI").toString(); + mapKeyContract = PublicMethed.deployContract(contractName, abi, code, "", maxFeeLimit, + 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + SmartContractOuterClass.SmartContract smartContract = PublicMethed.getContract(mapKeyContract, + blockingStubFull); + Assert.assertNotNull(smartContract.getAbi()); + } + + + @Test(enabled = true, description = "function array test view to default") + public void test01View2Default() { + String triggerTxid = + PublicMethed.triggerContract(mapKeyContract, "testViewToDefault()", "#", false, + 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals(12, + ByteArray.toInt(transactionInfo.get().getContractResult(0).substring(0, 32).toByteArray())); + Assert.assertEquals(22, + ByteArray.toInt(transactionInfo.get().getContractResult(0) + .substring(32, 64).toByteArray())); + } + + @Test(enabled = true, description = "function array pure to default") + public void test02Pure2Default() { + String triggerTxid = + PublicMethed.triggerContract(mapKeyContract, "testPureToDefault()", "#", false, + 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals(13, + ByteArray.toInt(transactionInfo.get().getContractResult(0).substring(0, 32).toByteArray())); + Assert.assertEquals(23, + ByteArray.toInt(transactionInfo.get().getContractResult(0) + .substring(32, 64).toByteArray())); + + } + + @Test(enabled = true, description = "function array pure to view ") + public void test03Pure2View() { + String triggerTxid = + PublicMethed.triggerContract(mapKeyContract, "testPureToView()", "#", false, + 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals(13, + ByteArray.toInt(transactionInfo.get().getContractResult(0).substring(0, 32).toByteArray())); + Assert.assertEquals(23, + ByteArray.toInt(transactionInfo.get().getContractResult(0) + .substring(32, 64).toByteArray())); + } + + + /** + * constructor. + */ + @AfterClass + public void shutdown() throws InterruptedException { + PublicMethed.freedResource(contractExcAddress, contractExcKey, + testNetAccountAddress, blockingStubFull); + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + + +} + diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/NewFeatureForSolc086.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/NewFeatureForSolc086.java new file mode 100644 index 00000000000..30544ef8e64 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/NewFeatureForSolc086.java @@ -0,0 +1,305 @@ +package stest.tron.wallet.dailybuild.tvmnewcommand.newGrammar; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import java.util.HashMap; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import org.tron.api.GrpcAPI; +import org.tron.api.WalletGrpc; +import org.tron.common.crypto.ECKey; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; +import org.tron.core.Wallet; +import org.tron.protos.Protocol; +import org.tron.protos.contract.SmartContractOuterClass; +import stest.tron.wallet.common.client.Configuration; +import stest.tron.wallet.common.client.Parameter; +import stest.tron.wallet.common.client.utils.PublicMethed; + + + + +@Slf4j +public class NewFeatureForSolc086 { + + private final String testNetAccountKey = Configuration.getByPath("testng.conf") + .getString("foundationAccount.key2"); + private final byte[] testNetAccountAddress = PublicMethed.getFinalAddress(testNetAccountKey); + byte[] mapKeyContract = null; + ECKey ecKey1 = new ECKey(Utils.getRandom()); + byte[] contractExcAddress = ecKey1.getAddress(); + String contractExcKey = ByteArray.toHexString(ecKey1.getPrivKeyBytes()); + private Long maxFeeLimit = Configuration.getByPath("testng.conf") + .getLong("defaultParameter.maxFeeLimit"); + private ManagedChannel channelFull = null; + private WalletGrpc.WalletBlockingStub blockingStubFull = null; + + private String fullnode = Configuration.getByPath("testng.conf") + .getStringList("fullnode.ip.list").get(0); + + @BeforeSuite + public void beforeSuite() { + Wallet wallet = new Wallet(); + Wallet.setAddressPreFixByte(Parameter.CommonConstant.ADD_PRE_FIX_BYTE_MAINNET); + } + + /** + * constructor. + */ + + @BeforeClass(enabled = true) + public void beforeClass() { + PublicMethed.printAddress(contractExcKey); + channelFull = ManagedChannelBuilder.forTarget(fullnode) + .usePlaintext(true) + .build(); + blockingStubFull = WalletGrpc.newBlockingStub(channelFull); + + Assert.assertTrue(PublicMethed + .sendcoin(contractExcAddress, 300100_000_000L, + testNetAccountAddress, testNetAccountKey, blockingStubFull)); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + String filePath = "src/test/resources/soliditycode/NewFeature086.sol"; + String contractName = "C"; + HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); + + String code = retMap.get("byteCode").toString(); + String abi = retMap.get("abI").toString(); + mapKeyContract = PublicMethed.deployContract(contractName, abi, code, "", maxFeeLimit, + 500000000L, 100, null, contractExcKey, + contractExcAddress, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + SmartContractOuterClass.SmartContract smartContract = PublicMethed.getContract(mapKeyContract, + blockingStubFull); + Assert.assertNotNull(smartContract.getAbi()); + } + + + @Test(enabled = true, description = "catch assert fail") + public void test01TrtCatchAssertFail() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(mapKeyContract, + "catchAssertFail()", "#", true, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + int trueRes = ByteArray.toInt(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals(1, trueRes); + + } + + @Test(enabled = true, description = "catch under flow") + public void test02CatchUnderFlow() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(mapKeyContract, + "catchUnderFlow()", "#", true, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + int trueRes = ByteArray.toInt(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals(17, trueRes); + + } + + @Test(enabled = true, description = "catch divide zero") + public void test03CatchDivideZero() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(mapKeyContract, + "catchDivideZero()", "#", true, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + int trueRes = ByteArray.toInt(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + Assert.assertEquals(18, trueRes); + } + + @Test(enabled = true, description = "get address code length") + public void test04GetAddressCodeLength() { + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "getAddressCodeLength()", + "#", false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertTrue(transactionInfo.get().getFee() < 40000); + } + + @Test(enabled = true, description = "fix kecca256 bug: differt length return same code") + public void test05Kecca256BugFix() { + String args = "\"abcd123\""; + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "keccak256Bug(string)", + args, false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals(0, + ByteArray.toInt(transactionInfo.get().getContractResult(0).toByteArray())); + logger.info(transactionInfo.toString()); + } + + @Test(enabled = true, description = "revert error type with params") + public void test06RevertErrorType() { + String args = "\"T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb\",1000000000"; + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "transfer(address,uint256)", + args, false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + logger.info(transactionInfo.toString()); + Assert.assertEquals(1, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals("cf479181", + ByteArray.toHexString(transactionInfo.get() + .getContractResult(0).substring(0, 4).toByteArray())); + Assert.assertEquals("0000000000000000000000000000000000000000000000000000000000000000", + ByteArray.toHexString(transactionInfo.get().getContractResult(0) + .substring(4, 36).toByteArray())); + Assert.assertEquals("000000000000000000000000000000000000000000000000000000003b9aca00", + ByteArray.toHexString(transactionInfo.get().getContractResult(0) + .substring(36, 68).toByteArray())); + + } + + @Test(enabled = true, description = "revert error type no params") + public void test07RevertErrorType() { + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "withdraw()", "#", false, + 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + Assert.assertEquals(1, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.REVERT, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals("82b42900", + ByteArray.toHexString(transactionInfo.get().getContractResult(0) + .substring(0, 4).toByteArray())); + } + + @Test(enabled = true, description = "test bytes concat") + public void test08bytesConcat() { + String args = "\"0x1234\",\"p2\",\"0x48e2f56f2c57e3532146eef2587a2a72\""; + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(mapKeyContract, + "bytesConcat(bytes,string,bytes16)", args, false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + int trueRes = ByteArray.toInt(transactionExtention.getConstantResult(0).toByteArray()); + Assert.assertEquals(36, trueRes); + } + + @Test(enabled = true, description = "test emit event") + public void test09EmitEvent() { + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "testEmitEvent()", "#", false, + 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + logger.info(transactionInfo.toString()); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals(6, + ByteArray.toInt(transactionInfo.get().getLog(0).getData().toByteArray())); + } + + + @Test(enabled = true, description = "test bytes convert to byteN overflow") + public void test10Bytes2ByteN() { + String args = "\"0x12345678\""; + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "bytes2BytesN(bytes)", + args, false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + logger.info(transactionInfo.toString()); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals("1234560000000000000000000000000000000000000000000000000000000000", + ByteArray.toHexString(transactionInfo.get().getContractResult(0).toByteArray())); + } + + @Test(enabled = true, description = "test bytes convert to byteN underflow") + public void test11Bytes2ByteN() { + String args = "\"0x1234\""; + String triggerTxid = PublicMethed.triggerContract(mapKeyContract, "bytes2BytesN(bytes)", + args, false, 0, maxFeeLimit, contractExcAddress, contractExcKey, blockingStubFull); + PublicMethed.waitProduceNextBlock(blockingStubFull); + + Optional transactionInfo = PublicMethed + .getTransactionInfoById(triggerTxid, blockingStubFull); + logger.info(transactionInfo.toString()); + Assert.assertEquals(0, transactionInfo.get().getResultValue()); + Assert.assertEquals(Protocol.Transaction.Result.contractResult.SUCCESS, + transactionInfo.get().getReceipt().getResult()); + Assert.assertEquals("1234000000000000000000000000000000000000000000000000000000000000", + ByteArray.toHexString(transactionInfo.get().getContractResult(0).toByteArray())); + } + + @Test(enabled = true, description = "get contract address by different function") + public void test12GetConcatAddress() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(mapKeyContract, + "getContractAddress()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + String res1 = ByteArray.toHexString(transactionExtention.getConstantResult(0) + .substring(0, 32).toByteArray()); + String res2 = ByteArray.toHexString(transactionExtention.getConstantResult(0) + .substring(32, 64).toByteArray()); + Assert.assertEquals(res1, res2); + } + + @Test(enabled = true, description = "test bytes concat with empty string") + public void test13bytesConcatWithEmptyStr() { + GrpcAPI.TransactionExtention transactionExtention = PublicMethed + .triggerConstantContractForExtention(mapKeyContract, + "bytesConcatWithEmptyStr()", "#", false, + 0, maxFeeLimit, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); + Assert.assertEquals(true, transactionExtention.getResult().getResult()); + Assert.assertEquals("SUCESS", + transactionExtention.getTransaction().getRet(0).getRet().toString()); + } + + /** + * constructor. + */ + @AfterClass + public void shutdown() throws InterruptedException { + PublicMethed.freedResource(contractExcAddress, contractExcKey, + testNetAccountAddress, blockingStubFull); + if (channelFull != null) { + channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + } + + +} + diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/TvmVote.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/TvmVote.java index 0236d21bc60..9d450b0392f 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/TvmVote.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/newGrammar/TvmVote.java @@ -60,7 +60,7 @@ public void beforeSuite() { * constructor. */ - @BeforeClass(enabled = false) + @BeforeClass(enabled = true) public void beforeClass() { PublicMethed.printAddress(contractExcKey); channelFull = ManagedChannelBuilder.forTarget(fullnode) @@ -88,49 +88,7 @@ public void beforeClass() { Assert.assertNotNull(smartContract.getAbi()); } - @Test(enabled = false, description = "freeze balance and vote witness") - public void yty() { - String filePath = "src/test/resources/soliditycode/tvmVote.sol"; - String contractName = "TestVote"; - - HashMap retMap = PublicMethed.getBycodeAbi(filePath, contractName); - String code = retMap.get("byteCode").toString(); - String abi = retMap.get("abI").toString(); - final String transferTokenTxid = PublicMethed - .deployContractAndGetTransactionInfoById(contractName, abi, code, "", maxFeeLimit, - 0, 0, 10000, "0", 0, - null, contractExcKey, contractExcAddress, - blockingStubFull); - - PublicMethed.waitProduceNextBlock(blockingStubFull); - Optional infoById = PublicMethed - .getTransactionInfoById(transferTokenTxid, blockingStubFull); - - if (transferTokenTxid == null || infoById.get().getResultValue() != 0) { - Assert.fail("deploy transaction failed with message: " + infoById.get().getResMessage() - .toStringUtf8()); - } - - mapKeyContract = infoById.get().getContractAddress().toByteArray(); - - String methodStr = "freeze(address,uint256,uint256)"; - String receiverAdd = Base58.encode58Check(mapKeyContract); - String args = "\"" + receiverAdd + "\"," + freezeCount + ",1"; - logger.info("receiverAdd: " + receiverAdd); - logger.info("args: " + args); - String triggerTxid = PublicMethed - .triggerContract(mapKeyContract, methodStr, args, false, 0, - 1000000000L, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); - - PublicMethed.waitProduceNextBlock(blockingStubFull); - - infoById = PublicMethed.getTransactionInfoById(triggerTxid, blockingStubFull); - logger.info("infoById: " + infoById.toString()); - - - } - - @Test(enabled = false, description = "query reward balance") + @Test(enabled = true, description = "query reward balance") public void test01QueryRewardBalance() { GrpcAPI.TransactionExtention transactionExtention = PublicMethed .triggerConstantContractForExtention(mapKeyContract, @@ -148,7 +106,7 @@ public void test01QueryRewardBalance() { } - @Test(enabled = false, description = "freeze balance and vote witness") + @Test(enabled = true, description = "freeze balance and vote witness") public void test02VoteWitness() { String methodStr = "freeze(address,uint256,uint256)"; String receiverAdd = Base58.encode58Check(mapKeyContract); @@ -191,7 +149,7 @@ public void test02VoteWitness() { Assert.assertEquals(1, voteCount); } - @Test(enabled = false, description = "query contract address is Sr Candidate or not") + @Test(enabled = true, description = "query contract address is Sr Candidate or not") public void test03IsSrCandidate() { String args = "\"" + Base58.encode58Check(mapKeyContract) + "\""; GrpcAPI.TransactionExtention transactionExtention = PublicMethed @@ -203,7 +161,7 @@ public void test03IsSrCandidate() { Assert.assertEquals(0, 0); } - @Test(enabled = false, description = "query sr address is Sr Candidate or not") + @Test(enabled = true, description = "query sr address is Sr Candidate or not") public void test04IsSrCandidate() { String args = "\"" + Base58.encode58Check(witnessAddress) + "\""; GrpcAPI.TransactionExtention transactionExtention = PublicMethed @@ -215,7 +173,7 @@ public void test04IsSrCandidate() { Assert.assertEquals(1, 1); } - @Test(enabled = false, description = "query zero address is Sr Candidate or not") + @Test(enabled = true, description = "query zero address is Sr Candidate or not") public void test05IsSrCandidate() { String args = "\"T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb\""; GrpcAPI.TransactionExtention transactionExtention = PublicMethed @@ -227,7 +185,7 @@ public void test05IsSrCandidate() { Assert.assertEquals(0, 0); } - @Test(enabled = false, description = "query sr's total vote count") + @Test(enabled = true, description = "query sr's total vote count") public void test06querySrTotalVoteCount() { String args = "\"" + Base58.encode58Check(witnessAddress) + "\""; GrpcAPI.TransactionExtention transactionExtention = PublicMethed @@ -239,7 +197,7 @@ public void test06querySrTotalVoteCount() { Assert.assertEquals(0, trueRes); } - @Test(enabled = false, description = "query contract's total vote count") + @Test(enabled = true, description = "query contract's total vote count") public void test07queryContractTotalVoteCount() { String args = "\"" + Base58.encode58Check(mapKeyContract) + "\""; GrpcAPI.TransactionExtention transactionExtention = PublicMethed @@ -251,7 +209,7 @@ public void test07queryContractTotalVoteCount() { Assert.assertEquals(freezeCount / 1000000, trueRes); } - @Test(enabled = false, description = "query vote count") + @Test(enabled = true, description = "query vote count") public void test08queryVoteCount() { String from = Base58.encode58Check(mapKeyContract); String to = Base58.encode58Check(witnessAddress); @@ -265,7 +223,7 @@ public void test08queryVoteCount() { Assert.assertEquals(voteCount, trueRes); } - @Test(enabled = false, description = "query contract used vote count") + @Test(enabled = true, description = "query contract used vote count") public void test09queryUsedVoteCount() { String from = Base58.encode58Check(mapKeyContract); String args = "\"" + from + "\""; @@ -278,7 +236,7 @@ public void test09queryUsedVoteCount() { Assert.assertEquals(voteCount, trueRes); } - @Test(enabled = false, description = "query witnesses received vote count") + @Test(enabled = true, description = "query witnesses received vote count") public void test10queryReceivedVoteCount() { String witness = Base58.encode58Check(witnessAddress); String args = "\"" + witness + "\""; @@ -302,7 +260,7 @@ public void test10queryReceivedVoteCount() { Assert.assertEquals(trueRes, receiveCount); } - @Test(enabled = false, description = "withdraw reward") + @Test(enabled = true, description = "withdraw reward") public void test11WithdrawReward() { String methodStr = "withdrawReward()"; String triggerTxid = PublicMethed.triggerContract(mapKeyContract, methodStr, "#", false, @@ -321,7 +279,7 @@ public void test11WithdrawReward() { Assert.assertEquals("", internal.getCallValueInfo(0).toString()); } - @Test(enabled = false, description = "unfreeze energy") + @Test(enabled = true, description = "unfreeze energy") public void test12Unfreeze() { String methodStr = "unfreeze(address,uint256)"; String args = "\"" + Base58.encode58Check(mapKeyContract) + "\",1"; @@ -340,7 +298,7 @@ public void test12Unfreeze() { Assert.assertEquals(freezeCount, internal.getCallValueInfo(0).getCallValue()); } - @Test(enabled = false, description = "kill me") + @Test(enabled = true, description = "kill me") public void test13Suicide() { String methodStr = "killme(address)"; String args = "\"" + Base58.encode58Check(witnessAddress) + "\""; diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/transferfailed/ContractTestSendCoin001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/transferfailed/ContractTestSendCoin001.java index 58222f029b9..59cf22a7d43 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/transferfailed/ContractTestSendCoin001.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/transferfailed/ContractTestSendCoin001.java @@ -181,7 +181,7 @@ public void testSendCoinAndTransferAssetContract001() { dev001Address, dev001Key, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer asset to smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer asset to smartContract.", ret.getMessage().toStringUtf8()); Long contractAssetCount = PublicMethed .getAssetIssueValue(transferTokenContractAddress, assetAccountId, blockingStubFull); @@ -194,7 +194,7 @@ public void testSendCoinAndTransferAssetContract001() { .sendcoinForReturn(transferTokenContractAddress, 1_000_000L, fromAddress, testKey002, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret1.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer TRX to a smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer TRX to a smartContract.", ret1.getMessage().toStringUtf8()); String num = "\"" + Base58.encode58Check(dev001Address) + "\""; @@ -328,7 +328,7 @@ public void testSendCoinAndTransferAssetContract002() { dev001Address, dev001Key, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer asset to smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer asset to smartContract.", ret.getMessage().toStringUtf8()); Long contractAssetCount = PublicMethed .getAssetIssueValue(testContractAddress, assetAccountId, blockingStubFull); @@ -341,7 +341,7 @@ public void testSendCoinAndTransferAssetContract002() { .sendcoinForReturn(testContractAddress, 1_000_000L, fromAddress, testKey002, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret1.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer TRX to a smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer TRX to a smartContract.", ret1.getMessage().toStringUtf8()); String num = "\"" + Base58.encode58Check(dev001Address) + "\""; @@ -478,7 +478,7 @@ public void testSendCoinAndTransferAssetContract003() { dev001Address, dev001Key, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer asset to smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer asset to smartContract.", ret.getMessage().toStringUtf8()); Return ret1 = PublicMethed @@ -486,7 +486,7 @@ public void testSendCoinAndTransferAssetContract003() { dev001Address, dev001Key, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret1.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer asset to smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer asset to smartContract.", ret1.getMessage().toStringUtf8()); txid = PublicMethed @@ -557,7 +557,7 @@ public void testSendCoinAndTransferAssetContract003() { Assert.assertThat(transactionExtention.getResult().getCode().toString(), containsString("CONTRACT_VALIDATE_ERROR")); Assert.assertThat(transactionExtention.getResult().getMessage().toStringUtf8(), - containsString("contract validate error : No contract or not a valid smart contract")); + containsString("Contract validate error : No contract or not a valid smart contract")); Assert.assertTrue(PublicMethed .transferAsset(returnAddressBytes, assetAccountId.toByteArray(), 100L, dev001Address, @@ -592,7 +592,7 @@ public void testSendCoinAndTransferAssetContract003() { dev001Address, dev001Key, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer asset to smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer asset to smartContract.", ret.getMessage().toStringUtf8()); ret1 = PublicMethed @@ -600,7 +600,7 @@ public void testSendCoinAndTransferAssetContract003() { dev001Address, dev001Key, blockingStubFull); Assert.assertEquals(CONTRACT_VALIDATE_ERROR, ret1.getCode()); - Assert.assertEquals("contract validate error : Cannot transfer asset to smartContract.", + Assert.assertEquals("Contract validate error : Cannot transfer asset to smartContract.", ret1.getMessage().toStringUtf8()); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/triggerconstant/TriggerConstant003.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/triggerconstant/TriggerConstant003.java index b542e36e10b..c28e838eed1 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/triggerconstant/TriggerConstant003.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/triggerconstant/TriggerConstant003.java @@ -209,7 +209,7 @@ public void test003TriggerConstantContract() { "testPayable()", "#", false, 1L, 1000000000, "0", 0, contractExcAddress, contractExcKey, blockingStubFull); transaction = transactionExtention.getTransaction(); - + System.out.println(transactionExtention.toString()); result = transactionExtention.getConstantResult(0).toByteArray(); System.out.println("message:" + transaction.getRet(0).getRet()); System.out.println(":" + ByteArray @@ -219,11 +219,7 @@ public void test003TriggerConstantContract() { Assert.assertEquals(1, ByteArray.toLong(ByteArray .fromHexString(Hex .toHexString(result)))); - Assert.assertEquals("constant cannot set call value or call token value.", - ByteArray - .toStr(transactionExtention.getResult().getMessage().toByteArray())); - Assert.assertEquals("FAILED", transaction.getRet(0).getRet().toString()); - + Assert.assertEquals("SUCESS", transaction.getRet(0).getRet().toString()); } diff --git a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/zenProofCommand/pedersenHash001.java b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/zenProofCommand/pedersenHash001.java index 74f1c0bd833..9ea86709e2e 100644 --- a/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/zenProofCommand/pedersenHash001.java +++ b/framework/src/test/java/stest/tron/wallet/dailybuild/tvmnewcommand/zenProofCommand/pedersenHash001.java @@ -86,12 +86,14 @@ public void test01DataIsEmpty() { PublicMethed.waitProduceNextBlock(blockingStubFull); Optional infoById = PublicMethed .getTransactionInfoById(txid, blockingStubFull); - Assert.assertEquals(1, infoById.get().getResultValue()); - Assert.assertEquals("FAILED", infoById.get().getResult().toString()); - Assert.assertEquals("OUT_OF_ENERGY", infoById.get().getReceipt().getResult().toString()); - Assert.assertEquals(1000000000, infoById.get().getFee()); - Assert.assertTrue(infoById.get().getResMessage().toStringUtf8() - .contains("Not enough energy for 'SWAP2' operation executing: curInvokeEnergyLimit")); + Assert.assertEquals(0, infoById.get().getResultValue()); + Assert.assertEquals("SUCESS", infoById.get().getResult().toString()); + byte[] result = infoById.get().getContractResult(0).toByteArray(); + String boolResult = ByteArray.toHexString(ByteArray.subArray(result, 0, 32)); + System.out.println("boolResult: " + boolResult); + Assert.assertEquals("0000000000000000000000000000000000000000000000000000000000000000", + boolResult); + } @Test(enabled = true, description = "data length limit") @@ -106,12 +108,11 @@ public void test02DataLengthLimit() { PublicMethed.waitProduceNextBlock(blockingStubFull); infoById = PublicMethed .getTransactionInfoById(txid, blockingStubFull); - Assert.assertEquals(1, infoById.get().getResultValue()); - Assert.assertEquals("FAILED", infoById.get().getResult().toString()); - Assert.assertEquals("OUT_OF_ENERGY", infoById.get().getReceipt().getResult().toString()); - Assert.assertEquals(1000000000, infoById.get().getFee()); - Assert.assertTrue(infoById.get().getResMessage().toStringUtf8() - .contains("Not enough energy for 'SWAP2' operation executing: curInvokeEnergyLimit")); + Assert.assertEquals(0, infoById.get().getResultValue()); + Assert.assertEquals("SUCESS", infoById.get().getResult().toString()); + int boolResult = ByteArray.toInt(infoById.get().getContractResult(0).toByteArray()); + Assert.assertFalse(Boolean.valueOf(String.valueOf(boolResult))); + Assert.assertTrue(maxFeeLimit > infoById.get().getFee()); // length:128 String argsStr2 = "\"0000000000000000000000000000000000000000000000000000000000000001" diff --git a/framework/src/test/java/stest/tron/wallet/onlinestress/TransactionCheck.java b/framework/src/test/java/stest/tron/wallet/onlinestress/TransactionCheck.java new file mode 100644 index 00000000000..c14e596e378 --- /dev/null +++ b/framework/src/test/java/stest/tron/wallet/onlinestress/TransactionCheck.java @@ -0,0 +1,52 @@ +package stest.tron.wallet.onlinestress; + +import com.google.protobuf.ByteString; +import org.testng.annotations.Test; +import org.tron.common.crypto.ECKey.ECDSASignature; +import org.tron.common.crypto.SignUtils; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.utils.ByteArray; +import stest.tron.wallet.common.client.WalletClient; +import stest.tron.wallet.common.client.utils.Sha256Hash; + +public class TransactionCheck { + + @Test + public void hexToTransaction() throws Exception { + String targetHex1 = ""; + String targetHex2 = ""; + String hex = targetHex1; + org.tron.protos.Protocol.Transaction transaction = org.tron.protos.Protocol.Transaction + .parseFrom(ByteArray.fromHexString(hex)); + getBase64FromByteString(transaction.getSignature(0)); + String base64 = getBase64FromByteString(transaction.getSignature(0)); + byte[] address = SignUtils + .signatureToAddress((Sha256Hash + .hash(CommonParameter.getInstance().isECKeyCryptoEngine(), + transaction.getRawData().toByteArray())), base64, + CommonParameter.getInstance().isECKeyCryptoEngine()); + String addressStr = WalletClient.encode58Check(address); + String data = String.valueOf(transaction.getRawData().getData().toStringUtf8()); + System.out.println(addressStr); + System.out.println(data); + } + + + /** + * constructor. + */ + public static String getBase64FromByteString(ByteString sign) { + byte[] r = sign.substring(0, 32).toByteArray(); + byte[] s = sign.substring(32, 64).toByteArray(); + byte v = sign.byteAt(64); + if (v < 27) { + v += 27; //revId -> v + } + ECDSASignature signature = ECDSASignature.fromComponents(r, s, v); + return signature.toBase64(); + } + + + + +} diff --git a/framework/src/test/resources/config-localtest.conf b/framework/src/test/resources/config-localtest.conf index 1dbc5d534c2..22a41d22564 100644 --- a/framework/src/test/resources/config-localtest.conf +++ b/framework/src/test/resources/config-localtest.conf @@ -157,6 +157,15 @@ node { # maxHeaderListSize = } + jsonrpc { + # httpFullNodeEnable = true + # httpFullNodePort = 8545 + # httpSolidityEnable = true + # httpSolidityPort = 8555 + # httpPBFTEnable = true + # httpPBFTPort = 8565 + } + } diff --git a/framework/src/test/resources/config-test-index.conf b/framework/src/test/resources/config-test-index.conf index 84f85d1c184..d2feabff04e 100644 --- a/framework/src/test/resources/config-test-index.conf +++ b/framework/src/test/resources/config-test-index.conf @@ -136,7 +136,12 @@ seed.node = { genesis.block = { # Reserve balance assets = [ - + { + accountName = "Blackhole" + accountType = "AssetIssue" + address = "27WtBq2KoSy5v8VnVZBZHHJcDuWNiSgjbE3" + balance = "-9223372036854775808" + } ] witnesses = [ diff --git a/framework/src/test/resources/soliditycode/Create2Test024.sol b/framework/src/test/resources/soliditycode/Create2Test024.sol index 3e55e1cf0fc..5d43c0f4ab2 100644 --- a/framework/src/test/resources/soliditycode/Create2Test024.sol +++ b/framework/src/test/resources/soliditycode/Create2Test024.sol @@ -31,7 +31,7 @@ contract Factory { assembly { addr1 := create2(0, add(code, 0x20), mload(code), salt) - if iszero(extcodesize(addr)) { + if iszero(extcodesize(addr1)) { revert(0, 0) } } diff --git a/framework/src/test/resources/soliditycode/EthGrammer.sol b/framework/src/test/resources/soliditycode/EthGrammer.sol new file mode 100644 index 00000000000..1be4d2d0881 --- /dev/null +++ b/framework/src/test/resources/soliditycode/EthGrammer.sol @@ -0,0 +1,191 @@ +contract C { + constructor() public payable{} + + function baseFee() external view returns (uint ret) { + assembly { + ret := basefee() + } + assert(block.basefee == ret); + } + + function baseFeeOnly() external view returns (uint ret) { + assembly { + ret := basefee() + } + } + + function gasPrice() external view returns (uint ret) { + assembly { + ret := basefee() + } + assert(tx.gasprice == ret); + } + + function gasPriceOnly() external view returns (uint) { + return tx.gasprice; + } + + function testCall(address payable caller, address payable transferTo) public { + (bool success, bytes memory data) = caller.call(abi.encodeWithSignature("transfer(address)",transferTo)); + require(success); + } + + function testDelegateCall(address payable caller, address payable transferTo) public { + (bool success, bytes memory data) = caller.delegatecall(abi.encodeWithSignature("transfer(address)",transferTo)); + require(success); + } + + uint sum = 0; + function transfer(address payable transerTo) public { + for (uint i = 0; i < type(uint256).max; i++) + sum = 0; + for (uint j = 0; j < type(uint8).max; j++) + sum += j; + transerTo.transfer(1); + } + + function testCallFunctionInContract(address payable transferTo) public { + this.transfer(transferTo); + } + + + function getRipemd160(string memory input) public returns(bytes32 output) { + bytes memory tem = bytes(input); + assembly { + if iszero(staticcall(not(0), 0x020003, add(tem, 0x20), mload(tem), output, 0x20)) { + revert(0, 0) + } + output := mload(add(output,0x0c)) + } + } + + function getRipemd160Str(string memory input) public view returns(bytes32 output) { + assembly { + if iszero(staticcall(not(0), 0x020003, add(input, 0x20), mload(input), output, 0x20)) { + revert(0, 0) + } + output := mload(add(output,0x0c)) + } + + } + + function F(uint32 rounds, bytes32[2] memory h, bytes32[4] memory m, bytes8[2] memory t, bool f) public view returns (bytes32[2] memory) { + bytes32[2] memory output; + + bytes memory args = abi.encodePacked(rounds, h[0], h[1], m[0], m[1], m[2], m[3], t[0], t[1], f); + + assembly { + if iszero(staticcall(not(0), 0x020009, add(args, 32), 0xd5, output, 0x40)) { + revert(0, 0) + } + } + + return output; + } + + function callF() public view returns (bytes32[2] memory) { + uint32 rounds = 12; + + bytes32[2] memory h; + h[0] = hex"48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5"; + h[1] = hex"d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b"; + + bytes32[4] memory m; + m[0] = hex"6162630000000000000000000000000000000000000000000000000000000000"; + m[1] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + m[2] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + m[3] = hex"0000000000000000000000000000000000000000000000000000000000000000"; + + bytes8[2] memory t; + t[0] = hex"03000000"; + t[1] = hex"00000000"; + + bool f = true; + + // Expected output: + // ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1 + // 7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923 + return F(rounds, h, m, t, f); + } + + +} + +contract D { + constructor() public payable{} + + function deploy(uint256 salt) public returns(address){ + address addr; + bytes memory code = type(C).creationCode; + assembly { + addr := create2(0, add(code, 0x20), mload(code), salt) + } + return addr; + } + + uint sum = 0; + function transfer(address payable transerTo) public { + for (uint i = 0; i < type(uint256).max; i++) + sum = 0; + for (uint j = 0; j < type(uint8).max; j++) + sum += j; + transerTo.transfer(1); + } + + function callCreate2(uint256 salt) public returns(address){ + address addr; + bytes memory code = type(C).creationCode; + assembly { + addr := create2(0, add(code, 0x20), mload(code), salt) + } + return addr; + } + + function fixCreate2StackDepth(uint salt) public { + if (isEmptyAddress(callCreate2(salt + 1))) { + revert(); + } + this.fixCreate2StackDepth(salt + 1); + } + + function callCreate() public returns(address){ + address addr; + bytes memory code = type(C).creationCode; + assembly { + addr := create(0, add(code, 0x20), mload(code)) + } + return addr; + } + + function fixCreateStackDepth() public { + if (isEmptyAddress(callCreate())) { + revert(); + } + this.fixCreateStackDepth(); + } + + bool constant bool1 = true; + function isEmptyAddress(address add2) public returns(bool result){ + + assembly { + if iszero(extcodesize(add2)) { + result := bool1 + } + } + } + + function deployef(bytes memory code) public payable{ + address addr; + assembly { + addr := create(0, add(code, 0x20), mload(code)) + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + } +} + + + + + diff --git a/framework/src/test/resources/soliditycode/EthGrammer02.sol b/framework/src/test/resources/soliditycode/EthGrammer02.sol new file mode 100644 index 00000000000..d032b531fa6 --- /dev/null +++ b/framework/src/test/resources/soliditycode/EthGrammer02.sol @@ -0,0 +1,45 @@ +contract D { + constructor() public payable{} + + event createAddress(address addr); + function createDeployEf(bytes memory code) public returns(address addr){ + address addr; + assembly { + addr := create(0, add(code, 0x20), mload(code)) + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + return addr; + } + + function create2DeployEf(bytes memory code,uint256 salt) public returns(address addr){ + address addr; + assembly { + addr := create2(0, add(code, 0x20), mload(code), salt) + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + emit createAddress(addr); + return addr; + } + + function setSlot(bytes memory slot,uint256 value) external { +// uint256 value = 123; + assembly { + sstore(slot, value) + } + } + + function getSlot(bytes memory slot) view external returns(uint res) { + assembly { + res := sload(slot) + } + } +} + + + + + diff --git a/framework/src/test/resources/soliditycode/NewFeature086.sol b/framework/src/test/resources/soliditycode/NewFeature086.sol new file mode 100644 index 00000000000..f898fadde3e --- /dev/null +++ b/framework/src/test/resources/soliditycode/NewFeature086.sol @@ -0,0 +1,121 @@ +contract C { + constructor() public payable{} + + function catchAssertFail() external view returns(uint) { + try this.assertFail() { + return 0; + } catch Panic(uint _code) { + if (_code == 0x01) { + return 0x01; + } + return 2; + } + return 3; + } + function assertFail() external pure { + assert(0 == 1); + } + function catchUnderFlow() external view returns(uint) { + try this.underflow() { + return 44; + } catch Panic(uint _code) { + if (_code == 0x11) { + return 0x11; + } + return 22; + } + return 33; + } + function underflow() public pure { + uint x = 0; + x--; + } + + function catchDivideZero() external view returns(uint) { + try this.divideZero() { + return 14; + } catch Panic(uint _code) { + if (_code == 0x12) { + return 0x12; + } + return 11; + } + return 13; + } + function divideZero() public pure { + uint8 x = 0; + uint8 y = 1; + uint8 z = y/x; + } + + function convertUint2Int() public pure { + uint16 a = 1; +// int32 b = int32(a); +// int32 b = a; + } + + function getAddressCodeLength() public returns(uint) { + return address(this).code.length; + } + + function keccak256Bug(string memory s) public returns (bool ret) { + assembly { + let a := keccak256(s, 32) + let b := keccak256(s, 8) + ret := eq(a, b) + } + } + + error InsufficientBalance(uint256 available, uint256 required); + mapping(address => uint) balance; + function transfer(address to, uint256 amount) public { + if (amount > balance[msg.sender]) + revert InsufficientBalance({available: balance[msg.sender], required: amount}); + balance[msg.sender] -= amount; + balance[to] += amount; + } + + error Unauthorized(); + function withdraw() public { + address payable owner; + if (msg.sender != owner) + revert Unauthorized(); + owner.transfer(address(this).balance); + } + + bytes s = "Storage"; + function bytesConcat(bytes calldata c, string memory m, bytes16 b) public view returns(uint256) { + bytes memory a = bytes.concat(s, c, c[:2], "Literal", bytes(m), b); + assert((s.length + c.length + 2 + 7 + bytes(m).length + 16) == a.length); + return a.length; + } + + bytes p = "hihello"; + function bytesConcatWithEmptyStr() public view { + bytes memory a = bytes.concat("hi", "", "hello"); + assert(p.length == a.length); + } + + event ssoo(uint256); + function testEmitEvent() public payable { + emit ssoo(6); + } + + function bytes2BytesN(bytes memory c) public returns (bytes8) { + // If c is longer than 8 bytes, truncation happens + return bytes3(c); + } + + function getContractAddress() public view returns (address a1, address a2) { + a1 = address(this); + this.getContractAddress.address; + [this.getContractAddress.address][0]; + a2 = [this.getContractAddress.address][0]; + } + +} + + + + + diff --git a/framework/src/test/resources/soliditycode/abstractContractWithMapParamsConstructor.sol b/framework/src/test/resources/soliditycode/abstractContractWithMapParamsConstructor.sol new file mode 100644 index 00000000000..380c57180b8 --- /dev/null +++ b/framework/src/test/resources/soliditycode/abstractContractWithMapParamsConstructor.sol @@ -0,0 +1,23 @@ +abstract contract Feline { + + constructor (mapping (uint => uint) storage m) { + m[5] = 20; + } + + function utterance() public virtual returns (bytes32); + + function getContractName() public returns (string memory){ + return "Feline"; + } +} + + +contract Cat is Feline { + mapping (uint => uint) public m; + + constructor() Feline(m) { + } + function utterance() public override returns (bytes32) { return "miaow"; } + function getMapValue() public returns (uint) { return m[5]; } + +} \ No newline at end of file diff --git a/framework/src/test/resources/soliditycode/contractTrcToken001.sol b/framework/src/test/resources/soliditycode/contractTrcToken001.sol index ea28f4a62b6..4bd83e30229 100644 --- a/framework/src/test/resources/soliditycode/contractTrcToken001.sol +++ b/framework/src/test/resources/soliditycode/contractTrcToken001.sol @@ -1,6 +1,9 @@ contract tokenTest{ + + uint pos0; + mapping(address => uint) pos1; trcToken idCon = 0; uint256 tokenValueCon=0; uint256 callValueCon = 0; @@ -22,9 +25,17 @@ idCon = msg.tokenid; tokenValueCon = msg.tokenvalue; callValueCon = msg.value; + Storage(); } function getResultInCon() public payable returns(trcToken, uint256, uint256) { return (idCon, tokenValueCon, callValueCon); } + + + function Storage() public { + pos0 = 1234; + pos1[msg.sender] = 5678; + } + } \ No newline at end of file diff --git a/framework/src/test/resources/soliditycode/function_type_array_to_storage.sol b/framework/src/test/resources/soliditycode/function_type_array_to_storage.sol new file mode 100644 index 00000000000..a2093023d6a --- /dev/null +++ b/framework/src/test/resources/soliditycode/function_type_array_to_storage.sol @@ -0,0 +1,45 @@ +contract C { + constructor() public payable{} + function () external returns(uint)[1] externalDefaultArray; + function () external view returns(uint)[1] externalViewArray; + function () external pure returns(uint)[1] externalPureArray; + + function () internal returns(uint)[1] internalDefaultArray; + function () internal view returns(uint)[1] internalViewArray; + function () internal pure returns(uint)[1] internalPureArray; + + function externalDefault() external returns(uint) { return 11; } + function externalView() external view returns(uint) { return 12; } + function externalPure() external pure returns(uint) { return 13; } + + function internalDefault() internal returns(uint) { return 21; } + function internalView() internal view returns(uint) { return 22; } + function internalPure() internal pure returns(uint) { return 23; } + + function testViewToDefault() public returns (uint, uint) { + externalDefaultArray = [this.externalView]; + internalDefaultArray = [internalView]; + + return (externalDefaultArray[0](), internalDefaultArray[0]()); + } + + function testPureToDefault() public returns (uint, uint) { + externalDefaultArray = [this.externalPure]; + internalDefaultArray = [internalPure]; + + return (externalDefaultArray[0](), internalDefaultArray[0]()); + } + + function testPureToView() public returns (uint, uint) { + externalViewArray = [this.externalPure]; + internalViewArray = [internalPure]; + + return (externalViewArray[0](), internalViewArray[0]()); + } +} +// ==== +// compileViaYul: also +// ---- +// testViewToDefault() -> 12, 22 +// testPureToDefault() -> 13, 23 +// testPureToView() -> 13, 23 diff --git a/framework/src/test/resources/soliditycode/super_skip_unimplemented_in_abstract_contract.sol b/framework/src/test/resources/soliditycode/super_skip_unimplemented_in_abstract_contract.sol new file mode 100644 index 00000000000..82dc5d513f7 --- /dev/null +++ b/framework/src/test/resources/soliditycode/super_skip_unimplemented_in_abstract_contract.sol @@ -0,0 +1,22 @@ +contract A { + function f() public virtual returns (uint) { + return 42; + } +} + +abstract contract I { + function f() external virtual returns (uint); +} + +contract B is A, I { + function f() override(A, I) public returns (uint) { + // I.f() is before A.f() in the C3 linearized order + // but it has no implementation. + return super.f(); + } +} +// ==== +// compileToEwasm: also +// compileViaYul: also +// ---- +// f() -> 42 diff --git a/framework/src/test/resources/testng.conf b/framework/src/test/resources/testng.conf index addfb1b71d2..a45891de8ca 100644 --- a/framework/src/test/resources/testng.conf +++ b/framework/src/test/resources/testng.conf @@ -38,8 +38,8 @@ solidityNode = { "127.0.0.1:50071", #New beat 1 - #"39.106.145.222:50151", - #"39.106.145.222:50061", + "39.106.145.222:50061", + "39.106.145.222:50061", #"39.106.145.222:50071", #New beat 2 @@ -65,8 +65,8 @@ httpnode = { #New beta 2 - "101.200.46.37:50093", - "39.106.145.222:50093", + "101.200.46.37:50091", + "39.106.145.222:50091", "101.200.46.37:50192", "101.200.46.37:50094", "101.200.46.37:50082", @@ -81,6 +81,20 @@ eventnode = { ] } +jsonRpcNode = { + ip.list = [ + #"101.200.46.37:50545", + "127.0.0.1:50545", + ] +} + +ethHttpsNode = { + host.list = [ + "mainnet.infura.io", + #"47.95.206.44:50545", + ] +} + foundationAccount = { key1 = FC8BF0238748587B9617EB6D15D47A66C0E07C1A1959033CF249C6532DC29FE6 @@ -154,6 +168,7 @@ defaultParameter = { zenTokenFee = 10000000 zenTokenWhenCreateNewAddress = 1000000 zenTrc20TokenOwnerKey = ede941a01eb8234866f60c7e8e95db4614bb0d05298d82bae0abea81f1861046 + jsonRpcOwnerKey = dbc78781ad27f3751358333412d5edc85b13e5eee129a1a77f7232baadafae0e blackHoleAddress = THmtHi1Rzq4gSKYGEKv1DPkV7au6xU1AUB } diff --git a/plugins/src/main/java/org/tron/plugins/ArchiveManifest.java b/plugins/src/main/java/org/tron/plugins/ArchiveManifest.java index cc4a256ee56..caf2cc0dac6 100644 --- a/plugins/src/main/java/org/tron/plugins/ArchiveManifest.java +++ b/plugins/src/main/java/org/tron/plugins/ArchiveManifest.java @@ -56,15 +56,6 @@ public class ArchiveManifest implements Callable { private static final int CPUS = Runtime.getRuntime().availableProcessors(); - private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor( - CPUS, 16 * CPUS, 1, TimeUnit.MINUTES, - new ArrayBlockingQueue<>(CPUS, true), Executors.defaultThreadFactory(), - new ThreadPoolExecutor.CallerRunsPolicy()); - - static { - EXECUTOR.allowCoreThreadTimeOut(true); - } - public ArchiveManifest(String src, String name, int maxManifestSize, int maxBatchSize) { this.name = name; this.srcDbPath = Paths.get(src, name); @@ -96,6 +87,13 @@ public static org.iq80.leveldb.Options newDefaultLevelDbOptions() { } public static void main(String[] args) { + int code = run(args); + logger.info("exit code {}.", code); + System.out.printf("exit code %d.\n", code); + System.exit(code); + } + + public static int run(String[] args) { Args parameters = new Args(); JCommander jc = JCommander.newBuilder() .addObject(parameters) @@ -103,13 +101,13 @@ public static void main(String[] args) { jc.parse(args); if (parameters.help) { jc.usage(); - return; + return 0; } File dbDirectory = new File(parameters.databaseDirectory); if (!dbDirectory.exists()) { logger.info("Directory {} does not exist.", parameters.databaseDirectory); - return; + return 404; } List files = Arrays.stream(Objects.requireNonNull(dbDirectory.listFiles())) @@ -118,12 +116,19 @@ public static void main(String[] args) { if (files.isEmpty()) { logger.info("Directory {} does not contain any database.", parameters.databaseDirectory); - return; + return 0; } final long time = System.currentTimeMillis(); final List> res = new ArrayList<>(); + final ThreadPoolExecutor executor = new ThreadPoolExecutor( + CPUS, 16 * CPUS, 1, TimeUnit.MINUTES, + new ArrayBlockingQueue<>(CPUS, true), Executors.defaultThreadFactory(), + new ThreadPoolExecutor.CallerRunsPolicy()); + + executor.allowCoreThreadTimeOut(true); + files.forEach(f -> res.add( - EXECUTOR.submit(new ArchiveManifest(parameters.databaseDirectory, f.getName(), + executor.submit(new ArchiveManifest(parameters.databaseDirectory, f.getName(), parameters.maxManifestSize, parameters.maxBatchSize)))); int fails = res.size(); @@ -140,7 +145,7 @@ public static void main(String[] args) { } } - EXECUTOR.shutdown(); + executor.shutdown(); logger.info("DatabaseDirectory:{}, maxManifestSize:{}, maxBatchSize:{}," + "database reopen use {} seconds total.", parameters.databaseDirectory, parameters.maxManifestSize, parameters.maxBatchSize, @@ -148,7 +153,7 @@ public static void main(String[] args) { if (fails > 0) { logger.error("Failed!!!!!!!!!!!!!!!!!!!!!!!! size:{}", fails); } - System.exit(fails); + return fails; } public void open() throws IOException { diff --git a/plugins/src/test/java/org/tron/plugins/ArchiveManifestTest.java b/plugins/src/test/java/org/tron/plugins/ArchiveManifestTest.java index 53a57524579..4fd9e537d05 100644 --- a/plugins/src/test/java/org/tron/plugins/ArchiveManifestTest.java +++ b/plugins/src/test/java/org/tron/plugins/ArchiveManifestTest.java @@ -16,8 +16,8 @@ import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.iq80.leveldb.DB; import org.junit.AfterClass; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -58,27 +58,27 @@ public static void destroy() { } @Test - public void testMain() { + public void testRun() { String[] args = new String[] { "-d", OUTPUT_DIRECTORY }; - ArchiveManifest.main(args); + Assert.assertEquals(0, ArchiveManifest.run(args)); } @Test public void testHelp() { String[] args = new String[] {"-h"}; - ArchiveManifest.main(args); + Assert.assertEquals(0, ArchiveManifest.run(args)); } @Test public void testMaxManifest() { String[] args = new String[] {"-d", OUTPUT_DIRECTORY, "-m", "128"}; - ArchiveManifest.main(args); + Assert.assertEquals(0, ArchiveManifest.run(args)); } @Test public void testNotExist() { String[] args = new String[] {"-d", OUTPUT_DIRECTORY + File.separator + UUID.randomUUID()}; - ArchiveManifest.main(args); + Assert.assertEquals(404, ArchiveManifest.run(args)); } @Test @@ -87,7 +87,7 @@ public void testEmpty() { file.mkdirs(); file.deleteOnExit(); String[] args = new String[] {"-d", file.toString()}; - ArchiveManifest.main(args); + Assert.assertEquals(0, ArchiveManifest.run(args)); } private static void writeProperty(String filename, String key, String value) throws IOException { diff --git a/protocol/src/main/protos/api/api.proto b/protocol/src/main/protos/api/api.proto index 3766873318f..5f697026c10 100644 --- a/protocol/src/main/protos/api/api.proto +++ b/protocol/src/main/protos/api/api.proto @@ -1222,6 +1222,8 @@ message TransactionExtention { repeated bytes constant_result = 3; Return result = 4; int64 energy_used = 5; + repeated TransactionInfo.Log logs = 6; + repeated InternalTransaction internal_transactions = 7; } message BlockExtention { diff --git a/protocol/src/main/protos/core/Tron.proto b/protocol/src/main/protos/core/Tron.proto index 23bd8840711..a4409923086 100644 --- a/protocol/src/main/protos/core/Tron.proto +++ b/protocol/src/main/protos/core/Tron.proto @@ -405,6 +405,7 @@ message Transaction { JVM_STACK_OVER_FLOW = 12; UNKNOWN = 13; TRANSFER_FAILED = 14; + INVALID_CODE = 15; } int64 fee = 1; code ret = 2; diff --git a/protocol/src/main/protos/core/contract/smart_contract.proto b/protocol/src/main/protos/core/contract/smart_contract.proto index 9a173656481..ffbf399c38e 100644 --- a/protocol/src/main/protos/core/contract/smart_contract.proto +++ b/protocol/src/main/protos/core/contract/smart_contract.proto @@ -55,6 +55,7 @@ message SmartContract { int64 origin_energy_limit = 8; bytes code_hash = 9; bytes trx_hash = 10; + int32 version = 11; } message CreateSmartContract { diff --git a/shell.md b/shell.md new file mode 100644 index 00000000000..df7d01e7cd9 --- /dev/null +++ b/shell.md @@ -0,0 +1,229 @@ +# Quick Start Scripting Tool + +# Introduction + +Using the `start.sh` script, you can quickly and easily run and build java-tron. + +If you already downloaded the `FullNode.jar`, you can use `start.sh` to run it, or if you have not downloaded java-tron source code or jar packages, you can use `start.sh` to download the source code, compile, run or get the latest release version in the form of a `jar package ` and run. + +The script is available in the java-tron project at [github](https://github.com/tronprotocol/java-tron), or if you need a separate script: [start.sh](https://github.com/tronprotocol/java-tron/blob/develop/start.sh) + +*** + +# Usage + +## Examples + +* Start the `FullNode.jar` (`start.sh`, `config.conf` and `FullNode.jar` in the same directory.) + + ``` + sh start.sh --run + ``` + + Start the servive with options. + + ``` + sh start.sh --run -j /data/FullNode.jar -c /data/config.conf -d /data/output-directory + ``` + +* Stop the `FullNode.jar` + + ``` + sh start.sh --stop + ``` + +* Get the latest version of `FullNode.jar` and start it + + ``` + sh start.sh --release --run + ``` + +* Clone the source code, compile `java-tron`, and generate `FullNode.jar` and start it + + ``` + sh start.sh -cb --run + ``` + + + +## Options + +### Service operation + +* `--run` + + start the service + +* `--stop` + + stop the service + +* `-c` + + Specify the configuration file, by default it will load the `config.conf` in the same directory as `FullNode.jar` + +* `-d` + + Specify the database storage path, The default path is the same directory where `FullNode.jar` is located. + +* `-j` + + Specify the jar package, default value is the `FullNode.jar` in the current path. + +* `-mem` + + Specify the maximum memory of the `FullNode.jar` service in`MB`, jvm's startup maximum memory will be adjusted according to this parameter. + +### build project + +* `-cb` + + Clone the latest source code and compile. + +* `--release` + + Get the latest released version of the `jar` package from github. + + +### rebuild the manifest + +* `-d` + + specify the `output-directory` db directory + +* `-m` + + specify the minimum required manifest file size ,unit:M,default:0 + +* `-b` + + specify the batch manifest size,default:80000 + +* `-dr` or `--disable-rewrite-manifest` + disable rewrite manifest + +*** + +## How to use + +* Local mode + + Start the service using the local Jar package + +* Online mode + + Get the latest code or latest release from github and start the service + +### 1.local mode + +Format: + +``` +sh start.sh [-j ] [-d ] [-c ] [[--run] | [--stop]] +``` + +**start service** + +``` +sh start.sh --run +``` + +**stop service** + +``` +sh start.sh --stop +``` + +### 2.online mode + +* Get the latest release + +* Clone the source code and build + +**Get the latest release** + +Format: + +``` +sh start.sh <[--release | -cb]> <--run> [-m ] | [-b ] | [-d | [-dr | --disable-rewrite-manifes]] +``` + +Get the latest released version. + + +``` +sh start.sh --release --run +``` + +Following file structure will be generated after executed the above command and the `FullNode.jar` will be started. + +``` +├── ... +├── FullNode/ + ├── config.conf + ├── FullNode.jar + ├── start.sh +``` + +**Clone the source code and build** + +Get the latest code from master branch of https://github.com/tronprotocol/java-tron and compile. + +After using this command, the "FullNode" directory will be created, the compiled file `FullNode.jar` and the configuration file will be copied to this directory + +demo: + +``` +sh start.sh -cb --run +``` + +Following file structure will be created: + +``` +├── ... +├── java-tron + ├── actuator/ + ├── chainbase/ + ├── common/ + ├── config/ + ├── consensus/ + ├── crypto/ + ├── docker/ + ├── docs/ + ├── example/ + ├── framework/ + ├── gradle/ + ├── plugins/ + ├── protocol/ + ├── config.conf + ├── FullNode.jar + ├── start.sh + ├── README.md + ├── ... +``` + +``` +├── java-tron/ +├── FullNode/ + |── config.conf + ├── FullNode.jar + ├── start.sh +``` + +### 3. rebuild manifest tool + +This tool provides the ability to reformat the manifest based on current database, Enabled by default. + +1.Local mode: + +``` +sh start.sh --run -d /tmp/db/database -m 128 -b 64000 +``` + +2.Online mode + +``` +sh start.sh --release --run -d /tmp/db/database -m 128 -b 64000 +``` + +For more design details, please refer to: [TIP298](https://github.com/tronprotocol/tips/issues/298) | [Leveldb Startup Optimization Plugins](https://github.com/tronprotocol/documentation-en/blob/master/docs/developers/archive-manifest.md) \ No newline at end of file diff --git a/start.sh b/start.sh index 849d18450fc..77b4cadccde 100644 --- a/start.sh +++ b/start.sh @@ -1,46 +1,472 @@ #!/bin/bash -APP=$1 -APP=${APP:-"FullNode"} -START_OPT=`echo ${@:2}` -JAR_NAME="$APP.jar" +# build FullNode config +FULL_NODE_DIR="FullNode" +FULL_NODE_CONFIG="main_net_config.conf" +DEFAULT_FULL_NODE_CONFIG='config.conf' +#FULL_NODE_SHELL="start.sh" +JAR_NAME="FullNode.jar" +FULL_START_OPT='' +GITHUB_BRANCH='master' + +# shell option +ALL_OPT_LENGTH=$# + +# start service option MAX_STOP_TIME=60 +# modify this option to allow the minimum memory to be started, unit MB +ALLOW_MIN_MEMORY=8192 +# JVM option +MAX_DIRECT_MEMORY=1g +JVM_MS=4g +JVM_MX=4g + +SPECIFY_MEMORY=0 +RUN=false +UPGRADE=false + +# rebuild manifest +REBUILD_MANIFEST=true +REBUILD_DIR="$PWD/output-directory/database" +REBUILD_MANIFEST_SIZE=0 +REBUILD_BATCH_SIZE=80000 + +# download and upgrade +DOWNLOAD=false +RELEASE_URL='https://github.com/tronprotocol/java-tron/releases' +QUICK_START=false +CLONE_BUILD=false + +getLatestReleaseVersion() { + full_node_version=`git ls-remote --tags git@github.com:tronprotocol/java-tron.git |grep GreatVoyage- | awk -F '/' 'END{print $3}'` + if [[ -n $full_node_version ]]; then + echo $full_node_version + else + echo '' + fi +} + +checkVersion() { + github_release_version=$(`echo getLatestReleaseVersion`) + if [[ -n $github_release_version ]]; then + echo "info: github latest version: $github_release_version" + echo $github_release_version + else + echo 'info: not getting the latest version' + exit + fi +} + +upgrade() { + latest_version=$(`echo getLatestReleaseVersion`) + echo "info: latest version: $latest_version" + if [[ -n $latest_version ]]; then + old_jar="$PWD/$JAR_NAME" + if [[ -f $old_jar ]]; then + echo "info: backup $old_jar" + mv $PWD/$JAR_NAME $PWD/$JAR_NAME'_bak' + fi + download $RELEASE_URL/download/$latest_version/$JAR_NAME $JAR_NAME + if [[ $? == 0 ]]; then + echo "info: download version $latest_version success" + fi + else + echo 'info: nothing to upgrade' + fi +} + +download() { + local url=$1 + local file_name=$2 + if type wget >/dev/null 2>&1; then + wget --no-check-certificate -q $url + elif type curl >/dev/null 2>&1; then + echo "curl -OLJ $url" + curl -OLJ $url + else + echo 'info: no exists wget or curl, make sure the system can use the "wget" or "curl" command' + fi +} + +mkdirFullNode() { + if [ ! -d $FULL_NODE_DIR ]; then + echo "info: create $FULL_NODE_DIR" + mkdir $FULL_NODE_DIR + $(cp $0 $FULL_NODE_DIR) + cd $FULL_NODE_DIR + elif [ -d $FULL_NODE_DIR ]; then + cd $FULL_NODE_DIR + fi +} + +quickStart() { + full_node_version=$(`echo getLatestReleaseVersion`) + if [[ -n $full_node_version ]]; then + mkdirFullNode + echo "info: check latest version: $full_node_version" + echo 'info: download config' + download https://raw.githubusercontent.com/tronprotocol/tron-deployment/$GITHUB_BRANCH/$FULL_NODE_CONFIG $FULL_NODE_CONFIG + mv $FULL_NODE_CONFIG 'config.conf' + + echo "info: download $full_node_version" + download $RELEASE_URL/download/$full_node_version/$JAR_NAME $JAR_NAME + checkSign + else + echo 'info: not getting the latest version' + exit + fi +} + +cloneCode() { + if type git >/dev/null 2>&1; then + git_clone=$(git clone -b $GITHUB_BRANCH git@github.com:tronprotocol/java-tron.git) + if [[ git_clone == 0 ]]; then + echo 'info: git clone java-tron success' + fi + else + echo 'info: no exists git, make sure the system can use the "git" command' + fi +} + +cloneBuild() { + local currentPwd=$PWD + echo 'info: clone java-tron' + cloneCode -checkpid() { - pid=`ps -ef | grep $JAR_NAME |grep -v grep | awk '{print $2}'` - return $pid + echo 'info: build java-tron' + cd java-tron + sh gradlew clean build -x test + if [[ $? == 0 ]];then + cd $currentPwd + mkdirFullNode + cp '../java-tron/build/libs/FullNode.jar' $PWD + cp '../java-tron/framework/src/main/resources/config.conf' $PWD + else + exit + fi +} + +checkPid() { + if [[ $JAR_NAME =~ '/' ]]; then + JAR_NAME=$(echo $JAR_NAME |awk -F '/' '{print $NF}') + fi + pid=$(ps -ef | grep -v start | grep $JAR_NAME | grep -v grep | awk '{print $2}') + return $pid } stopService() { count=1 while [ $count -le $MAX_STOP_TIME ]; do - checkpid + checkPid if [ $pid ]; then - kill -15 $pid - sleep 1 + kill -15 $pid + sleep 1 else - echo "java-tron stop" - return + echo "info: java-tron stop" + return fi - count=$[$count+1] + count=$(($count + 1)) if [ $count -eq $MAX_STOP_TIME ]; then kill -9 $pid sleep 1 fi done + sleep 5 +} + +checkAllowMemory() { + os=`uname` + totalMemory=$(`echo getTotalMemory`) + total=`expr $totalMemory / 1024` + if [[ $os == 'Darwin' ]]; then + return + fi + + if [[ $total -lt $ALLOW_MIN_MEMORY ]]; then + echo "warn: the memory $total MB cannot be smaller than the minimum memory $ALLOW_MIN_MEMORY MB" + exit + elif [[ $SPECIFY_MEMORY -gt 0 ]] && + [[ $SPECIFY_MEMORY -lt $ALLOW_MIN_MEMORY ]]; then + echo "warn: the specified memory $SPECIFY_MEMORY MB cannot be smaller than the minimum memory $ALLOW_MIN_MEMORY MB" + echo 'warn: start abort' + exit + fi +} + +setTCMalloc() { + os=`uname` + if [[ $os == 'Linux' ]] || [[ $os == 'linux' ]] ; then + lib_tc_malloc="/usr/lib64/libtcmalloc.so" + if [[ -f $lib_tc_malloc ]]; then + export LD_PRELOAD="$lib_tc_malloc" + export TCMALLOC_RELEASE_RATE=10 + else + echo 'info: recommended for linux systems using tcmalloc as the default memory management tool' + fi + fi +} + +getTotalMemory() { + os=`uname` + if [[ $os == 'Linux' ]] || [[ $os == 'linux' ]] ; then + total=$(cat /proc/meminfo | grep MemTotal | awk -F ' ' '{print $2}') + echo $total + return + elif [[ $os == 'Darwin' ]]; then + total=$(sysctl -a | grep mem |grep hw.memsize |awk -F ' ' '{print $2}') + echo `expr $total / 1024` + fi +} + +setJVMMemory() { + os=`uname` + if [[ $os == 'Linux' ]] || [[ $os == 'linux' ]] ; then + if [[ $SPECIFY_MEMORY >0 ]]; then + max_direct=$(echo "$SPECIFY_MEMORY/1024*0.1" | bc | awk -F. '{print $1"g"}') + if [[ "$max_direct" != "g" ]]; then + MAX_DIRECT_MEMORY=$max_direct + fi + JVM_MX=$(echo "$SPECIFY_MEMORY/1024*0.6" | bc | awk -F. '{print $1"g"}') + JVM_MS=$JVM_MX + else + total=$(`echo getTotalMemory`) + MAX_DIRECT_MEMORY=$(echo "$total/1024/1024*0.1" | bc | awk -F. '{print $1"g"}') + JVM_MX=$(echo "$total/1024/1024*0.6" | bc | awk -F. '{print $1"g"}') + JVM_MS=$JVM_MX + fi + + elif [[ $os == 'Darwin' ]]; then + MAX_DIRECT_MEMORY='1g' + fi } startService() { - echo `date` >> start.log - total=`cat /proc/meminfo |grep MemTotal |awk -F ' ' '{print $2}'` - xmx=`echo "$total/1024/1024*0.8" | bc |awk -F. '{print $1"g"}'` - logtime=`date +%Y-%m-%d_%H-%M-%S` - nohup java -Xmx$xmx -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -Xloggc:./gc.log\ - -XX:+PrintGCDateStamps -XX:+CMSParallelRemarkEnabled -XX:ReservedCodeCacheSize=256m\ - -XX:+CMSScavengeBeforeRemark -jar $JAR_NAME $START_OPT -c config.conf >> start.log 2>&1 & + echo $(date) >>start.log + if [[ ! $JAR_NAME =~ '-c' ]]; then + FULL_START_OPT="$FULL_START_OPT -c $DEFAULT_FULL_NODE_CONFIG" + fi + + if [[ ! -f $JAR_NAME ]]; then + echo "warn: jar file $JAR_NAME not exist" + exit + fi + + nohup java -Xms$JVM_MS -Xmx$JVM_MX -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -Xloggc:./gc.log \ + -XX:+PrintGCDateStamps -XX:+CMSParallelRemarkEnabled -XX:ReservedCodeCacheSize=256m -XX:+UseCodeCacheFlushing \ + -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \ + -XX:MaxDirectMemorySize=$MAX_DIRECT_MEMORY -XX:+HeapDumpOnOutOfMemoryError \ + -XX:NewRatio=2 -jar \ + $JAR_NAME $FULL_START_OPT >>start.log 2>&1 & + checkPid + echo "info: start java-tron with pid $pid on $HOSTNAME" + echo "info: if you need to stop the service, execute: sh start.sh --stop" +} - pid=`ps -ef |grep $JAR_NAME |grep -v grep |awk '{print $2}'` - echo "start java-tron with pid $pid on $HOSTNAME" +rebuildManifest() { + if [[ $REBUILD_MANIFEST = false ]]; then + echo 'info: disable rebuild manifest!' + return + fi + + if [[ ! -d $REBUILD_DIR ]]; then + echo "info: database not exists, skip rebuild manifest" + return + fi + + ARCHIVE_JAR='ArchiveManifest.jar' + if [[ -f $ARCHIVE_JAR ]]; then + echo 'info: execute rebuild manifest.' + java -jar $ARCHIVE_JAR -d $REBUILD_DIR -m $REBUILD_MANIFEST_SIZE -b $REBUILD_BATCH_SIZE + else + echo 'info: download the rebuild manifest plugin from the github' + download $RELEASE_URL/download/GreatVoyage-v4.3.0/$ARCHIVE_JAR $ARCHIVE_JAR + if [[ $download == 0 ]]; then + echo 'info: download success, rebuild manifest' + java -jar $ARCHIVE_JAR $REBUILD_DIR -m $REBUILD_MANIFEST_SIZE -b $REBUILD_BATCH_SIZE + fi + fi + if [[ $? == 0 ]]; then + echo 'info: rebuild manifest success' + else + echo 'info: rebuild manifest fail, log in logs/archive.log' + fi } -stopService -startService +checkSign() { + echo 'info: verify signature' + local latest_version=$(`echo getLatestReleaseVersion`) + download $RELEASE_URL/download/$latest_version/sha256sum.txt sha256sum.txt + fullNodeSha256=$(cat sha256sum.txt|grep 'FullNode'| awk -F ' ' '{print $1}') + + os=`uname` + if [[ $os == 'Linux' ]] || [[ $os == 'linux' ]] ; then + releaseFullNodeSha256=$(sha256sum FullNode.jar| grep FullNode | awk -F ' ' '{print $1}') + elif [[ $os == 'Darwin' ]]; then + releaseFullNodeSha256=$(shasum -a 256 FullNode.jar| grep FullNode | awk -F ' ' '{print $1}') + cat $releaseFullNodeSha256 | awk -F ' ' '{print $0}' + fi + + echo "info: release sha256sum sign: $releaseFullNodeSha256" + echo "info: FullNode.jar sha256sum sign: $fullNodeSha256" + + if [[ "$fullNodeSha256" == "$releaseFullNodeSha256" ]]; then + echo 'info: sha256 signatures pass' + else + echo 'info: sha256 signature exception!!!' + echo 'info: please compile from the code or download the latest version from https://github.com/tronprotocol/java-tron' + fi +} + +restart() { + stopService + checkAllowMemory + rebuildManifest + setTCMalloc + setJVMMemory + startService +} + +while [ -n "$1" ]; do + case "$1" in + -c) + DEFAULT_FULL_NODE_CONFIG=$2 + FULL_START_OPT="$FULL_START_OPT $1 $2" + shift 2 + ;; + -d) + REBUILD_DIR=$2/database + FULL_START_OPT="$FULL_START_OPT $1 $2" + shift 2 + ;; + -j) + JAR_NAME=$2 + shift 2 + ;; + -m) + REBUILD_MANIFEST_SIZE=$2 + shift 2 + ;; + -n) + JAR_NAME=$2 + shift 2 + ;; + -b) + REBUILD_BATCH_SIZE=$2 + shift 2 + ;; + -cb) + CLONE_BUILD=true + shift 1 + ;; + --download) + DOWNLOAD=true + shift 1 + ;; + --deploy) + QUICK_START=true + shift 1 + ;; + --release) + QUICK_START=true + shift 1 + ;; + --clone) + cloneCode + exit + ;; + -mem) + SPECIFY_MEMORY=$2 + shift 2 + ;; + --disable-rewrite-manifes) + REBUILD_MANIFEST=false + shift 1 + ;; + -dr) + REBUILD_MANIFEST=false + shift 1 + ;; + --upgrade) + UPGRADE=true + shift 1 + ;; + --run) + if [[ $ALL_OPT_LENGTH -eq 1 ]]; then + restart + exit + fi + RUN=true + shift 1 + ;; + --stop) + stopService + exit + ;; + FullNode) + RUN=true + shift 1 + ;; + FullNode.jar) + RUN=true + shift 1 + ;; + *.jar) + RUN=true + shift 1 + ;; + *) + if [[ $ALL_OPT_LENGTH -eq 1 ]]; then + if [[ ! "$1" =~ "-" ]] && [[ ! "$1" =~ "--" ]]; then + if [[ $1 =~ '.jar' ]]; then + JAR_NAME=$1 + else + JAR_NAME="$1.jar" + fi + restart + exit + fi + fi + echo "warn: option $1 does not exist" + exit + ;; + esac +done + +if [[ $CLONE_BUILD == true ]];then + cloneBuild +fi + +if [[ $QUICK_START == true ]]; then + quickStart + if [[ $? == 0 ]] ; then + if [[ $RUN == true ]]; then + cd $FULL_NODE_DIR + FULL_START_OPT='' + restart + fi + fi + exit +fi + +if [[ $UPGRADE == true ]]; then + upgrade +fi + +if [[ $DOWNLOAD == true ]]; then + latest=$(`echo getLatestReleaseVersion`) + if [[ -n $latest ]]; then + download $RELEASE_URL/download/$latest/$JAR_NAME $latest + exit + else + echo 'info: not getting the latest version' + fi +fi + +if [[ $ALL_OPT_LENGTH -eq 0 ]]; then + restart + exit +fi + +if [[ $RUN == true ]]; then + restart + exit +fi \ No newline at end of file