TRON - это почти EVM сеть. Иногда это "почти" заставляет целые классы инструментов характерных для EVM-сетей внезапно ломаться, не поддерживать или отсутствовать, когда дело касается именно сети TRON.
Тот же простой реплей транзакции с дебаг-трейсом я в свое время не нашел как получить. Такого метода нет ни в HTTP, ни в JSON_RPC апи движка
Это не значит, что метода для получения дебаг-трейса через публичные ноды TRON нет в принципе, очевидно его реализовать можно. Скорее всего это я плохо искал. В любом случае, тут я показываю как поднять свою ноду локально. Это надежно, приватно и убережет от потенциальных технических проблем. Начнем.
Сперва про готовые решения. На докерхабе существуют уже обертки
Я покажу как сделать свою обертку в несколько шагов. По ходу создания решим еще 2 важные проблемы с которыми вы столкнетесь:
Проблема 1: Нетворк параметры
Это своего рода фича-тоглы, нужны чтобы все ноды сети могли обновиться мгновенно. Без их включения голая
Хорошая новость - часть их можно включить через конфиг:
Плохая новость - некоторые важные параметры с конфига не считываются. Например,
Вот как подобные параметры включать:
1. Качаем
2. Меняем
3. Создаем
3. Регистрируем в
4. Собираем
5. Запускаем
6. Проверяем
Потом советую добавить HTTP прокси-логгер. Будет удобно.
Проблема 2: А как деплоить?
Теперь когда тестнет готов остается только вопрос - "через какой интерфейс его использовать?". Никакого кода я тут давать не буду, просто обрисую как это должно выглядеть по-человечески.
Мы хотим писать наши плэйбуки/тесты/эксперименты (в общем то, что подразумевает под собой множественный деплой и вызов самрт-контрактов) декларативно через удобный формат типо
В общем, что-то типо
Архитектура примерно такая:
java-tron node <-- client (TronWeb) <-- playbook engine <-- .yaml
На этом всё. Давайте фидбек кто чем занимается, какие проблемы, какие успехи. Тут мало кто про крипту пишет.
Тот же простой реплей транзакции с дебаг-трейсом я в свое время не нашел как получить. Такого метода нет ни в HTTP, ни в JSON_RPC апи движка
java-tron. Единственный способ - это иметь локальный доступ к ноде, так как трейсы сохраняются только на диск с включенным флагом в конфиге:
Code:
vm = {
vmTrace = true
}
Сперва про готовые решения. На докерхабе существуют уже обертки
tronbox/tre и старый trontools/quickstart. Советую про них сразу забыть, они время не сэкономят. Я покажу как сделать свою обертку в несколько шагов. По ходу создания решим еще 2 важные проблемы с которыми вы столкнетесь:
Проблема 1: Нетворк параметры
Это своего рода фича-тоглы, нужны чтобы все ноды сети могли обновиться мгновенно. Без их включения голая
java-tron даже дебаг-трейса не даст.Хорошая новость - часть их можно включить через конфиг:
Code:
committee = {
allowCreationOfContracts = 1
allowUpdateAccountName = 1
allowSameTokenName = 1
...
}
Плохая новость - некоторые важные параметры с конфига не считываются. Например,
getMaxCpuTimeOfOneTx очень важный параметр от которого зависит выполнится ли твоя транзакция или уйдет в OUT_OF_TIME, что частый случай при включенном vmTrace = true, который замедляет.Вот как подобные параметры включать:
1. Качаем
java-tron
Code:
git clone https://github.com/tronprotocol/java-tron
/java-tron/framework/src/main/java/org/tron/core/consensus/ProposalService.java на:Спойлер: ProposalService.java
Code:
package org.tron.core.consensus;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.tron.core.capsule.ProposalCapsule;
import org.tron.core.config.Parameter.ForkBlockVersionEnum;
import org.tron.core.db.HistoryBlockHashUtil;
import org.tron.core.db.Manager;
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.core.utils.ProposalUtil;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
/**
* Notice:
* <p>
* if you want to add a proposal,you just should add a enum ProposalType and add the valid in the
* validator method, add the process in the process method
*/
@Slf4j
@Component
public class ProposalService extends ProposalUtil implements ApplicationContextAware {
private static ApplicationContext context;
private Manager manager;
private ProposalCapsule proposalCapsule;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
private static Manager getManagerFromContext() {
return context.getBean(Manager.class);
}
public static boolean process(Manager manager, ProposalCapsule proposalCapsule) {
Map<Long, Long> parameters = proposalCapsule.getInstance().getParametersMap();
boolean success = true;
ProposalService service = new ProposalService();
service.manager = manager;
service.proposalCapsule = proposalCapsule;
for (Map.Entry<Long, Long> entry : parameters.entrySet()) {
ProposalType proposalType = ProposalType.getEnumOrNull(entry.getKey());
if (proposalType == null) {
success = false;
continue;
}
service.apply(proposalType, entry.getValue());
}
return success;
}
/**
* Public static entry point for external callers (e.g. HTTP API, debugger) that want to apply
* a single dynamic parameter directly, outside of the normal on-chain proposal flow. There is
* no ProposalCapsule in this context, so any case that logs a price/fee history entry keyed by
* proposal expiration time will skip that history write and only persist the value itself.
*/
public static void apply(ProposalType proposalType, Long value) {
ProposalService service = new ProposalService();
service.manager = getManagerFromContext();
service.proposalCapsule = null;
service.applyInternal(proposalType, value);
}
private void applyInternal(ProposalType proposalType, Long value) {
DynamicPropertiesStore dynamicStore = manager.getDynamicPropertiesStore();
switch (proposalType) {
case MAINTENANCE_TIME_INTERVAL: {
dynamicStore.saveMaintenanceTimeInterval(value);
break;
}
case ACCOUNT_UPGRADE_COST: {
dynamicStore.saveAccountUpgradeCost(value);
break;
}
case CREATE_ACCOUNT_FEE: {
dynamicStore.saveCreateAccountFee(value);
break;
}
case TRANSACTION_FEE: {
dynamicStore.saveTransactionFee(value);
// update bandwidth price history
if (proposalCapsule != null) {
dynamicStore.saveBandwidthPriceHistory(
dynamicStore.getBandwidthPriceHistory()
+ "," + proposalCapsule.getExpirationTime() + ":" + value);
}
break;
}
case ASSET_ISSUE_FEE: {
dynamicStore.saveAssetIssueFee(value);
break;
}
case WITNESS_PAY_PER_BLOCK: {
dynamicStore.saveWitnessPayPerBlock(value);
break;
}
case WITNESS_STANDBY_ALLOWANCE: {
dynamicStore.saveWitnessStandbyAllowance(value);
break;
}
case CREATE_NEW_ACCOUNT_FEE_IN_SYSTEM_CONTRACT: {
dynamicStore
.saveCreateNewAccountFeeInSystemContract(value);
break;
}
case CREATE_NEW_ACCOUNT_BANDWIDTH_RATE: {
dynamicStore.saveCreateNewAccountBandwidthRate(value);
break;
}
case ALLOW_CREATION_OF_CONTRACTS: {
dynamicStore.saveAllowCreationOfContracts(value);
break;
}
case REMOVE_THE_POWER_OF_THE_GR: {
if (dynamicStore.getRemoveThePowerOfTheGr() == 0) {
dynamicStore.saveRemoveThePowerOfTheGr(value);
}
break;
}
case ENERGY_FEE: {
dynamicStore.saveEnergyFee(value);
// update energy price history
if (proposalCapsule != null) {
dynamicStore.saveEnergyPriceHistory(
dynamicStore.getEnergyPriceHistory()
+ "," + proposalCapsule.getExpirationTime() + ":" + value);
}
break;
}
case EXCHANGE_CREATE_FEE: {
dynamicStore.saveExchangeCreateFee(value);
break;
}
case MAX_CPU_TIME_OF_ONE_TX: {
dynamicStore.saveMaxCpuTimeOfOneTx(value);
break;
}
case ALLOW_UPDATE_ACCOUNT_NAME: {
dynamicStore.saveAllowUpdateAccountName(value);
break;
}
case ALLOW_SAME_TOKEN_NAME: {
dynamicStore.saveAllowSameTokenName(value);
break;
}
case ALLOW_DELEGATE_RESOURCE: {
dynamicStore.saveAllowDelegateResource(value);
break;
}
case TOTAL_ENERGY_LIMIT: {
dynamicStore.saveTotalEnergyLimit(value);
break;
}
case ALLOW_TVM_TRANSFER_TRC10: {
dynamicStore.saveAllowTvmTransferTrc10(value);
break;
}
case TOTAL_CURRENT_ENERGY_LIMIT: {
dynamicStore.saveTotalEnergyLimit2(value);
break;
}
case ALLOW_MULTI_SIGN: {
if (dynamicStore.getAllowMultiSign() == 0) {
dynamicStore.saveAllowMultiSign(value);
}
break;
}
case ALLOW_ADAPTIVE_ENERGY: {
if (dynamicStore.getAllowAdaptiveEnergy() == 0) {
dynamicStore.saveAllowAdaptiveEnergy(value);
if (manager.getChainBaseManager()
.getForkController().pass(ForkBlockVersionEnum.VERSION_3_6_5)) {
//24 * 60 * 2 . one minute,1/2 total limit.
dynamicStore.saveAdaptiveResourceLimitTargetRatio(2880);
dynamicStore.saveTotalEnergyTargetLimit(
dynamicStore.getTotalEnergyLimit() / 2880);
dynamicStore.saveAdaptiveResourceLimitMultiplier(50);
}
}
break;
}
case UPDATE_ACCOUNT_PERMISSION_FEE: {
dynamicStore.saveUpdateAccountPermissionFee(value);
break;
}
case MULTI_SIGN_FEE: {
dynamicStore.saveMultiSignFee(value);
break;
}
case ALLOW_PROTO_FILTER_NUM: {
dynamicStore.saveAllowProtoFilterNum(value);
break;
}
case ALLOW_ACCOUNT_STATE_ROOT: {
dynamicStore.saveAllowAccountStateRoot(value);
break;
}
case ALLOW_TVM_CONSTANTINOPLE: {
dynamicStore.saveAllowTvmConstantinople(value);
dynamicStore.addSystemContractAndSetPermission(48);
break;
}
case ALLOW_TVM_SOLIDITY_059: {
dynamicStore.saveAllowTvmSolidity059(value);
break;
}
case ADAPTIVE_RESOURCE_LIMIT_TARGET_RATIO: {
long ratio = 24 * 60 * value;
dynamicStore.saveAdaptiveResourceLimitTargetRatio(ratio);
dynamicStore.saveTotalEnergyTargetLimit(
dynamicStore.getTotalEnergyLimit() / ratio);
break;
}
case ADAPTIVE_RESOURCE_LIMIT_MULTIPLIER: {
dynamicStore.saveAdaptiveResourceLimitMultiplier(value);
break;
}
case ALLOW_CHANGE_DELEGATION: {
dynamicStore.saveChangeDelegation(value);
dynamicStore.addSystemContractAndSetPermission(49);
break;
}
case WITNESS_127_PAY_PER_BLOCK: {
dynamicStore.saveWitness127PayPerBlock(value);
break;
}
case FORBID_TRANSFER_TO_CONTRACT: {
dynamicStore.saveForbidTransferToContract(value);
break;
}
case ALLOW_PBFT: {
dynamicStore.saveAllowPBFT(value);
break;
}
case ALLOW_TVM_ISTANBUL: {
dynamicStore.saveAllowTvmIstanbul(value);
break;
}
case ALLOW_SHIELDED_TRC20_TRANSACTION: {
dynamicStore.saveAllowShieldedTRC20Transaction(value);
break;
}
case ALLOW_MARKET_TRANSACTION: {
if (dynamicStore.getAllowMarketTransaction() == 0) {
dynamicStore.saveAllowMarketTransaction(value);
dynamicStore.addSystemContractAndSetPermission(52);
dynamicStore.addSystemContractAndSetPermission(53);
}
break;
}
case MARKET_SELL_FEE: {
dynamicStore.saveMarketSellFee(value);
break;
}
case MARKET_CANCEL_FEE: {
dynamicStore.saveMarketCancelFee(value);
break;
}
case MAX_FEE_LIMIT: {
dynamicStore.saveMaxFeeLimit(value);
break;
}
case ALLOW_TRANSACTION_FEE_POOL: {
dynamicStore.saveAllowTransactionFeePool(value);
break;
}
case ALLOW_BLACKHOLE_OPTIMIZATION: {
dynamicStore.saveAllowBlackHoleOptimization(value);
break;
}
case ALLOW_NEW_RESOURCE_MODEL: {
dynamicStore.saveAllowNewResourceModel(value);
break;
}
case ALLOW_TVM_FREEZE: {
dynamicStore.saveAllowTvmFreeze(value);
break;
}
case ALLOW_TVM_VOTE: {
dynamicStore.saveNewRewardAlgorithmEffectiveCycle();
dynamicStore.saveAllowTvmVote(value);
break;
}
case ALLOW_TVM_LONDON: {
dynamicStore.saveAllowTvmLondon(value);
break;
}
case ALLOW_TVM_COMPATIBLE_EVM: {
dynamicStore.saveAllowTvmCompatibleEvm(value);
break;
}
case FREE_NET_LIMIT: {
dynamicStore.saveFreeNetLimit(value);
break;
}
case TOTAL_NET_LIMIT: {
dynamicStore.saveTotalNetLimit(value);
break;
}
case ALLOW_ACCOUNT_ASSET_OPTIMIZATION: {
dynamicStore.setAllowAccountAssetOptimization(value);
break;
}
case ALLOW_HIGHER_LIMIT_FOR_MAX_CPU_TIME_OF_ONE_TX: {
dynamicStore.saveAllowHigherLimitForMaxCpuTimeOfOneTx(
value);
break;
}
case ALLOW_ASSET_OPTIMIZATION: {
dynamicStore.setAllowAssetOptimization(value);
break;
}
case ALLOW_NEW_REWARD: {
dynamicStore.saveNewRewardAlgorithmEffectiveCycle();
dynamicStore.saveAllowNewReward(value);
break;
}
case MEMO_FEE: {
dynamicStore.saveMemoFee(value);
// update memo fee history
if (proposalCapsule != null) {
dynamicStore.saveMemoFeeHistory(
dynamicStore.getMemoFeeHistory()
+ "," + proposalCapsule.getExpirationTime() + ":" + value);
}
break;
}
case UNFREEZE_DELAY_DAYS: {
dynamicStore.saveUnfreezeDelayDays(value);
dynamicStore.addSystemContractAndSetPermission(
ContractType.FreezeBalanceV2Contract_VALUE);
dynamicStore.addSystemContractAndSetPermission(
ContractType.UnfreezeBalanceV2Contract_VALUE);
dynamicStore.addSystemContractAndSetPermission(
ContractType.WithdrawExpireUnfreezeContract_VALUE);
dynamicStore.addSystemContractAndSetPermission(
ContractType.DelegateResourceContract_VALUE);
dynamicStore.addSystemContractAndSetPermission(
ContractType.UnDelegateResourceContract_VALUE);
break;
}
case ALLOW_DELEGATE_OPTIMIZATION: {
dynamicStore.saveAllowDelegateOptimization(value);
break;
}
case ALLOW_OPTIMIZED_RETURN_VALUE_OF_CHAIN_ID: {
dynamicStore
.saveAllowOptimizedReturnValueOfChainId(value);
break;
}
case ALLOW_DYNAMIC_ENERGY: {
dynamicStore.saveAllowDynamicEnergy(value);
break;
}
case DYNAMIC_ENERGY_THRESHOLD: {
dynamicStore.saveDynamicEnergyThreshold(value);
break;
}
case DYNAMIC_ENERGY_INCREASE_FACTOR: {
dynamicStore.saveDynamicEnergyIncreaseFactor(value);
break;
}
case DYNAMIC_ENERGY_MAX_FACTOR: {
dynamicStore.saveDynamicEnergyMaxFactor(value);
break;
}
case ALLOW_TVM_SHANGHAI: {
dynamicStore.saveAllowTvmShangHai(value);
break;
}
case ALLOW_CANCEL_ALL_UNFREEZE_V2: {
if (dynamicStore.getAllowCancelAllUnfreezeV2() == 0) {
dynamicStore.saveAllowCancelAllUnfreezeV2(value);
dynamicStore.addSystemContractAndSetPermission(
ContractType.CancelAllUnfreezeV2Contract_VALUE);
}
break;
}
case MAX_DELEGATE_LOCK_PERIOD: {
dynamicStore.saveMaxDelegateLockPeriod(value);
break;
}
case ALLOW_OLD_REWARD_OPT: {
dynamicStore.saveAllowOldRewardOpt(value);
break;
}
case ALLOW_ENERGY_ADJUSTMENT: {
dynamicStore.saveAllowEnergyAdjustment(value);
break;
}
case MAX_CREATE_ACCOUNT_TX_SIZE: {
dynamicStore.saveMaxCreateAccountTxSize(value);
break;
}
case ALLOW_STRICT_MATH: {
dynamicStore.saveAllowStrictMath(value);
break;
}
case CONSENSUS_LOGIC_OPTIMIZATION: {
dynamicStore
.saveConsensusLogicOptimization(value);
break;
}
case ALLOW_TVM_CANCUN: {
dynamicStore.saveAllowTvmCancun(value);
break;
}
case ALLOW_TVM_BLOB: {
dynamicStore.saveAllowTvmBlob(value);
break;
}
case ALLOW_TVM_SELFDESTRUCT_RESTRICTION: {
dynamicStore.saveAllowTvmSelfdestructRestriction(value);
break;
}
case PROPOSAL_EXPIRE_TIME: {
dynamicStore.saveProposalExpireTime(value);
break;
}
case ALLOW_TVM_OSAKA: {
dynamicStore.saveAllowTvmOsaka(value);
break;
}
case ALLOW_TVM_PRAGUE: {
dynamicStore.saveAllowTvmPrague(value);
HistoryBlockHashUtil.deploy(manager);
break;
}
case ALLOW_HARDEN_RESOURCE_CALCULATION: {
dynamicStore
.saveAllowHardenResourceCalculation(value);
break;
}
case ALLOW_HARDEN_EXCHANGE_CALCULATION: {
dynamicStore
.saveAllowHardenExchangeCalculation(value);
break;
}
default:
break;
}
}
}
/java-tron/framework/src/main/java/org/tron/core/services/http/UpdateProposalParameterServlet.javaСпойлер: UpdateProposalParameterServlet.java
Code:
package org.tron.core.services.http;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.tron.core.consensus.ProposalService;
import org.tron.core.utils.ProposalUtil.ProposalType;
import org.tron.json.JSONObject;
@Slf4j(topic = "API")
@Component
public class UpdateProposalParameterServlet extends RateLimiterServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
try {
String body = request.getReader().lines().reduce("", (a, b) -> a + b);
JSONObject json = JSONObject.parseObject(body);
String key = json.getString("key");
long value = json.getLongValue("value");
ProposalType proposalType;
try {
proposalType = ProposalType.valueOf(key);
} catch (IllegalArgumentException e) {
response.getWriter().println("{\"result\":false,\"error\":\"unknown key: " + key + "\"}");
return;
}
ProposalService.apply(proposalType, value);
response.getWriter().println("{\"result\":true}");
} catch (Exception e) {
logger.error("UpdateProposalParameterServlet error", e);
try {
response.getWriter().println("{\"result\":false,\"error\":\"" + e.getMessage() + "\"}");
} catch (IOException ex) {
logger.error("IOException", ex);
}
}
}
}
/java-tron/framework/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java
Code:
@Autowired
private UpdateProposalParameterServlet updateProposalParameterServlet;
...
context.addServlet(new ServletHolder(updateProposalParameterServlet),
"/wallet/updateproposalparameter");
Спойлер: Dockefile
Code:
FROM tronprotocol/centos7:0.2
ENV TMP_DIR="/tron-build"
ENV JDK_TAR="jdk-8u202-linux-x64.tar.gz"
ENV JDK_DIR="jdk1.8.0_202"
ENV JDK_MD5="0029351f7a946f6c05b582100c7d45b7"
ENV BASE_DIR="/java-tron"
# исходники копируются из локального контекста сборки
COPY . $TMP_DIR/java-tron
RUN set -o errexit -o nounset \
&& yum -y install git wget \
&& wget -P /usr/local https://github.com/frekele/oracle-java/releases/download/8u202-b08/$JDK_TAR \
&& echo "$JDK_MD5 /usr/local/$JDK_TAR" | md5sum -c \
&& tar -zxf /usr/local/$JDK_TAR -C /usr/local \
&& rm /usr/local/$JDK_TAR \
&& export JAVA_HOME=/usr/local/$JDK_DIR \
&& export CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar \
&& export PATH=$PATH:$JAVA_HOME/bin \
&& cd $TMP_DIR/java-tron \
&& chmod +x gradlew \
&& ./gradlew build -x test \
&& cd build/distributions \
&& 7za x -y java-tron-1.0.0.zip \
&& mv java-tron-1.0.0 $BASE_DIR \
&& rm -rf $TMP_DIR \
&& rm -rf ~/.gradle \
&& mv $JAVA_HOME/jre /usr/local \
&& rm -rf $JAVA_HOME \
&& yum clean all
RUN wget -P $BASE_DIR/config https://raw.githubusercontent.com/tronprotocol/tron-deployment/master/main_net_config.conf
ENV JAVA_HOME="/usr/local/jre"
ENV PATH=$PATH:$JAVA_HOME/bin
WORKDIR $BASE_DIR
ENTRYPOINT ["./bin/FullNode"]
Спойлер: docker-compose.yml
Code:
services:
tron-witness1:
# image: tronprotocol/java-tron:latest
image: mine/java-tron
container_name: tron-witness1
networks:
- tron_private_network
deploy:
resources:
limits:
memory: 12g
ports:
- "8545:8545"
- "8090:8090" # for external http API request
- "50051:50051" # for external rpc API request
volumes:
- ./conf/:/java-tron/conf/
# - ./datadir:/java-tron/data # mount a local directory to make the blocks data persistent.
# - ./logs/tron-witness1:/java-tron/logs # map to host logs
command: >
-jvm "{-Xmx12g -Xmn2g -XX:+UseConcMarkSweepGC}" -c /java-tron/conf/private_net_config_witness1.conf -d /java-tron/data -w
networks:
tron_private_network:
driver: bridge
Code:
curl -X POST http://localhost:8090/wallet/updateproposalparameter \
-d '{"key": "ALLOW_CANCEL_ALL_UNFREEZE_V2", "value": 1}'
Code:
curl -X POST http://localhost:8090/wallet/getchainparameters
Спойлер: mainet_chainparameters.json
Code:
{
"chainParameter": [
{
"key": "getMaintenanceTimeInterval",
"value": 21600000
},
{
"key": "getAccountUpgradeCost",
"value": 9999000000
},
{
"key": "getCreateAccountFee",
"value": 100000
},
{
"key": "getTransactionFee",
"value": 1000
},
{
"key": "getAssetIssueFee",
"value": 1024000000
},
{
"key": "getWitnessPayPerBlock",
"value": 8000000
},
{
"key": "getWitnessStandbyAllowance",
"value": 115200000000
},
{
"key": "getCreateNewAccountFeeInSystemContract",
"value": 1000000
},
{
"key": "getCreateNewAccountBandwidthRate",
"value": 1
},
{
"key": "getAllowCreationOfContracts",
"value": 1
},
{
"key": "getRemoveThePowerOfTheGr",
"value": -1
},
{
"key": "getEnergyFee",
"value": 100
},
{
"key": "getExchangeCreateFee",
"value": 1024000000
},
{
"key": "getMaxCpuTimeOfOneTx",
"value": 800
},
{
"key": "getAllowUpdateAccountName"
},
{
"key": "getAllowSameTokenName",
"value": 1
},
{
"key": "getAllowDelegateResource",
"value": 1
},
{
"key": "getTotalEnergyLimit",
"value": 180000000000
},
{
"key": "getAllowTvmTransferTrc10",
"value": 1
},
{
"key": "getTotalEnergyCurrentLimit",
"value": 180000000000
},
{
"key": "getAllowMultiSign",
"value": 1
},
{
"key": "getAllowAdaptiveEnergy"
},
{
"key": "getTotalEnergyTargetLimit",
"value": 12500000
},
{
"key": "getTotalEnergyAverageUsage"
},
{
"key": "getUpdateAccountPermissionFee",
"value": 100000000
},
{
"key": "getMultiSignFee",
"value": 1000000
},
{
"key": "getAllowAccountStateRoot"
},
{
"key": "getAllowProtoFilterNum"
},
{
"key": "getAllowTvmConstantinople",
"value": 1
},
{
"key": "getAllowTvmSolidity059",
"value": 1
},
{
"key": "getAllowTvmIstanbul",
"value": 1
},
{
"key": "getAllowShieldedTRC20Transaction",
"value": 1
},
{
"key": "getForbidTransferToContract"
},
{
"key": "getAdaptiveResourceLimitTargetRatio",
"value": 10
},
{
"key": "getAdaptiveResourceLimitMultiplier",
"value": 1000
},
{
"key": "getChangeDelegation",
"value": 1
},
{
"key": "getWitness127PayPerBlock",
"value": 128000000
},
{
"key": "getAllowMarketTransaction"
},
{
"key": "getMarketSellFee"
},
{
"key": "getMarketCancelFee"
},
{
"key": "getAllowPBFT"
},
{
"key": "getAllowTransactionFeePool"
},
{
"key": "getMaxFeeLimit",
"value": 15000000000
},
{
"key": "getAllowOptimizeBlackHole",
"value": 1
},
{
"key": "getAllowNewResourceModel"
},
{
"key": "getAllowTvmFreeze"
},
{
"key": "getAllowTvmVote",
"value": 1
},
{
"key": "getAllowTvmLondon",
"value": 1
},
{
"key": "getAllowTvmCompatibleEvm"
},
{
"key": "getAllowAccountAssetOptimization"
},
{
"key": "getFreeNetLimit",
"value": 600
},
{
"key": "getTotalNetLimit",
"value": 43200000000
},
{
"key": "getAllowHigherLimitForMaxCpuTimeOfOneTx",
"value": 1
},
{
"key": "getAllowAssetOptimization",
"value": 1
},
{
"key": "getAllowNewReward",
"value": 1
},
{
"key": "getMemoFee",
"value": 1000000
},
{
"key": "getAllowDelegateOptimization",
"value": 1
},
{
"key": "getUnfreezeDelayDays",
"value": 14
},
{
"key": "getAllowOptimizedReturnValueOfChainId",
"value": 1
},
{
"key": "getAllowDynamicEnergy",
"value": 1
},
{
"key": "getDynamicEnergyThreshold",
"value": 5000000000
},
{
"key": "getDynamicEnergyIncreaseFactor",
"value": 2000
},
{
"key": "getDynamicEnergyMaxFactor",
"value": 34000
},
{
"key": "getAllowTvmShangHai",
"value": 1
},
{
"key": "getAllowCancelAllUnfreezeV2",
"value": 1
},
{
"key": "getMaxDelegateLockPeriod",
"value": 864000
},
{
"key": "getAllowOldRewardOpt",
"value": 1
},
{
"key": "getAllowEnergyAdjustment",
"value": 1
},
{
"key": "getMaxCreateAccountTxSize",
"value": 1000
},
{
"key": "getAllowStrictMath",
"value": 1
},
{
"key": "getConsensusLogicOptimization",
"value": 1
},
{
"key": "getAllowTvmCancun",
"value": 1
},
{
"key": "getAllowTvmBlob",
"value": 1
},
{
"key": "getAllowTvmSelfdestructRestriction",
"value": 1
},
{
"key": "getProposalExpireTime",
"value": 259200000
},
{
"key": "getAllowTvmOsaka"
},
{
"key": "getAllowTvmPrague"
},
{
"key": "getAllowHardenResourceCalculation"
},
{
"key": "getAllowHardenExchangeCalculation"
}
]
}
Спойлер: getter_key_mapping.json
Code:
{
"getAbiMoveDone": {
"key": "ABI_MOVE_DONE",
"setter": "saveAbiMoveDone"
},
"getAccountUpgradeCost": {
"key": "ACCOUNT_UPGRADE_COST",
"setter": "saveAccountUpgradeCost"
},
"getAllowAccountAssetOptimizationFromRoot": {
"key": "ALLOW_ACCOUNT_ASSET_OPTIMIZATION",
"setter": null
},
"getAllowAccountStateRoot": {
"key": "ALLOW_ACCOUNT_STATE_ROOT",
"setter": "saveAllowAccountStateRoot"
},
"getAllowAdaptiveEnergy": {
"key": "ALLOW_ADAPTIVE_ENERGY",
"setter": "saveAllowAdaptiveEnergy"
},
"getAllowAssetOptimization": {
"key": "ALLOW_ASSET_OPTIMIZATION",
"setter": null
},
"getAllowBlackHoleOptimization": {
"key": "ALLOW_BLACKHOLE_OPTIMIZATION",
"setter": "saveAllowBlackHoleOptimization"
},
"getAllowCancelAllUnfreezeV2": {
"key": "ALLOW_CANCEL_ALL_UNFREEZE_V2",
"setter": "saveAllowCancelAllUnfreezeV2"
},
"getAllowCreationOfContracts": {
"key": "ALLOW_CREATION_OF_CONTRACTS",
"setter": "saveAllowCreationOfContracts"
},
"getAllowDelegateOptimization": {
"key": "ALLOW_DELEGATE_OPTIMIZATION",
"setter": "saveAllowDelegateOptimization"
},
"getAllowDelegateResource": {
"key": "ALLOW_DELEGATE_RESOURCE",
"setter": "saveAllowDelegateResource"
},
"getAllowDynamicEnergy": {
"key": "ALLOW_DYNAMIC_ENERGY",
"setter": "saveAllowDynamicEnergy"
},
"getAllowEnergyAdjustment": {
"key": "ALLOW_ENERGY_ADJUSTMENT",
"setter": "saveAllowEnergyAdjustment"
},
"getAllowHardenExchangeCalculation": {
"key": "ALLOW_HARDEN_EXCHANGE_CALCULATION",
"setter": "saveAllowHardenExchangeCalculation"
},
"getAllowHardenResourceCalculation": {
"key": "ALLOW_HARDEN_RESOURCE_CALCULATION",
"setter": "saveAllowHardenResourceCalculation"
},
"getAllowHigherLimitForMaxCpuTimeOfOneTx": {
"key": "ALLOW_HIGHER_LIMIT_FOR_MAX_CPU_TIME_OF_ONE_TX",
"setter": "saveAllowHigherLimitForMaxCpuTimeOfOneTx"
},
"getAllowMarketTransaction": {
"key": "ALLOW_MARKET_TRANSACTION",
"setter": "saveAllowMarketTransaction"
},
"getAllowMultiSign": {
"key": "ALLOW_MULTI_SIGN",
"setter": "saveAllowMultiSign"
},
"getAllowNewResourceModel": {
"key": "ALLOW_NEW_RESOURCE_MODEL",
"setter": "saveAllowNewResourceModel"
},
"getAllowNewReward": {
"key": "ALLOW_NEW_REWARD",
"setter": "saveAllowNewReward"
},
"getAllowOldRewardOpt": {
"key": "ALLOW_OLD_REWARD_OPT",
"setter": "saveAllowOldRewardOpt"
},
"getAllowOptimizedReturnValueOfChainId": {
"key": "ALLOW_OPTIMIZED_RETURN_VALUE_OF_CHAIN_ID",
"setter": "saveAllowOptimizedReturnValueOfChainId"
},
"getAllowPBFT": {
"key": "ALLOW_PBFT",
"setter": "saveAllowPBFT"
},
"getAllowProtoFilterNum": {
"key": "ALLOW_PROTO_FILTER_NUM",
"setter": "saveAllowProtoFilterNum"
},
"getAllowSameTokenName": {
"key": "ALLOW_SAME_TOKEN_NAME",
"setter": "saveAllowSameTokenName"
},
"getAllowShieldedTRC20Transaction": {
"key": "ALLOW_SHIELDED_TRC20_TRANSACTION",
"setter": "saveAllowShieldedTRC20Transaction"
},
"getAllowShieldedTransaction": {
"key": "ALLOW_SHIELDED_TRANSACTION",
"setter": "saveAllowShieldedTransaction"
},
"getAllowStrictMath": {
"key": "ALLOW_STRICT_MATH",
"setter": "saveAllowStrictMath"
},
"getAllowTransactionFeePool": {
"key": "ALLOW_TRANSACTION_FEE_POOL",
"setter": "saveAllowTransactionFeePool"
},
"getAllowTvmBlob": {
"key": "ALLOW_TVM_BLOB",
"setter": "saveAllowTvmBlob"
},
"getAllowTvmCancun": {
"key": "ALLOW_TVM_CANCUN",
"setter": "saveAllowTvmCancun"
},
"getAllowTvmCompatibleEvm": {
"key": "ALLOW_TVM_COMPATIBLE_EVM",
"setter": "saveAllowTvmCompatibleEvm"
},
"getAllowTvmConstantinople": {
"key": "ALLOW_TVM_CONSTANTINOPLE",
"setter": "saveAllowTvmConstantinople"
},
"getAllowTvmFreeze": {
"key": "ALLOW_TVM_FREEZE",
"setter": "saveAllowTvmFreeze"
},
"getAllowTvmIstanbul": {
"key": "ALLOW_TVM_ISTANBUL",
"setter": "saveAllowTvmIstanbul"
},
"getAllowTvmLondon": {
"key": "ALLOW_TVM_LONDON",
"setter": "saveAllowTvmLondon"
},
"getAllowTvmOsaka": {
"key": "ALLOW_TVM_OSAKA",
"setter": "saveAllowTvmOsaka"
},
"getAllowTvmPrague": {
"key": "ALLOW_TVM_PRAGUE",
"setter": "saveAllowTvmPrague"
},
"getAllowTvmSelfdestructRestriction": {
"key": "ALLOW_TVM_SELFDESTRUCT_RESTRICTION",
"setter": "saveAllowTvmSelfdestructRestriction"
},
"getAllowTvmShangHai": {
"key": "ALLOW_TVM_SHANGHAI",
"setter": "saveAllowTvmShangHai"
},
"getAllowTvmSolidity059": {
"key": "ALLOW_TVM_SOLIDITY_059",
"setter": "saveAllowTvmSolidity059"
},
"getAllowTvmTransferTrc10": {
"key": "ALLOW_TVM_TRANSFER_TRC10",
"setter": "saveAllowTvmTransferTrc10"
},
"getAllowTvmVote": {
"key": "ALLOW_TVM_VOTE",
"setter": "saveAllowTvmVote"
},
"getAllowUpdateAccountName": {
"key": "ALLOW_UPDATE_ACCOUNT_NAME",
"setter": "saveAllowUpdateAccountName"
},
"getAssetIssueFee": {
"key": "ASSET_ISSUE_FEE",
"setter": "saveAssetIssueFee"
},
"getBandwidthPriceHistory": {
"key": "BANDWIDTH_PRICE_HISTORY",
"setter": "saveBandwidthPriceHistory"
},
"getBandwidthPriceHistoryDone": {
"key": "BANDWIDTH_PRICE_HISTORY_DONE",
"setter": "saveBandwidthPriceHistoryDone"
},
"getBlockFilledSlotsIndex": {
"key": "BLOCK_FILLED_SLOTS_INDEX",
"setter": "saveBlockFilledSlotsIndex"
},
"getBlockFilledSlotsNumber": {
"key": "LATEST_SOLIDIFIED_BLOCK_NUM",
"setter": null
},
"getBlockHashHistoryInstalled": {
"key": "BLOCK_HASH_HISTORY_INSTALLED",
"setter": "saveBlockHashHistoryInstalled"
},
"getBurnTrxAmount": {
"key": "BURN_TRX_AMOUNT",
"setter": null
},
"getChangeDelegation": {
"key": "ALLOW_CHANGE_DELEGATION",
"setter": "saveChangeDelegation"
},
"getConsensusLogicOptimization": {
"key": "CONSENSUS_LOGIC_OPTIMIZATION",
"setter": "saveConsensusLogicOptimization"
},
"getCreateAccountFee": {
"key": "CREATE_ACCOUNT_FEE",
"setter": "saveCreateAccountFee"
},
"getCreateNewAccountBandwidthRate": {
"key": "CREATE_NEW_ACCOUNT_BANDWIDTH_RATE",
"setter": "saveCreateNewAccountBandwidthRate"
},
"getCreateNewAccountFeeInSystemContract": {
"key": "CREATE_NEW_ACCOUNT_FEE_IN_SYSTEM_CONTRACT",
"setter": "saveCreateNewAccountFeeInSystemContract"
},
"getCurrentCycleNumber": {
"key": "CURRENT_CYCLE_NUMBER",
"setter": "saveCurrentCycleNumber"
},
"getDynamicEnergyIncreaseFactor": {
"key": "DYNAMIC_ENERGY_INCREASE_FACTOR",
"setter": "saveDynamicEnergyIncreaseFactor"
},
"getDynamicEnergyMaxFactor": {
"key": "DYNAMIC_ENERGY_MAX_FACTOR",
"setter": "saveDynamicEnergyMaxFactor"
},
"getDynamicEnergyThreshold": {
"key": "DYNAMIC_ENERGY_THRESHOLD",
"setter": "saveDynamicEnergyThreshold"
},
"getEnergyPriceHistory": {
"key": "ENERGY_PRICE_HISTORY",
"setter": "saveEnergyPriceHistory"
},
"getEnergyPriceHistoryDone": {
"key": "ENERGY_PRICE_HISTORY_DONE",
"setter": "saveEnergyPriceHistoryDone"
},
"getExchangeBalanceLimit": {
"key": "EXCHANGE_BALANCE_LIMIT",
"setter": "saveExchangeBalanceLimit"
},
"getExchangeCreateFee": {
"key": "EXCHANGE_CREATE_FEE",
"setter": "saveExchangeCreateFee"
},
"getForbidTransferToContract": {
"key": "FORBID_TRANSFER_TO_CONTRACT",
"setter": "saveForbidTransferToContract"
},
"getLatestBlockHeaderHash": {
"key": "LATEST_BLOCK_HEADER_HASH",
"setter": "saveLatestBlockHeaderHash"
},
"getLatestBlockHeaderNumber": {
"key": "LATEST_BLOCK_HEADER_NUMBER",
"setter": "saveLatestBlockHeaderNumber"
},
"getLatestBlockHeaderNumberFromDB": {
"key": "STATE_FLAG",
"setter": null
},
"getLatestBlockHeaderTimestamp": {
"key": "LATEST_BLOCK_HEADER_TIMESTAMP",
"setter": "saveLatestBlockHeaderTimestamp"
},
"getLatestExchangeNum": {
"key": "LATEST_EXCHANGE_NUM",
"setter": "saveLatestExchangeNum"
},
"getLatestProposalNum": {
"key": "LATEST_PROPOSAL_NUM",
"setter": "saveLatestProposalNum"
},
"getMaintenanceSkipSlots": {
"key": "VERSION_NUMBER",
"setter": null
},
"getMaintenanceTimeInterval": {
"key": "MAINTENANCE_TIME_INTERVAL",
"setter": "saveMaintenanceTimeInterval"
},
"getMarketCancelFee": {
"key": "MARKET_CANCEL_FEE",
"setter": "saveMarketCancelFee"
},
"getMarketQuantityLimit": {
"key": "MARKET_QUANTITY_LIMIT",
"setter": "saveMarketQuantityLimit"
},
"getMarketSellFee": {
"key": "MARKET_SELL_FEE",
"setter": "saveMarketSellFee"
},
"getMaxCpuTimeOfOneTx": {
"key": "MAX_CPU_TIME_OF_ONE_TX",
"setter": "saveMaxCpuTimeOfOneTx"
},
"getMaxCreateAccountTxSize": {
"key": "MAX_CREATE_ACCOUNT_TX_SIZE",
"setter": "saveMaxCreateAccountTxSize"
},
"getMaxDelegateLockPeriod": {
"key": "MAX_DELEGATE_LOCK_PERIOD",
"setter": "saveMaxDelegateLockPeriod"
},
"getMaxFeeLimit": {
"key": "MAX_FEE_LIMIT",
"setter": "saveMaxFeeLimit"
},
"getMaxFrozenSupplyNumber": {
"key": "MAX_FROZEN_SUPPLY_NUMBER",
"setter": "saveMaxFrozenSupplyNumber"
},
"getMaxFrozenSupplyTime": {
"key": "MAX_FROZEN_SUPPLY_TIME",
"setter": "saveMaxFrozenSupplyTime"
},
"getMaxFrozenTime": {
"key": "MAX_FROZEN_TIME",
"setter": "saveMaxFrozenTime"
},
"getMemoFee": {
"key": "MEMO_FEE",
"setter": "saveMemoFee"
},
"getMemoFeeHistory": {
"key": "MEMO_FEE_HISTORY",
"setter": "saveMemoFeeHistory"
},
"getMinFrozenSupplyTime": {
"key": "MIN_FROZEN_SUPPLY_TIME",
"setter": "saveMinFrozenSupplyTime"
},
"getMinFrozenTime": {
"key": "MIN_FROZEN_TIME",
"setter": "saveMinFrozenTime"
},
"getMultiSignFee": {
"key": "MULTI_SIGN_FEE",
"setter": "saveMultiSignFee"
},
"getNewRewardAlgorithmEffectiveCycle": {
"key": "NEW_REWARD_ALGORITHM_EFFECTIVE_CYCLE",
"setter": "saveNewRewardAlgorithmEffectiveCycle"
},
"getNextMaintenanceTime": {
"key": "NEXT_MAINTENANCE_TIME",
"setter": "saveNextMaintenanceTime"
},
"getOneDayNetLimit": {
"key": "ENERGY_FEE",
"setter": "saveOneDayNetLimit"
},
"getProposalExpireTime": {
"key": "PROPOSAL_EXPIRE_TIME",
"setter": "saveProposalExpireTime"
},
"getRemoveThePowerOfTheGr": {
"key": "REMOVE_THE_POWER_OF_THE_GR",
"setter": "saveRemoveThePowerOfTheGr"
},
"getSetBlackholeAccountPermission": {
"key": "SET_BLACKHOLE_ACCOUNT_PERMISSION",
"setter": null
},
"getShieldedTransactionCreateAccountFee": {
"key": "SHIELDED_TRANSACTION_CREATE_ACCOUNT_FEE",
"setter": "saveShieldedTransactionCreateAccountFee"
},
"getShieldedTransactionFee": {
"key": "SHIELDED_TRANSACTION_FEE",
"setter": "saveShieldedTransactionFee"
},
"getStorageExchangeTaxRate": {
"key": "STORAGE_EXCHANGE_TAX_RATE",
"setter": "saveStorageExchangeTaxRate"
},
"getTokenIdNum": {
"key": "TOKEN_ID_NUM",
"setter": "saveTokenIdNum"
},
"getTokenUpdateDone": {
"key": "TOKEN_UPDATE_DONE",
"setter": "saveTokenUpdateDone"
},
"getTotalCreateAccountCost": {
"key": "TOTAL_CREATE_ACCOUNT_COST",
"setter": null
},
"getTotalCreateWitnessCost": {
"key": "TOTAL_CREATE_WITNESS_COST",
"setter": null
},
"getTotalShieldedPoolValue": {
"key": "TOTAL_SHIELDED_POOL_VALUE",
"setter": "saveTotalShieldedPoolValue"
},
"getTotalSignNum": {
"key": "TOTAL_SIGN_NUM",
"setter": "saveTotalSignNum"
},
"getTotalStoragePool": {
"key": "TOTAL_STORAGE_POOL",
"setter": "saveTotalStoragePool"
},
"getTotalStorageReserved": {
"key": "TOTAL_STORAGE_RESERVED",
"setter": "saveTotalStorageReserved"
},
"getTotalStorageTax": {
"key": "TOTAL_STORAGE_TAX",
"setter": "saveTotalStorageTax"
},
"getTotalTransactionCost": {
"key": "TOTAL_TRANSACTION_COST",
"setter": "saveTotalTransactionCost"
},
"getTransactionFee": {
"key": "TRANSACTION_FEE",
"setter": "saveTransactionFee"
},
"getTransactionFeePool": {
"key": "TRANSACTION_FEE_POOL",
"setter": "saveTransactionFeePool"
},
"getTurkishKeyMigrationDone": {
"key": "TURKISH_KEY_MIGRATION_DONE",
"setter": "saveTurkishKeyMigrationDone"
},
"getUnfreezeDelayDays": {
"key": "UNFREEZE_DELAY_DAYS",
"setter": "saveUnfreezeDelayDays"
},
"getUpdateAccountPermissionFee": {
"key": "UPDATE_ACCOUNT_PERMISSION_FEE",
"setter": "saveUpdateAccountPermissionFee"
},
"getWitness127PayPerBlock": {
"key": "WITNESS_127_PAY_PER_BLOCK",
"setter": "saveWitness127PayPerBlock"
},
"getWitnessAllowanceFrozenTime": {
"key": "WITNESS_ALLOWANCE_FROZEN_TIME",
"setter": "saveWitnessAllowanceFrozenTime"
},
"getWitnessPayPerBlock": {
"key": "WITNESS_PAY_PER_BLOCK",
"setter": "saveWitnessPayPerBlock"
},
"getWitnessStandbyAllowance": {
"key": "WITNESS_STANDBY_ALLOWANCE",
"setter": "saveWitnessStandbyAllowance"
},
"getAdaptiveResourceLimitMultiplier": {
"key": "ADAPTIVE_RESOURCE_LIMIT_MULTIPLIER",
"setter": "saveAdaptiveResourceLimitMultiplier"
},
"getAdaptiveResourceLimitTargetRatio": {
"key": "ADAPTIVE_RESOURCE_LIMIT_TARGET_RATIO",
"setter": "saveAdaptiveResourceLimitTargetRatio"
},
"getAllowAccountAssetOptimization": {
"key": "ALLOW_ACCOUNT_ASSET_OPTIMIZATION",
"setter": "saveAllowAccountAssetOptimization"
},
"getAllowOptimizeBlackHole": {
"key": "ALLOW_BLACKHOLE_OPTIMIZATION",
"setter": "saveAllowBlackHoleOptimization"
},
"getEnergyFee": {
"key": "ENERGY_FEE",
"setter": "saveEnergyFee"
},
"getFreeNetLimit": {
"key": "FREE_NET_LIMIT",
"setter": "saveFreeNetLimit"
},
"getTotalEnergyAverageUsage": {
"key": "TOTAL_ENERGY_AVERAGE_USAGE",
"setter": "saveTotalEnergyAverageUsage"
},
"getTotalEnergyCurrentLimit": {
"key": "TOTAL_ENERGY_CURRENT_LIMIT",
"setter": "saveTotalEnergyCurrentLimit"
},
"getTotalEnergyLimit": {
"key": "TOTAL_ENERGY_LIMIT",
"setter": "saveTotalEnergyLimit"
},
"getTotalEnergyTargetLimit": {
"key": "TOTAL_ENERGY_TARGET_LIMIT",
"setter": "saveTotalEnergyTargetLimit"
},
"getTotalNetLimit": {
"key": "TOTAL_NET_LIMIT",
"setter": "saveTotalNetLimit"
}
}
Спойлер: updateparams.py
Code:
import json
import os
import requests
# Пути к файлам конфигурации относительно текущей директории
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CHAIN_PARAMS_PATH = os.path.join(BASE_DIR, "../data/mainet_chainparameters.json")
MAPPING_PATH = os.path.join(BASE_DIR, "../data/getter_key_mapping.json")
# URL эндпоинта java-tron
URL = "http://localhost:8090/wallet/updateproposalparameter"
HEADERS = {"Content-Type": "application/json"}
def load_json(file_path: str) -> dict:
if not os.path.exists(file_path):
raise FileNotFoundError(f"Файл не найден по пути: {file_path}")
with open(file_path, "r", encoding="utf-8") as f:
return json.load(f)
def main():
chain_params_data = load_json(CHAIN_PARAMS_PATH)
mapping_data = load_json(MAPPING_PATH)
chain_parameters = chain_params_data.get("chainParameter", [])
print(f"Загружено {len(chain_parameters)} параметров из {CHAIN_PARAMS_PATH}\n")
success_count = 0
skipped_count = 0
error_count = 0
for item in chain_parameters:
getter_name = item.get("key")
value = item.get("value")
if not getter_name:
continue
# Ищем соответствие геттера (например, "getAccountUpgradeCost") в маппинге
mapping_info = mapping_data.get(getter_name)
if not mapping_info or not mapping_info.get("key"):
print(f"[SKIPPED] Пропущен геттер '{getter_name}': не найден ключ в getter_key_mapping.json")
skipped_count += 1
continue
proposal_key = mapping_info["key"]
payload = {"key": proposal_key, "value": value}
try:
response = requests.post(URL, json=payload, headers=HEADERS, timeout=10)
if response.status_code == 200:
print(f"[OK] {getter_name} -> '{proposal_key}': {value} | Ответ: {response.text.strip()}")
success_count += 1
else:
print(f"[ERROR] {getter_name} -> '{proposal_key}': {value} | HTTP {response.status_code}: {response.text.strip()}")
error_count += 1
except requests.exceptions.RequestException as e:
print(f"[FAIL] Ошибка при отправке {proposal_key}: {e}")
error_count += 1
print("\n" + "=" * 40)
print(f"Итог: Успешно: {success_count} | Пропущено: {skipped_count} | Ошибок: {error_count}")
if __name__ == "__main__":
main()
Потом советую добавить HTTP прокси-логгер. Будет удобно.
Спойлер: docker-compose.yml
Code:
tron-proxy:
image: mitmproxy/mitmproxy:latest
container_name: tron-proxy
networks:
- tron_private_network
ports:
- "9090:8080"
volumes:
- ./logger/log_compact.py:/log_compact.py:ro
command: ["mitmdump", "-q", "--mode", "reverse:http://tron-witness1:8090", "-s", "/log_compact.py"]
depends_on:
- tron-witness1
Спойлер: logger.py
Code:
import json
from mitmproxy import http
MAX_STRING_LEN = 100 # Максимальная длина строки
# ANSI-коды для цветов
COLOR_GREEN = "\033[92m"
COLOR_PINK = "\033[95m"
COLOR_RESET = "\033[0m"
def truncate_strings(data, max_len=MAX_STRING_LEN):
"""Рекурсивно обрезает слишком длинные строки в JSON-структуре."""
if isinstance(data, dict):
return {k: truncate_strings(v, max_len) for k, v in data.items()}
elif isinstance(data, list):
return [truncate_strings(item, max_len) for item in data]
elif isinstance(data, str) and len(data) > max_len:
return data[:max_len] + "..."
return data
def format_body(content: bytes) -> str:
"""Парсит body, рекурсивно обрезает длинные поля и форматирует обратно в JSON."""
if not content:
return "EMPTY"
text = content.decode("utf-8", errors="replace").strip()
if not text:
return "EMPTY"
try:
data = json.loads(text)
truncated_data = truncate_strings(data)
return json.dumps(truncated_data, ensure_ascii=False)
except Exception:
# Если тело запроса/ответа — не JSON, а обычный текст
if len(text) > MAX_STRING_LEN:
return text[:MAX_STRING_LEN] + "..."
return text
def response(flow: http.HTTPFlow) -> None:
req_body = format_body(flow.request.content)
resp_body = format_body(flow.response.content)
path = flow.request.path
method = flow.request.method
status = flow.response.status_code
req_out = f"{COLOR_GREEN}REQ: {req_body}{COLOR_RESET}"
resp_out = f"{COLOR_PINK}RESP: {resp_body}{COLOR_RESET}"
print(
f"{method} {path} -> {status}\n"
f"{req_out}\n"
f"{resp_out}",
flush=True,
)
Проблема 2: А как деплоить?
Теперь когда тестнет готов остается только вопрос - "через какой интерфейс его использовать?". Никакого кода я тут давать не буду, просто обрисую как это должно выглядеть по-человечески.
Мы хотим писать наши плэйбуки/тесты/эксперименты (в общем то, что подразумевает под собой множественный деплой и вызов самрт-контрактов) декларативно через удобный формат типо
.yaml. Мы хотим видеть IaC интерфейс со своим стейтом, чтобы шаги не выполнялись заново при каждом новом вызове. В общем, что-то типо
Terraform или Hardhat Ignition.Архитектура примерно такая:
java-tron node <-- client (TronWeb) <-- playbook engine <-- .yaml
На этом всё. Давайте фидбек кто чем занимается, какие проблемы, какие успехи. Тут мало кто про крипту пишет.
👍41
❤️7
👏3
😢12
LIMB