I’m running a Lite Full Node (Java-Tron) inside Docker, based on the official tronprotocol/java-tron:latest image.
The node successfully connects to my bridge peer and receives new blocks.
During runtime, I can see in the logs that it processes and stores incoming blocks correctly:
INFO [sync-handle-block] Save block: BlockCapsule [number=76753130, txs size=150]
INFO [sync-handle-block] PushBlock block number: 76753130, cost/txs: 2023/150 true
INFO [sync-handle-block] Success process block Num:76753130
The new block files are also written to output-directory/database/block/ inside the container.
The node should persist the latest head block (and possibly the last ~65,536 blocks window)
even after restart — since they are already written to LevelDB under output-directory/database/block/.
After restarting the container, the node reloads only the original snapshot range
and ignores the blocks that were added after startup.
It always resets headNum to the snapshot’s head (76753126).
Is this behavior expected for Lite Full Nodes (i.e., it always reverts to the snapshot window)?
Or should a Lite Full Node keep the newly received blocks on disk and continue from the latest synced height after restart?
If it’s expected — is there any configuration or flag that allows a Lite Node to “extend” the snapshot window forward and retain those new blocks?
net {
type = mainnet
# type = testnet
}
storage {
# Directory for storing persistent data
db.engine = "LEVELDB",
db.sync = false,
db.directory = "database",
index.directory = "index",
transHistory.switch = "off",
# You can custom these 14 databases' configs:
# account, account-index, asset-issue, block, block-index,
# block_KDB, peers, properties, recent-block, trans,
# utxo, votes, witness, witness_schedule.
# Otherwise, db configs will remain default and data will be stored in
# the path of "output-directory" or which is set by "-d" ("--output-directory").
# setting can impove leveldb performance .... start
# node: if this will increase process fds,you may be check your ulimit if 'too many open files' error occurs
# see https://github.com/tronprotocol/tips/blob/master/tip-343.md for detail
# if you find block sync has lower performance,you can try this settings
#default = {
# maxOpenFiles = 100
#}
#defaultM = {
# maxOpenFiles = 500
#}
#defaultL = {
# maxOpenFiles = 1000
#}
# setting can impove leveldb performance .... end
# Attention: name is a required field that must be set !!!
properties = [
// {
// name = "account",
// path = "storage_directory_test",
// createIfMissing = true,
// paranoidChecks = true,
// verifyChecksums = true,
// compressionType = 1, // compressed with snappy
// blockSize = 4096, // 4 KB = 4 * 1024 B
// writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
// cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
// maxOpenFiles = 100
// },
// {
// name = "account-index",
// path = "storage_directory_test",
// createIfMissing = true,
// paranoidChecks = true,
// verifyChecksums = true,
// compressionType = 1, // compressed with snappy
// blockSize = 4096, // 4 KB = 4 * 1024 B
// writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
// cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
// maxOpenFiles = 100
// },
]
needToUpdateAsset = true
//dbsettings is needed when using rocksdb as the storage implement (db.engine="ROCKSDB").
//we'd strongly recommend that do not modify it unless you know every item's meaning clearly.
dbSettings = {
levelNumber = 7
//compactThreads = 32
blocksize = 64 // n * KB
maxBytesForLevelBase = 256 // n * MB
maxBytesForLevelMultiplier = 10
level0FileNumCompactionTrigger = 4
targetFileSizeBase = 256 // n * MB
targetFileSizeMultiplier = 1
}
//backup settings when using rocks db as the storage implement (db.engine="ROCKSDB").
//if you want to use the backup plugin, please confirm set the db.engine="ROCKSDB" above.
backup = {
enable = false // indicate whether enable the backup plugin
propPath = "prop.properties" // record which bak directory is valid
bak1path = "bak1/database" // you must set two backup directories to prevent application halt unexpected(e.g. kill -9).
bak2path = "bak2/database"
frequency = 10000 // indicate backup db once every 10000 blocks processed.
}
balance.history.lookup = false
# checkpoint.version = 2
# checkpoint.sync = true
# the estimated number of block transactions (default 1000, min 100, max 10000).
# so the total number of cached transactions is 65536 * txCache.estimatedTransactions
txCache.estimatedTransactions = 200
# if true, transaction cache initialization will be faster. default false
txCache.initOptimization = true
# data root setting, for check data, currently, only reward-vi is used.
# merkleRoot = {
# reward-vi = 9debcb9924055500aaae98cdee10501c5c39d4daa75800a996f4bdda73dbccd8 // main-net, Sha256Hash, hexString
# }
}
node.discovery = {
enable = false
persist = false
}
# custom stop condition
#node.shutdown = {
# BlockTime = "54 59 08 * * ?" # if block header time in persistent db matched.
# BlockHeight = 33350800 # if block header height in persistent db matched.
# BlockCount = 12 # block sync count after node start.
#}
node.backup {
# my priority, each member should use different priority
priority = 8
# udp listen port, each member should have the save configuration
port = 10001
# time interval to send keepAlive message, each member should have the save configuration
keepAliveInterval = 3000
# peer's ip list, can't contain mine
members = [
# "ip",
# "ip"
]
}
crypto {
engine = "eckey"
}
# prometheus metrics start
# node.metrics = {
# prometheus{
# enable=true
# port="9527"
# }
# }
# prometheus metrics end
node {
# trust node for solidity node
# trustNode = "ip:port"
trustNode = "127.0.0.1:50051"
# expose extension api to public or not
walletExtensionApi = true
listen.port = 18888
connection.timeout = 2
fetchBlock.timeout = 200
tcpNettyWorkThreadNum = 0
udpNettyWorkThreadNum = 1
maxConnections = 30
minConnections = 8
minActiveConnections = 3
# Number of validate sign thread, default availableProcessors / 2
# validateSignThreadNum = 16
maxConnectionsWithSameIp = 2
maxHttpConnectNumber = 50
minParticipationRate = 15
isOpenFullTcpDisconnect = true
inactiveThreshold = 0 //seconds
p2p {
version = 11111 # 11111: mainnet; 20180622: testnet
}
active = [
# Active establish connection in any case
# Sample entries:
# "ip:port",
# "ip:port"
"192.168.28.133:18889"
]
passive = [
# Passive accept connection in any case
# Sample entries:
# "ip:port",
# "192.168.28.133:18889"
]
fastForward = [
#"100.27.171.62:18888",
# "192.168.28.133:18889"
]
http {
fullNodeEnable = true
fullNodePort = 8090
solidityEnable = true
solidityPort = 8091
PBFTEnable = true
PBFTPort = 8092
}
# use your ipv6 address for node discovery and tcp connection, default false
enableIpv6 = false
# if your node's highest block num is below than all your pees', try to acquire new connection. default false
effectiveCheckEnable = false
dns {
# dns urls to get nodes, url format tree://{pubkey}@{domain}, default empty
treeUrls = [
# "tree://AKMQMNAJJBL73LXWPXDI4I5ZWWIZ4AWO34DWQ636QOBBXNFXH3LQS@main.trondisco.net",
]
}
rpc {
enable = true
port = 50051
solidityEnable = true
solidityPort = 50061
PBFTEnable = true
PBFTPort = 50071
# Number of gRPC thread, default availableProcessors / 2
# thread = 16
# The maximum number of concurrent calls permitted for each incoming connection
# maxConcurrentCallsPerConnection =
# The HTTP/2 flow control window, default 1MB
# flowControlWindow =
# Connection being idle for longer than which will be gracefully terminated
maxConnectionIdleInMillis = 60000
# Connection lasting longer than which will be gracefully terminated
# maxConnectionAgeInMillis =
# The maximum message size allowed to be received on the server, default 4MB
# maxMessageSize =
# The maximum size of header list allowed to be received, default 8192
# maxHeaderListSize =
# Transactions can only be broadcast if the number of effective connections is reached.
minEffectiveConnection = 1
# The switch of the reflection service, effective for all gRPC services
# reflectionService = true
}
# number of solidity thread in the FullNode.
# If accessing solidity rpc and http interface timeout, could increase the number of threads,
# The default value is the number of cpu cores of the machine.
#solidity.threads = 8
# Limits the maximum percentage (default 75%) of producing block interval
# to provide sufficient time to perform other operations e.g. broadcast block
# blockProducedTimeOut = 75
# Limits the maximum number (default 700) of transaction from network layer
# netMaxTrxPerSecond = 700
# open the history query APIs(http&GRPC) when node is a lite fullNode,
# like {getBlockByNum, getBlockByID, getTransactionByID...}.
# default: false.
# 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 = true
jsonrpc {
# Note: If you turn on jsonrpc and run it for a while and then turn it off, you will not
# be able to get the data from eth_getLogs for that period of time.
# httpFullNodeEnable = true
# httpFullNodePort = 8545
# httpSolidityEnable = true
# httpSolidityPort = 8555
# httpPBFTEnable = true
# httpPBFTPort = 8565
# The maximum blocks range to retrieve logs for eth_getLogs, default value is 5000,
# should be > 0, otherwise means no limit.
# maxBlockRange = 5000
# The maximum number of allowed topics within a topic criteria, default value is 1000,
# should be > 0, otherwise means no limit.
# maxSubTopics = 1000
}
# 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
rate.limiter = {
# Every api could be set a specific rate limit strategy. Three strategy are supported:GlobalPreemptibleAdapter、IPQPSRateLimiterAdapte、QpsRateLimiterAdapter
# GlobalPreemptibleAdapter: permit is the number of preemptible resource, every client must apply one resourse
# before do the request and release the resource after got the reponse automaticlly. permit should be a Integer.
# QpsRateLimiterAdapter: qps is the average request count in one second supported by the server, it could be a Double or a Integer.
# IPQPSRateLimiterAdapter: similar to the QpsRateLimiterAdapter, qps could be a Double or a Integer.
# If do not set, the "default strategy" is set.The "default startegy" is based on QpsRateLimiterAdapter, the qps is set as 10000.
#
# Sample entries:
#
http = [
# {
# component = "GetNowBlockServlet",
# strategy = "GlobalPreemptibleAdapter",
# paramString = "permit=1"
# },
# {
# component = "GetAccountServlet",
# strategy = "IPQPSRateLimiterAdapter",
# paramString = "qps=1"
# },
# {
# component = "ListWitnessesServlet",
# strategy = "QpsRateLimiterAdapter",
# paramString = "qps=1"
# }
],
rpc = [
# {
# component = "protocol.Wallet/GetBlockByLatestNum2",
# strategy = "GlobalPreemptibleAdapter",
# paramString = "permit=1"
# },
# {
# component = "protocol.Wallet/GetAccount",
# strategy = "IPQPSRateLimiterAdapter",
# paramString = "qps=1"
# },
# {
# component = "protocol.Wallet/ListWitnesses",
# strategy = "QpsRateLimiterAdapter",
# paramString = "qps=1"
# },
]
}
seed.node = {
# List of the seed nodes
# Seed nodes are stable full nodes
# example:
# ip.list = [
# "ip:port",
# "ip:port"
# ]
ip.list = [
# "54.236.37.243:18888",
# "52.53.189.99:18888",
# "18.196.99.16:18888",
# "34.253.187.192:18888",
# "52.56.56.149:18888",
# "35.180.51.163:18888",
# "54.252.224.209:18888",
# "18.228.15.36:18888",
# "52.15.93.92:18888",
# "34.220.77.106:18888",
# "13.127.47.162:18888",
# "13.124.62.58:18888",
# "54.151.226.240:18888",
# "35.174.93.198:18888",
# "18.210.241.149:18888",
# "54.177.115.127:18888",
# "54.254.131.82:18888",
# "18.167.171.167:18888",
# "54.167.11.177:18888",
# "35.74.7.196:18888",
# "52.196.244.176:18888",
# "54.248.129.19:18888",
# "43.198.142.160:18888",
# "3.0.214.7:18888",
# "54.153.59.116:18888",
# "54.153.94.160:18888",
# "54.82.161.39:18888",
# "54.179.207.68:18888",
# "18.142.82.44:18888",
# "18.163.230.203:18888"
]
}
genesis.block = {
# Reserve balance
assets = [
{
accountName = "Zion"
accountType = "AssetIssue"
address = "TLLM21wteSPs4hKjbxgmH1L6poyMjeTbHm"
balance = "99000000000000000"
},
{
accountName = "Sun"
accountType = "AssetIssue"
address = "TXmVpin5vq5gdZsciyyjdZgKRUju4st1wM"
balance = "0"
},
{
accountName = "Blackhole"
accountType = "AssetIssue"
address = "TLsV52sRDL79HXGGm9yzwKibb6BeruhUzy"
balance = "-9223372036854775808"
}
]
witnesses = [
{
address: THKJYuUmMKKARNf7s2VT51g5uPY6KEqnat,
url = "http://GR1.com",
voteCount = 100000026
},
{
address: TVDmPWGYxgi5DNeW8hXrzrhY8Y6zgxPNg4,
url = "http://GR2.com",
voteCount = 100000025
},
{
address: TWKZN1JJPFydd5rMgMCV5aZTSiwmoksSZv,
url = "http://GR3.com",
voteCount = 100000024
},
{
address: TDarXEG2rAD57oa7JTK785Yb2Et32UzY32,
url = "http://GR4.com",
voteCount = 100000023
},
{
address: TAmFfS4Tmm8yKeoqZN8x51ASwdQBdnVizt,
url = "http://GR5.com",
voteCount = 100000022
},
{
address: TK6V5Pw2UWQWpySnZyCDZaAvu1y48oRgXN,
url = "http://GR6.com",
voteCount = 100000021
},
{
address: TGqFJPFiEqdZx52ZR4QcKHz4Zr3QXA24VL,
url = "http://GR7.com",
voteCount = 100000020
},
{
address: TC1ZCj9Ne3j5v3TLx5ZCDLD55MU9g3XqQW,
url = "http://GR8.com",
voteCount = 100000019
},
{
address: TWm3id3mrQ42guf7c4oVpYExyTYnEGy3JL,
url = "http://GR9.com",
voteCount = 100000018
},
{
address: TCvwc3FV3ssq2rD82rMmjhT4PVXYTsFcKV,
url = "http://GR10.com",
voteCount = 100000017
},
{
address: TFuC2Qge4GxA2U9abKxk1pw3YZvGM5XRir,
url = "http://GR11.com",
voteCount = 100000016
},
{
address: TNGoca1VHC6Y5Jd2B1VFpFEhizVk92Rz85,
url = "http://GR12.com",
voteCount = 100000015
},
{
address: TLCjmH6SqGK8twZ9XrBDWpBbfyvEXihhNS,
url = "http://GR13.com",
voteCount = 100000014
},
{
address: TEEzguTtCihbRPfjf1CvW8Euxz1kKuvtR9,
url = "http://GR14.com",
voteCount = 100000013
},
{
address: TZHvwiw9cehbMxrtTbmAexm9oPo4eFFvLS,
url = "http://GR15.com",
voteCount = 100000012
},
{
address: TGK6iAKgBmHeQyp5hn3imB71EDnFPkXiPR,
url = "http://GR16.com",
voteCount = 100000011
},
{
address: TLaqfGrxZ3dykAFps7M2B4gETTX1yixPgN,
url = "http://GR17.com",
voteCount = 100000010
},
{
address: TX3ZceVew6yLC5hWTXnjrUFtiFfUDGKGty,
url = "http://GR18.com",
voteCount = 100000009
},
{
address: TYednHaV9zXpnPchSywVpnseQxY9Pxw4do,
url = "http://GR19.com",
voteCount = 100000008
},
{
address: TCf5cqLffPccEY7hcsabiFnMfdipfyryvr,
url = "http://GR20.com",
voteCount = 100000007
},
{
address: TAa14iLEKPAetX49mzaxZmH6saRxcX7dT5,
url = "http://GR21.com",
voteCount = 100000006
},
{
address: TBYsHxDmFaRmfCF3jZNmgeJE8sDnTNKHbz,
url = "http://GR22.com",
voteCount = 100000005
},
{
address: TEVAq8dmSQyTYK7uP1ZnZpa6MBVR83GsV6,
url = "http://GR23.com",
voteCount = 100000004
},
{
address: TRKJzrZxN34YyB8aBqqPDt7g4fv6sieemz,
url = "http://GR24.com",
voteCount = 100000003
},
{
address: TRMP6SKeFUt5NtMLzJv8kdpYuHRnEGjGfe,
url = "http://GR25.com",
voteCount = 100000002
},
{
address: TDbNE1VajxjpgM5p7FyGNDASt3UVoFbiD3,
url = "http://GR26.com",
voteCount = 100000001
},
{
address: TLTDZBcPoJ8tZ6TTEeEqEvwYFk2wgotSfD,
url = "http://GR27.com",
voteCount = 100000000
}
]
timestamp = "0" #2017-8-26 12:00:00
parentHash = "0xe58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f"
}
// Optional.The default is empty.
// It is used when the witness account has set the witnessPermission.
// When it is not empty, the localWitnessAccountAddress represents the address of the witness account,
// and the localwitness is configured with the private key of the witnessPermissionAddress in the witness account.
// When it is empty,the localwitness is configured with the private key of the witness account.
//localWitnessAccountAddress =
localwitness = [
]
#localwitnesskeystore = [
# "localwitnesskeystore.json"
#]
block = {
needSyncCheck = true
maintenanceTimeInterval = 21600000
proposalExpireTime = 259200000 // 3 day: 259200000(ms)
}
# Transaction reference block, default is "solid", configure to "head" may accur TaPos error
# trx.reference.block = "solid" // head;solid;
# This property sets the number of milliseconds after the creation of the transaction that is expired, default value is 60000.
# trx.expiration.timeInMilliseconds = 60000
vm = {
supportConstant = false
maxEnergyLimitForConstant = 100000000
minTimeRatio = 0.0
maxTimeRatio = 5.0
saveInternalTx = false
# Indicates whether the node stores featured internal transactions, such as freeze, vote and so on
# saveFeaturedInternalTx = false
# Indicates whether the node stores the details of the internal transactions generated by the CANCELALLUNFREEZEV2 opcode, such as bandwidth/energy/tronpower cancel amount.
# saveCancelAllUnfreezeV2Details = false
# In rare cases, transactions that will be within the specified maximum execution time (default 10(ms)) are re-executed and packaged
# longRunningTime = 10
# Indicates whether the node support estimate energy API.
# estimateEnergy = false
# Indicates the max retry time for executing transaction in estimating energy.
# estimateEnergyMaxRetry = 3
}
committee = {
allowCreationOfContracts = 0 //mainnet:0 (reset by committee),test:1
allowAdaptiveEnergy = 0 //mainnet:0 (reset by committee),test:1
}
event.subscribe = {
native = {
useNativeQueue = true // if true, use native message queue, else use event plugin.
bindport = 5555 // bind port
sendqueuelength = 1000 //max length of send queue
}
path = "" // absolute path of plugin
server = "" // target server address to receive event triggers
dbconfig = "" // dbname|username|password
contractParse = true,
topics = [
{
triggerName = "block" // block trigger, the value can't be modified
enable = false
topic = "block" // plugin topic, the value could be modified
},
{
triggerName = "transaction"
enable = false
topic = "transaction"
},
{
triggerName = "contractevent"
enable = false
topic = "contractevent"
},
{
triggerName = "contractlog"
enable = false
topic = "contractlog"
},
{
triggerName = "solidity" // solidity block event trigger, the value can't be modified
enable = true // the default value is true
topic = "solidity"
},
{
triggerName = "solidityevent"
enable = false
topic = "solidityevent"
},
{
triggerName = "soliditylog"
enable = false
topic = "soliditylog"
}
]
filter = {
fromblock = "" // the value could be "", "earliest" or a specified block number as the beginning of the queried range
toblock = "" // the value could be "", "latest" or a specified block number as end of the queried range
contractAddress = [
"" // contract address you want to subscribe, if it's set to "", you will receive contract logs/events with any contract address.
]
contractTopic = [
"" // contract topic you want to subscribe, if it's set to "", you will receive contract logs/events with any contract topic.
]
}
}
Hi everyone,
I’m running a Lite Full Node (Java-Tron) inside Docker, based on the official tronprotocol/java-tron:latest image.
The node successfully connects to my bridge peer and receives new blocks.
During runtime, I can see in the logs that it processes and stores incoming blocks correctly:
INFO [sync-handle-block] Save block: BlockCapsule [number=76753130, txs size=150]
INFO [sync-handle-block] PushBlock block number: 76753130, cost/txs: 2023/150 true
INFO [sync-handle-block] Success process block Num:76753130
The new block files are also written to output-directory/database/block/ inside the container.
However — after stopping and restarting the Docker container,
the node always resets back to the same snapshot height:
Current headNum is: 76753126
Node type is: lite
Lite node lowestNum: 76687591
So even though it had already synced up to block 76753130 (and beyond),
after restart it loads the snapshot again and starts from 76753126.
Expected behavior:
The node should persist the latest head block (and possibly the last ~65,536 blocks window)
even after restart — since they are already written to LevelDB under output-directory/database/block/.
Actual behavior
After restarting the container, the node reloads only the original snapshot range
and ignores the blocks that were added after startup.
It always resets headNum to the snapshot’s head (76753126).
Question
Is this behavior expected for Lite Full Nodes (i.e., it always reverts to the snapshot window)?
Or should a Lite Full Node keep the newly received blocks on disk and continue from the latest synced height after restart?
If it’s expected — is there any configuration or flag that allows a Lite Node to “extend” the snapshot window forward and retain those new blocks?
config.conf :