Skip to content

Commit

Permalink
Checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
kdimentionaltree committed Oct 8, 2024
1 parent 9d7a9fa commit a58d9c3
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 25 deletions.
13 changes: 7 additions & 6 deletions docker-compose.swarm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ services:
TON_API_GET_METHODS_ENABLED:
TON_API_JSON_RPC_ENABLED:
TON_API_WEBSERVERS_WORKERS:
TON_API_WEBSERVERS_THREADS:
TON_API_V3_ENABLED:
TON_API_GUNICORN_FLAGS:
TON_API_ROOT_PATH:
Expand All @@ -51,16 +52,16 @@ services:
labels:
co.elastic.logs/enabled: "true"
ton_network: ${TONCENTER_ENV}
healthcheck:
test: curl --fail http://127.0.0.1:8081/api/v2/getMasterchainInfo
interval: 15s
timeout: 3s
retries: 12
# healthcheck:
# test: curl --fail http://127.0.0.1:8081/api/v2/getMasterchainInfo
# interval: 15s
# timeout: 3s
# retries: 12
deploy:
mode: replicated
replicas: ${SWARM_REPLICAS:-1}
update_config:
parallelism: 6
parallelism: ${SWARM_UPDATE_PARALLELISM:-1}
delay: 30s
monitor: 60s
failure_action: pause
Expand Down
11 changes: 6 additions & 5 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
- TON_API_GET_METHODS_ENABLED
- TON_API_JSON_RPC_ENABLED
- TON_API_WEBSERVERS_WORKERS
- TON_API_WEBSERVERS_THREADS
- TON_API_V3_ENABLED
- TON_API_GUNICORN_FLAGS
- TON_API_ROOT_PATH
Expand All @@ -36,11 +37,11 @@ services:
- liteserver_config
labels:
co.elastic.logs/enabled: "true"
healthcheck:
test: curl -sS http://127.0.0.1:8081${TON_API_ROOT_PATH}/healthcheck || echo 1
interval: 15s
timeout: 3s
retries: 12
# healthcheck:
# test: curl -sS http://127.0.0.1:8081${TON_API_ROOT_PATH}/healthcheck || echo 1
# interval: 15s
# timeout: 3s
# retries: 12
secrets:
liteserver_config:
file: ${TON_API_TONLIB_LITESERVER_CONFIG}
Expand Down
2 changes: 1 addition & 1 deletion ton-http-api/.docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ echo "ENVIRONMENT:"
printenv

