Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ public class CommonParameter {
public long maxEnergyLimitForConstant = 100_000_000L;
@Getter
@Setter
public int maxConcurrentConstantCalls = 8;
@Getter
@Setter
public int lruCacheSize = 500;
@Getter
@Setter
Expand Down Expand Up @@ -216,6 +219,9 @@ public class CommonParameter {
public int maxMessageSize;
@Getter
@Setter
public int maxHttpRequestBodySize = 5 * 1024 * 1024;
@Getter
@Setter
public int maxHeaderListSize;
@Getter
@Setter
Expand Down Expand Up @@ -459,6 +465,18 @@ public class CommonParameter {
@Getter
@Setter
public int jsonRpcMaxBlockFilterNum = 50000;
@Getter
@Setter
public int jsonRpcMaxBatchSize = 1000;
@Getter
@Setter
public int jsonRpcMaxResponseSize = 25 * 1024 * 1024;
@Getter
@Setter
public int jsonRpcMaxRequestTimeout = 30;
@Getter
@Setter
public int jsonRpcMaxAddressSize = 1000;

@Getter
@Setter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@

package org.tron.common.application;

import java.util.EnumSet;
import java.util.concurrent.CompletableFuture;
import javax.servlet.DispatcherType;
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.tron.core.config.args.Args;
import org.tron.core.services.filter.RequestBodySizeLimitFilter;

@Slf4j(topic = "rpc")
public abstract class HttpService extends AbstractService {
Expand Down Expand Up @@ -70,6 +74,7 @@ protected ServletContextHandler initContextHandler() {
protected abstract void addServlet(ServletContextHandler context);

protected void addFilter(ServletContextHandler context) {

context.addFilter(new FilterHolder(new RequestBodySizeLimitFilter()),
"/*", EnumSet.allOf(DispatcherType.class));
}
}
27 changes: 27 additions & 0 deletions framework/src/main/java/org/tron/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Semaphore;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -263,6 +264,9 @@
@Component
public class Wallet {

private static final Semaphore CONSTANT_CALL_SEMAPHORE = new Semaphore(
Args.getInstance().getMaxConcurrentConstantCalls());

private static final String SHIELDED_ID_NOT_ALLOWED = "ShieldedTransactionApi is not allowed";
private static final String PAYMENT_ADDRESS_FORMAT_WRONG = "paymentAddress format is wrong";
private static final String SHIELDED_TRANSACTION_SCAN_RANGE =
Expand Down Expand Up @@ -743,6 +747,9 @@ public Block getByJsonBlockId(String id) throws JsonRpcInvalidParamsException {
} else if (PENDING_STR.equalsIgnoreCase(id)) {
throw new JsonRpcInvalidParamsException(TAG_PENDING_SUPPORT_ERROR);
} else {
if (id.length() > 128) {
throw new JsonRpcInvalidParamsException("invalid block number");
}
long blockNumber;
try {
blockNumber = ByteArray.hexToBigInteger(id).longValue();
Expand Down Expand Up @@ -3124,6 +3131,26 @@ public Transaction triggerConstantContract(TriggerSmartContract triggerSmartCont
TransactionCapsule trxCap, Builder builder, Return.Builder retBuilder, boolean isEstimating)
throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException {

if (!CONSTANT_CALL_SEMAPHORE.tryAcquire()) {
throw new ContractValidateException(
"Too many concurrent constant calls, max allowed: "
+ Args.getInstance().getMaxConcurrentConstantCalls());
}
try {
return doTriggerConstantContract(
triggerSmartContract, trxCap, builder, retBuilder, isEstimating);
} finally {
CONSTANT_CALL_SEMAPHORE.release();
}
}

private Transaction doTriggerConstantContract(
TriggerSmartContract triggerSmartContract,
TransactionCapsule trxCap, Builder builder, Return.Builder retBuilder,
boolean isEstimating)
throws ContractValidateException, ContractExeException,
HeaderNotFound, VMIllegalException {

if (triggerSmartContract.getContractAddress().isEmpty()) { // deploy contract
CreateSmartContract.Builder deployBuilder = CreateSmartContract.newBuilder();
deployBuilder.setOwnerAddress(triggerSmartContract.getOwnerAddress());
Expand Down
30 changes: 30 additions & 0 deletions framework/src/main/java/org/tron/core/config/args/Args.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ public static void applyConfigParams(
PARAMETER.maxEnergyLimitForConstant = max(ENERGY_LIMIT_IN_CONSTANT_TX, configLimit, true);
}

if (config.hasPath(ConfigKey.VM_MAX_CONCURRENT_CONSTANT_CALLS)) {
PARAMETER.maxConcurrentConstantCalls =
config.getInt(ConfigKey.VM_MAX_CONCURRENT_CONSTANT_CALLS);
}

if (config.hasPath(ConfigKey.VM_LRU_CACHE_SIZE)) {
PARAMETER.lruCacheSize = config.getInt(ConfigKey.VM_LRU_CACHE_SIZE);
}
Expand Down Expand Up @@ -265,6 +270,26 @@ public static void applyConfigParams(
config.getInt(ConfigKey.NODE_JSONRPC_MAX_BLOCK_FILTER_NUM);
}

if (config.hasPath(ConfigKey.NODE_JSONRPC_MAX_BATCH_SIZE)) {
PARAMETER.jsonRpcMaxBatchSize =
config.getInt(ConfigKey.NODE_JSONRPC_MAX_BATCH_SIZE);
}

if (config.hasPath(ConfigKey.NODE_JSONRPC_MAX_RESPONSE_SIZE)) {
PARAMETER.jsonRpcMaxResponseSize =
config.getInt(ConfigKey.NODE_JSONRPC_MAX_RESPONSE_SIZE);
}

if (config.hasPath(ConfigKey.NODE_JSONRPC_MAX_REQUEST_TIMEOUT)) {
PARAMETER.jsonRpcMaxRequestTimeout =
config.getInt(ConfigKey.NODE_JSONRPC_MAX_REQUEST_TIMEOUT);
}

if (config.hasPath(ConfigKey.NODE_JSONRPC_MAX_ADDRESS_SIZE)) {
PARAMETER.jsonRpcMaxAddressSize =
config.getInt(ConfigKey.NODE_JSONRPC_MAX_ADDRESS_SIZE);
}

if (config.hasPath(ConfigKey.VM_MIN_TIME_RATIO)) {
PARAMETER.minTimeRatio = config.getDouble(ConfigKey.VM_MIN_TIME_RATIO);
}
Expand Down Expand Up @@ -526,6 +551,11 @@ public static void applyConfigParams(
PARAMETER.maxMessageSize = config.hasPath(ConfigKey.NODE_RPC_MAX_MESSAGE_SIZE)
? config.getInt(ConfigKey.NODE_RPC_MAX_MESSAGE_SIZE) : GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;

if (config.hasPath(ConfigKey.NODE_HTTP_MAX_REQUEST_BODY_SIZE)) {
PARAMETER.maxHttpRequestBodySize =
config.getInt(ConfigKey.NODE_HTTP_MAX_REQUEST_BODY_SIZE);
}

PARAMETER.maxHeaderListSize = config.hasPath(ConfigKey.NODE_RPC_MAX_HEADER_LIST_SIZE)
? config.getInt(ConfigKey.NODE_RPC_MAX_HEADER_LIST_SIZE)
: GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
Expand Down
12 changes: 12 additions & 0 deletions framework/src/main/java/org/tron/core/config/args/ConfigKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ private ConfigKey() {
// vm
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_MAX_CONCURRENT_CONSTANT_CALLS =
"vm.maxConcurrentConstantCalls";
public static final String VM_LRU_CACHE_SIZE = "vm.lruCacheSize";
public static final String VM_MIN_TIME_RATIO = "vm.minTimeRatio";
public static final String VM_MAX_TIME_RATIO = "vm.maxTimeRatio";
Expand Down Expand Up @@ -123,6 +125,8 @@ private ConfigKey() {
public static final String NODE_RPC_MAX_CONNECTION_AGE_IN_MILLIS =
"node.rpc.maxConnectionAgeInMillis";
public static final String NODE_RPC_MAX_MESSAGE_SIZE = "node.rpc.maxMessageSize";
public static final String NODE_HTTP_MAX_REQUEST_BODY_SIZE =
"node.http.maxRequestBodySize";
public static final String NODE_RPC_MAX_HEADER_LIST_SIZE = "node.rpc.maxHeaderListSize";
public static final String NODE_RPC_REFLECTION_SERVICE = "node.rpc.reflectionService";
public static final String NODE_RPC_MIN_EFFECTIVE_CONNECTION =
Expand Down Expand Up @@ -150,6 +154,14 @@ private ConfigKey() {
public static final String NODE_JSONRPC_MAX_SUB_TOPICS = "node.jsonrpc.maxSubTopics";
public static final String NODE_JSONRPC_MAX_BLOCK_FILTER_NUM =
"node.jsonrpc.maxBlockFilterNum";
public static final String NODE_JSONRPC_MAX_BATCH_SIZE =
"node.jsonrpc.maxBatchSize";
public static final String NODE_JSONRPC_MAX_RESPONSE_SIZE =
"node.jsonrpc.maxResponseSize";
public static final String NODE_JSONRPC_MAX_REQUEST_TIMEOUT =
"node.jsonrpc.maxRequestTimeout";
public static final String NODE_JSONRPC_MAX_ADDRESS_SIZE =
"node.jsonrpc.maxAddressSize";

// node - dns
public static final String NODE_DNS_TREE_URLS = "node.dns.treeUrls";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.tron.core.services.filter;

import java.io.ByteArrayOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
* Buffers the response body so the caller can inspect the size
* before committing. If maxBytes > 0, writes that push the buffer
* past maxBytes throw ResponseTooLargeException immediately.
*/
public class BufferedResponseWrapper extends HttpServletResponseWrapper {

private final ByteArrayOutputStream buffer =
new ByteArrayOutputStream();
private final int maxBytes;
private final ServletOutputStream outputStream =
new ServletOutputStream() {
@Override
public void write(int b) {
checkLimit(1);
buffer.write(b);
}

@Override
public void write(byte[] b, int off, int len) {
checkLimit(len);
buffer.write(b, off, len);
}

@Override
public boolean isReady() {
return true;
}

@Override
public void setWriteListener(WriteListener writeListener) {
}
};

public BufferedResponseWrapper(HttpServletResponse response,
int maxBytes) {
super(response);
this.maxBytes = maxBytes;
}

private void checkLimit(int incoming) {
if (maxBytes > 0 && buffer.size() + incoming > maxBytes) {
throw new ResponseTooLargeException(
"Response size exceeds the limit of " + maxBytes
+ " bytes");
}
}

@Override
public ServletOutputStream getOutputStream() {
return outputStream;
}

@Override
public void setContentLength(int len) {
}

@Override
public void setContentLengthLong(long len) {
}

public byte[] toByteArray() {
return buffer.toByteArray();
}

public static class ResponseTooLargeException
extends RuntimeException {

public ResponseTooLargeException(String message) {
super(message);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.tron.core.services.filter;

import java.io.ByteArrayInputStream;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
* Wraps a request and replays a pre-read body from a byte array.
*/
public class CachedBodyRequestWrapper extends HttpServletRequestWrapper {

private final byte[] body;

public CachedBodyRequestWrapper(HttpServletRequest request,
byte[] body) {
super(request);
this.body = body;
}

@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bais.read();
}

@Override
public int read(byte[] b, int off, int len) {
return bais.read(b, off, len);
}

@Override
public boolean isFinished() {
return bais.available() == 0;
}

@Override
public boolean isReady() {
return true;
}

@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.tron.core.services.filter;

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.tron.common.parameter.CommonParameter;

@Slf4j(topic = "API")
public class RequestBodySizeLimitFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) {
try {
if (request instanceof HttpServletRequest) {
HttpServletRequest httpReq = (HttpServletRequest) request;
int maxBodySize = CommonParameter.getInstance()
.getMaxHttpRequestBodySize();
if (maxBodySize > 0 && httpReq.getContentLength() > maxBodySize) {
HttpServletResponse resp = (HttpServletResponse) response;
resp.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
resp.setContentType("application/json; charset=utf-8");
resp.getWriter().println(
"{\"Error\":\"request body too large, limit is "
+ maxBodySize + " bytes\"}");
return;
}
}
chain.doFilter(request, response);
} catch (Exception e) {
logger.error("RequestBodySizeLimitFilter exception: {}",
e.getMessage());
}
}

@Override
public void destroy() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,8 @@ protected void addServlet(ServletContextHandler context) {

@Override
protected void addFilter(ServletContextHandler context) {
super.addFilter(context);

// filters the specified APIs
// when node is lite fullnode and openHistoryQueryWhenLiteFN is false
context.addFilter(new FilterHolder(liteFnQueryHttpFilter), "/*",
Expand Down
Loading
Loading