Skip to content

Commit

Permalink
support allow_tvm_london and allow_tvm_compatible_evm
Browse files Browse the repository at this point in the history
  • Loading branch information
neo hong committed Aug 24, 2021
1 parent 8fa5120 commit 9e159c4
Show file tree
Hide file tree
Showing 10 changed files with 435 additions and 43 deletions.
11 changes: 10 additions & 1 deletion actuator/src/main/java/org/tron/core/actuator/VMActuator.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,15 @@ public void execute(Object object) throws ContractExeException {

if (TrxType.TRX_CONTRACT_CREATION_TYPE == trxType && !result.isRevert()) {
byte[] code = program.getResult().getHReturn();
if (vmConfig.allowTvmLondon() && code[0] == (byte) 0xEF) {
// todo deal with exception
// throw new Program.BytecodeExecutionException("Contract creation error: code cannot "
// + "start with {}", "0xEF");
if (null == result.getException()) {
result.setException(Program.Exception
.invalidOpCode((byte) 0xEF));
}
}
long saveCodeEnergy = (long) getLength(code) * EnergyCost.getInstance().getCREATE_DATA();
long afterSpend = program.getEnergyLimitLeft().longValue() - saveCodeEnergy;
if (afterSpend < 0) {
Expand Down Expand Up @@ -297,7 +306,7 @@ private void create()
if (contract == null) {
throw new ContractValidateException("Cannot get CreateSmartContract from transaction");
}
SmartContract newSmartContract = contract.getNewContract();
SmartContract newSmartContract = contract.getNewContract().toBuilder().setVersion(1).build();
if (!contract.getOwnerAddress().equals(newSmartContract.getOriginAddress())) {
logger.info("OwnerAddress not equals OriginAddress");
throw new ContractValidateException("OwnerAddress is not equals OriginAddress");
Expand Down
16 changes: 8 additions & 8 deletions actuator/src/main/java/org/tron/core/utils/ProposalUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -471,10 +471,10 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore,
}
case ALLOW_TVM_LONDON: {
// todo version modify
if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_3)) {
throw new ContractValidateException(
"Bad chain parameter id [ALLOW_TVM_LONDON]");
}
// if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_3)) {
// 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");
Expand All @@ -483,10 +483,10 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore,
}
case ALLOW_TVM_COMPATIBLE_EVM: {
// todo version modify
if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_3)) {
throw new ContractValidateException(
"Bad chain parameter id [ALLOW_TVM_COMPATIBLE_EVM]");
}
// if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_3)) {
// 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");
Expand Down
4 changes: 4 additions & 0 deletions actuator/src/main/java/org/tron/core/vm/OpCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
80 changes: 80 additions & 0 deletions actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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) {

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -1721,4 +1739,66 @@ public Pair<Boolean, byte[]> 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<Boolean, byte[]> 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<Boolean, byte[]> execute(byte[] data) {

if (data.length != 213) {
logger.info("Incorrect input length. Expected {} and got {}", 213, data.length);
return Pair.of(true, DataWord.ZERO().getData());
}
if ((data[212] & 0xFE) != 0) {
logger.info("Incorrect finalization flag, expected 0 or 1 and got {}", data[212]);
return Pair.of(true, DataWord.ZERO().getData());
}
final MessageDigest digest = new Blake2bfMessageDigest();
byte[] result;
try {
digest.update(data);
result = digest.digest();
} catch (Exception e) {
return Pair.of(true, new DataWord(EMPTY_BYTE_ARRAY).getData());
}
return Pair.of(true, result);
}
}

}
43 changes: 15 additions & 28 deletions actuator/src/main/java/org/tron/core/vm/VM.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,7 @@
import static org.tron.common.crypto.Hash.sha3;
import static org.tron.common.utils.ByteUtil.EMPTY_BYTE_ARRAY;
import static org.tron.core.db.TransactionTrace.convertToTronAddress;
import static org.tron.core.vm.OpCode.CALL;
import static org.tron.core.vm.OpCode.CALLTOKEN;
import static org.tron.core.vm.OpCode.CALLTOKENID;
import static org.tron.core.vm.OpCode.CALLTOKENVALUE;
import static org.tron.core.vm.OpCode.CHAINID;
import static org.tron.core.vm.OpCode.CREATE2;
import static org.tron.core.vm.OpCode.EXTCODEHASH;
import static org.tron.core.vm.OpCode.FREEZE;
import static org.tron.core.vm.OpCode.FREEZEEXPIRETIME;
import static org.tron.core.vm.OpCode.ISCONTRACT;
import static org.tron.core.vm.OpCode.PUSH1;
import static org.tron.core.vm.OpCode.REVERT;
import static org.tron.core.vm.OpCode.SAR;
import static org.tron.core.vm.OpCode.SELFBALANCE;
import static org.tron.core.vm.OpCode.SHL;
import static org.tron.core.vm.OpCode.SHR;
import static org.tron.core.vm.OpCode.TOKENBALANCE;
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.*;