gunicorn -k uvicorn.workers.UvicornWorker -w ${TON_API_WEBSERVERS_WORKERS:-1} \
--bind 0.0.0.0:8081 ${TON_API_GUNICORN_FLAGS} pyTON.main:app
--threads ${TON_API_WEBSERVERS_THREADS:-1} --bind 0.0.0.0:8081 ${TON_API_GUNICORN_FLAGS} pyTON.main:app
71 changes: 69 additions & 2 deletions ton-http-api/pyTON/api/api_v2/endpoints/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,25 @@ async def get_block_transactions(
"""
return await tonlib.getBlockTransactions(workchain, shard, seqno, count, root_hash, file_hash, after_lt, after_hash)

@router.get('/getBlockTransactionsExt', response_model=TonResponse, response_model_exclude_none=True, tags=['blocks','transactions'])
@json_rpc('getBlockTransactionsExt')
@wrap_result
async def get_block_transactions_ext(
workchain: int,
shard: int,
seqno: int,
root_hash: Optional[str] = None,
file_hash: Optional[str] = None,
after_lt: Optional[int] = None,
after_hash: Optional[str] = None,
count: int = 40,
tonlib: TonlibManager = Depends(tonlib_dep)
):
"""
Get transactions of the given block.
"""
return await tonlib.getBlockTransactionsExt(workchain, shard, seqno, count, root_hash, file_hash, after_lt, after_hash)

@router.get('/getBlockHeader', response_model=TonResponse, response_model_exclude_none=True, tags=['blocks'])
@json_rpc('getBlockHeader')
@wrap_result
Expand Down Expand Up @@ -351,6 +370,29 @@ async def get_config_param(
"""
return await tonlib.get_config_param(config_id, seqno)

@router.get('/getConfigAll', response_model=TonResponse, response_model_exclude_none=True, tags=['get config'])
@json_rpc('getConfigAll')
@wrap_result
async def get_config_all(
seqno: Optional[int] = Query(None, description="Masterchain seqno. If not specified, latest blockchain state will be used."),
tonlib: TonlibManager = Depends(tonlib_dep)
):
"""
Get cell with full config.
"""
return await tonlib.get_config_all(seqno)

@router.get('/getOutMsgQueueSizes', response_model=TonResponse, response_model_exclude_none=True, tags=['blocks'])
@json_rpc('getOutMsgQueueSizes')
@wrap_result
async def get_out_msg_queue_sizes(
tonlib: TonlibManager = Depends(tonlib_dep)
):
"""
Get info with current sizes of messages queues by shards.
"""
return await tonlib.get_out_msg_queue_sizes()

@router.get('/getTokenData', response_model=TonResponse, response_model_exclude_none=True, tags=['accounts'])
@json_rpc('getTokenData')
@wrap_result
Expand Down Expand Up @@ -422,7 +464,7 @@ def send_boc_to_external_endpoint(boc):
try:
endpoint = settings.webserver.boc_endpoint
logger.info(f'BOC is: "{boc}"')
res = requests.post(endpoint, json={'boc': boc})
res = requests.post(endpoint, json={'boc': boc}, timeout=0.5)
logger.info(f"Boc sent to external endpoint: {res}")
return res.get('ok', False)
except Exception as ee:
Expand Down Expand Up @@ -470,6 +512,30 @@ async def send_boc_return_hash(
background_tasks.add_task(send_boc_to_external_endpoint, base64.b64encode(boc).decode('utf8'))
return res

# Chrome extensions have antiddos protection, that blocks consequent requests with 500+ response codes.
# To handle it we create this method that returns status code 400 in case of errors
@router.post('/sendBocReturnHashNoError', response_model=TonResponse, response_model_exclude_none=True, include_in_schema=False, tags=['send'])
@json_rpc('sendBocReturnHashNoError')
@wrap_result
async def send_boc_return_hash_no_error(
background_tasks: BackgroundTasks,
boc: str = Body(..., embed=True, description="b64 encoded bag of cells"),
tonlib: TonlibManager = Depends(tonlib_dep)
):
"""
Send serialized boc file: fully packed and serialized external message to blockchain. The method returns message hash.
"""
boc = base64.b64decode(boc)
try:
res = await tonlib.raw_send_message_return_hash(boc)
except Exception as e:
raise HTTPException(status_code=400, detail=f"Error: {e}")
if res.get('@type') == 'raw.extMessageInfo':
logger.info("External message accepted: {hash}", hash=res.get('hash'))
if settings.webserver.boc_endpoint is not None:
background_tasks.add_task(send_boc_to_external_endpoint, base64.b64encode(boc).decode('utf8'))
return res

async def send_boc_unsafe_task(boc_bytes: bytes, tonlib: TonlibManager):
send_interval = 5
send_duration = 60
Expand Down Expand Up @@ -616,13 +682,14 @@ async def run_get_method(
address: str = Body(..., description='Contract address'),
method: Union[str, int] = Body(..., description='Method name or method id'),
stack: List[List[Any]] = Body(..., description="Array of stack elements: `[['num',3], ['cell', cell_object], ['slice', slice_object]]`"),
seqno: Optional[int] = Body(None, description="Seqno of masterchain block at which moment the Get Method is to be executed"),
tonlib: TonlibManager = Depends(tonlib_dep)
):
"""
Run get method on smart contract.
"""
address = prepare_address(address)
return await tonlib.raw_run_method(address, method, stack)
return await tonlib.raw_run_method(address, method, stack, seqno)


if settings.webserver.json_rpc:
Expand Down
30 changes: 24 additions & 6 deletions ton-http-api/pyTON/core/tonlib/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ async def generic_get_account_state(self, address: str):
async def get_token_data(self, address: str):
return await self.dispatch_request('get_token_data', address)

async def raw_run_method(self, address, method, stack_data, output_layout=None):
return await self.dispatch_request('raw_run_method', address, method, stack_data, output_layout)
async def raw_run_method(self, address, method, stack_data, seqno=None):
return await self.dispatch_request('raw_run_method', address, method, stack_data, seqno)

async def _send_message(self, serialized_boc, method):
ls_index_list = self.select_worker(count=4)
Expand Down Expand Up @@ -407,6 +407,9 @@ async def raw_getBlockTransactions(self, fullblock, count, after_tx):

async def getBlockTransactions(self, workchain, shard, seqno, count, root_hash=None, file_hash=None, after_lt=None, after_hash=None):
return await self.dispatch_archival_request('get_block_transactions', workchain, shard, seqno, count, root_hash, file_hash, after_lt, after_hash)

async def getBlockTransactionsExt(self, workchain, shard, seqno, count, root_hash=None, file_hash=None, after_lt=None, after_hash=None):
return await self.dispatch_archival_request('get_block_transactions_ext', workchain, shard, seqno, count, root_hash, file_hash, after_lt, after_hash)

async def getBlockHeader(self, workchain, shard, seqno, root_hash=None, file_hash=None):
method = 'get_block_header'
Expand All @@ -416,12 +419,27 @@ async def getBlockHeader(self, workchain, shard, seqno, root_hash=None, file_has
return await self.dispatch_archival_request(method, workchain, shard, seqno, root_hash, file_hash)

async def get_config_param(self, config_id: int, seqno: Optional[int]):
seqno = seqno or self.consensus_block.seqno
method = 'get_config_param'
if self.consensus_block.seqno - seqno < 2000:
return await self.dispatch_request(method, config_id, seqno)
if seqno is not None:
if self.consensus_block.seqno - seqno < 2000:
return await self.dispatch_request(method, config_id, seqno)
else:
return await self.dispatch_archival_request(method, config_id, seqno)
else:
return await self.dispatch_request(method, config_id)

async def get_config_all(self, seqno: Optional[int]):
method = 'get_config_all'
if seqno is not None:
if self.consensus_block.seqno - seqno < 2000:
return await self.dispatch_request(method, seqno)
else:
return await self.dispatch_archival_request(method, seqno)
else:
return await self.dispatch_archival_request(method, config_id, seqno)
return await self.dispatch_request(method)

async def get_out_msg_queue_sizes(self):
return await self.dispatch_request('get_out_msg_queue_sizes')

async def tryLocateTxByOutcomingMessage(self, source, destination, creation_lt):
return await self.dispatch_archival_request('try_locate_tx_by_outcoming_message', source, destination, creation_lt)
Expand Down
10 changes: 5 additions & 5 deletions ton-http-api/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
redis==5.0.1
loguru>=0.6.0
fastapi==0.90.0
fastapi<0.100.0
pydantic>=1.2.0,<2.0.0
requests>=2.28.0
requests>=2.31.0
ring==0.10.1
uvicorn>=0.17.6
gunicorn>=20.1.0
pytonlib>=0.0.50
uvicorn>=0.29.0
gunicorn>=22.0.0
pytonlib==0.0.63
tvm_valuetypes==0.0.12
inject>=4.3.1
67 changes: 67 additions & 0 deletions update_init_block.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/bash

ENDPOINT=https://toncenter.com/api/v2


function usage() {
echo 'required 1 positional argument: name of config file'
echo 'Supported argumets:'
echo ' -h --help Show this message'
echo ' --testnet Use testnet endpoint'
exit
}

while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
exit 1
;;
--testnet)
ENDPOINT=https://testnet.toncenter.com/api/v2
shift
;;
-*|--*)
echo "Error: unknown option $1"
usage
exit 1
;;
*)
POSITIONAL_ARGS+=("$1") # save positional arg
shift # past argument
;;
esac
done

