Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure all exceptions are caught when executing code in http_plugin's thread pool, so Leap doesn't crash when processing APIs. #1370

Merged
merged 6 commits into from
Jul 28, 2023
Merged
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
20 changes: 12 additions & 8 deletions plugins/http_plugin/include/eosio/http_plugin/macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,19 @@
_http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \
body=std::move(body), \
http_fwd = std::move(http_fwd)]() { \
chain::t_or_exception<call_result> result = http_fwd(); \
if (std::holds_alternative<fc::exception_ptr>(result)) { \
try { \
std::get<fc::exception_ptr>(result)->dynamic_rethrow_exception(); \
} catch (...) { \
http_plugin::handle_exception(#api_name, #call_name, body, cb); \
try { \
chain::t_or_exception<call_result> result = http_fwd(); \
if (std::holds_alternative<fc::exception_ptr>(result)) { \
try { \
std::get<fc::exception_ptr>(result)->dynamic_rethrow_exception(); \
} catch (...) { \
http_plugin::handle_exception(#api_name, #call_name, body, cb); \
} \
} else { \
cb(resp_code, fc::variant(std::get<call_result>(std::move(result)))); \
} \
} else { \
cb(resp_code, fc::variant(std::get<call_result>(std::move(result)))); \
} catch (...) { \
http_plugin::handle_exception(#api_name, #call_name, body, cb); \
} \
}); \
} catch (...) { \
Expand Down
3 changes: 0 additions & 3 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,6 @@ add_test(NAME full-version-label-test COMMAND tests/full-version-label.sh "v${VE
add_test(NAME nested_container_multi_index_test COMMAND tests/nested_container_multi_index_test.py -n 2 WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST nested_container_multi_index_test PROPERTY LABELS nonparallelizable_tests)

add_test(NAME nodeos_run_check_test COMMAND tests/nodeos_run_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST nodeos_run_check_test PROPERTY LABELS nonparallelizable_tests)

add_test(NAME p2p_multiple_listen_test COMMAND tests/p2p_multiple_listen_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST p2p_multiple_listen_test PROPERTY LABELS nonparallelizable_tests)
add_test(NAME p2p_no_listen_test COMMAND tests/p2p_no_listen_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
Expand Down
29 changes: 29 additions & 0 deletions tests/nodeos_run_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,35 @@
accounts=[testeraAccount, currencyAccount, exchangeAccount]
cluster.validateAccounts(accounts)

# run a get_table_rows API call for a table which has an incorrect abi (missing type), to make sure that
# the resulting exception in http-plugin is caught and doesn't cause nodeos to crash (leap issue #1372).
contractDir="unittests/contracts/eosio.token"
wasmFile="eosio.token.wasm"
abiFile="eosio.token.bad.abi"
Print("Publish contract")
trans=node.publishContract(currencyAccount, contractDir, wasmFile, abiFile, waitForTransBlock=True)
if trans is None:
cmdError("%s set contract currency1111" % (ClientName))
errorExit("Failed to publish contract.")

contract="currency1111"
table="accounts"
row0=node.getTableRow(contract, currencyAccount.name, table, 0)

# because we set a bad abi (missing type, see "eosio.token.bad.abi") on the contract, the
# getTableRow() is expected to fail and return None
try:
assert(not row0)
except (AssertionError, KeyError) as _:
Print("ERROR: Failed get table row assertion. %s" % (row0))
raise

# However check that the node is still running and didn't crash when processing getTableRow on a contract
# with a bad abi. If node does crash and we get an exception during "get info", it means that we did not
# catch the exception that occured while calling `cb()` in `http_plugin/macros.hpp`.
currentBlockNum=node.getHeadBlockNum()
Print("CurrentBlockNum: %d" % (currentBlockNum))

testSuccessful=True
finally:
TestHelper.shutdown(cluster, walletMgr, testSuccessful, dumpErrorDetails)
Expand Down
2 changes: 2 additions & 0 deletions unittests/contracts/eosio.token/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/eosio.token.wasm ${CMAKE_CURRENT_BINARY_DIR}/eosio.token.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/eosio.token.abi ${CMAKE_CURRENT_BINARY_DIR}/eosio.token.abi COPYONLY )
endif()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/eosio.token.bad.abi ${CMAKE_CURRENT_BINARY_DIR}/eosio.token.bad.abi COPYONLY )

193 changes: 193 additions & 0 deletions unittests/contracts/eosio.token/eosio.token.bad.abi
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
{
"____comment": "This file was generated with eosio-abigen. Manually edited to add a table named global with an undefined type ",
"version": "eosio::abi/1.2",
"types": [],
"structs": [
{
"name": "account",
"base": "",
"fields": [
{
"name": "balance",
"type": "asset"
}
]
},
{
"name": "close",
"base": "",
"fields": [
{
"name": "owner",
"type": "name"
},
{
"name": "symbol",
"type": "symbol"
}
]
},
{
"name": "create",
"base": "",
"fields": [
{
"name": "issuer",
"type": "name"
},
{
"name": "maximum_supply",
"type": "asset"
}
]
},
{
"name": "currency_stats",
"base": "",
"fields": [
{
"name": "supply",
"type": "asset"
},
{
"name": "max_supply",
"type": "asset"
},
{
"name": "issuer",
"type": "name"
}
]
},
{
"name": "issue",
"base": "",
"fields": [
{
"name": "to",
"type": "name"
},
{
"name": "quantity",
"type": "asset"
},
{
"name": "memo",
"type": "string"
}
]
},
{
"name": "open",
"base": "",
"fields": [
{
"name": "owner",
"type": "name"
},
{
"name": "symbol",
"type": "symbol"
},
{
"name": "ram_payer",
"type": "name"
}
]
},
{
"name": "retire",
"base": "",
"fields": [
{
"name": "quantity",
"type": "asset"
},
{
"name": "memo",
"type": "string"
}
]
},
{
"name": "transfer",
"base": "",
"fields": [
{
"name": "from",
"type": "name"
},
{
"name": "to",
"type": "name"
},
{
"name": "quantity",
"type": "asset"
},
{
"name": "memo",
"type": "string"
}
]
}
],
"actions": [
{
"name": "close",
"type": "close",
"ricardian_contract": ""
},
{
"name": "create",
"type": "create",
"ricardian_contract": ""
},
{
"name": "issue",
"type": "issue",
"ricardian_contract": ""
},
{
"name": "open",
"type": "open",
"ricardian_contract": ""
},
{
"name": "retire",
"type": "retire",
"ricardian_contract": ""
},
{
"name": "transfer",
"type": "transfer",
"ricardian_contract": ""
}
],
"tables": [
{
"name": "accounts",
"type": "account",
"index_type": "i64",
"key_names": [],
"key_types": []
},
{
"name": "stat",
"type": "currency_stats",
"index_type": "i64",
"key_names": [],
"key_types": []
},
{
"name": "global",
"type": "global",
"index_type": "i64",
"key_names": [],
"key_types": []
}
],
"ricardian_clauses": [],
"variants": [],
"action_results": []
}