import java.math.BigInteger;
import java.util.ArrayList;
Expand Down Expand Up @@ -119,6 +100,8 @@ 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());
}
Expand Down Expand Up @@ -829,7 +812,10 @@ && isDeadAccount(program, callAddressWord)
break;
case GASPRICE: {
DataWord energyPrice = new DataWord(0);

if (program.getContractVersion() == 1) {
energyPrice = new DataWord(program.getContractState()
.getDynamicPropertiesStore().getEnergyFee());
}
program.stackPush(energyPrice);
program.step();
}
Expand Down Expand Up @@ -867,18 +853,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;
Expand Down
28 changes: 22 additions & 6 deletions actuator/src/main/java/org/tron/core/vm/program/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public class Program {
private boolean stopped;
private ProgramPrecompile programPrecompile;


public Program(byte[] ops, ProgramInvoke programInvoke) {
this(ops, programInvoke, null);
}
Expand All @@ -159,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) {
Expand Down Expand Up @@ -716,6 +719,9 @@ private void createContractImpl(DataWord value, byte[] programCode, byte[] newAd

if (!contractAlreadyExists) {
Builder builder = SmartContract.newBuilder();
if (getContractVersion() == 1) {
builder.setVersion(1);
}
builder.setContractAddress(ByteString.copyFrom(newAddress))
.setConsumeUserResourcePercent(100)
.setOriginAddress(ByteString.copyFrom(senderAddress));
Expand All @@ -728,8 +734,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 (getContractVersion() == 1) {
builder.setVersion(1);
}
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()
Expand Down Expand Up @@ -1658,10 +1668,10 @@ public void checkTokenIdInTokenBalance(DataWord tokenIdDataWord) {
}

public DataWord getCallEnergy(OpCode op, DataWord requestedEnergy, DataWord availableEnergy) {
// todo version fork
if (VMConfig.allowTvmCompatibleEvm()) {
availableEnergy.div(new DataWord(intToBytes(64)));
availableEnergy.sub(availableEnergy);
if (getContractVersion() == 1) {
DataWord availableEnergyReduce = availableEnergy.clone();
availableEnergyReduce.div(new DataWord(intToBytes(64)));
availableEnergy.sub(availableEnergyReduce);
}
return requestedEnergy.compareTo(availableEnergy) > 0 ? availableEnergy : requestedEnergy;
}
Expand Down Expand Up @@ -1963,6 +1973,12 @@ public long withdrawReward() {
return 0;
}

public int getContractVersion() {
byte [] contractAddress =
TransactionTrace.convertToTronAddress(getContractAddress().getLast20Bytes());
return invoke.getDeposit().getContract(contractAddress).getContractVersion();
}

/**
* Denotes problem when executing Ethereum bytecode. From blockchain and peer perspective this is
* quite normal situation and doesn't mean exceptional situation in terms of the program
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,8 @@ public void clearABI() {
public byte[] getTrxHash() {
return this.smartContract.getTrxHash().toByteArray();
}

public int getContractVersion() {
return this.smartContract.getVersion();
}
}
Loading

0 comments on commit 9e159c4

Please sign in to comment.