set -- "${POSITIONAL_ARGS[@]}"

# main logic
LAST_SEQNO=$(curl -s ${ENDPOINT}/getMasterchainInfo | jq ".result.last.seqno")
echo "Last seqno is $LAST_SEQNO"

sleep 1
LAST_KEYBLOCK_SEQNO=$(curl -s "${ENDPOINT}/getBlockHeader?workchain=-1&shard=-9223372036854775808&seqno=${LAST_SEQNO}" | jq .result.prev_key_block_seqno)
echo "Last keyblock seqno is $LAST_KEYBLOCK_SEQNO"

sleep 1
RES=$(curl -s "${ENDPOINT}/lookupBlock?workchain=-1&shard=-9223372036854775808&seqno=${LAST_KEYBLOCK_SEQNO}" | jq .result )

SEQNO=$(echo "$RES" | jq '.seqno')
FILEHASH=$(echo "$RES" | jq '.file_hash')
ROOTHASH=$(echo "$RES" | jq '.root_hash')

FILENAME=$1

cp $FILENAME $FILENAME.bk || echo "Failed to backup the config"
python3 <<EOF
import json
with open("$FILENAME", 'r') as f:
data = json.load(f)
data['validator']['init_block']['seqno'] = $SEQNO
data['validator']['init_block']['file_hash'] = $FILEHASH
data['validator']['init_block']['root_hash'] = $ROOTHASH
with open("$FILENAME", 'w') as f:
json.dump(data, f, indent=4)
EOF
echo "Init block updated"

0 comments on commit a58d9c3

Please sign in to comment.