mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Extended error notes for unacceptable external messages (#383)
* patch sendMessage * Verbose error message for "sendMessage" LS query * More verbose errors in external-message.cpp Co-authored-by: dungeon-master-666 <dungeon666master@protonmail.com> Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
parent
89b8717cf8
commit
ca00f0ed91
6 changed files with 86 additions and 29 deletions
|
@ -25,6 +25,41 @@
|
|||
#include "ton/ton-shard.h"
|
||||
#include "vm/vm.h"
|
||||
|
||||
namespace {
|
||||
class StringLoggerTail : public td::LogInterface {
|
||||
public:
|
||||
explicit StringLoggerTail(size_t max_size = 256) : buf(max_size, '\0') {}
|
||||
void append(td::CSlice slice) override {
|
||||
if (slice.size() > buf.size()) {
|
||||
slice.remove_prefix(slice.size() - buf.size());
|
||||
}
|
||||
while (!slice.empty()) {
|
||||
size_t s = std::min(buf.size() - pos, slice.size());
|
||||
std::copy(slice.begin(), slice.begin() + s, buf.begin() + pos);
|
||||
pos += s;
|
||||
if (pos == buf.size()) {
|
||||
pos = 0;
|
||||
truncated = true;
|
||||
}
|
||||
slice.remove_prefix(s);
|
||||
}
|
||||
}
|
||||
std::string get_log() const {
|
||||
if (truncated) {
|
||||
std::string res = buf;
|
||||
std::rotate(res.begin(), res.begin() + pos, res.end());
|
||||
return res;
|
||||
} else {
|
||||
return buf.substr(0, pos);
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::string buf;
|
||||
size_t pos = 0;
|
||||
bool truncated = false;
|
||||
};
|
||||
}
|
||||
|
||||
namespace block {
|
||||
using td::Ref;
|
||||
|
||||
|
@ -1001,7 +1036,14 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
vm::GasLimits gas{(long long)cp.gas_limit, (long long)cp.gas_max, (long long)cp.gas_credit};
|
||||
LOG(DEBUG) << "creating VM";
|
||||
|
||||
vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm::VmLog(), compute_vm_libraries(cfg)};
|
||||
std::unique_ptr<StringLoggerTail> logger;
|
||||
auto vm_log = vm::VmLog();
|
||||
if (cfg.with_vm_log) {
|
||||
logger = std::make_unique<StringLoggerTail>();
|
||||
vm_log.log_interface = logger.get();
|
||||
vm_log.log_options = td::LogOptions(VERBOSITY_NAME(DEBUG), true, false);
|
||||
}
|
||||
vm::VmState vm{new_code, std::move(stack), gas, 1, new_data, vm_log, compute_vm_libraries(cfg)};
|
||||
vm.set_c7(prepare_vm_c7(cfg)); // tuple with SmartContractInfo
|
||||
// vm.incr_stack_trace(1); // enable stack dump after each step
|
||||
|
||||
|
@ -1024,6 +1066,9 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
LOG(INFO) << "steps: " << vm.get_steps_count() << " gas: used=" << gas.gas_consumed() << ", max=" << gas.gas_max
|
||||
<< ", limit=" << gas.gas_limit << ", credit=" << gas.gas_credit;
|
||||
LOG(INFO) << "out_of_gas=" << cp.out_of_gas << ", accepted=" << cp.accepted << ", success=" << cp.success;
|
||||
if (logger != nullptr) {
|
||||
cp.vm_log = logger->get_log();
|
||||
}
|
||||
if (cp.success) {
|
||||
cp.new_data = vm.get_committed_state().c4; // c4 -> persistent data
|
||||
cp.actions = vm.get_committed_state().c5; // c5 -> action list
|
||||
|
|
|
@ -106,6 +106,7 @@ struct ComputePhaseConfig {
|
|||
std::unique_ptr<vm::Dictionary> libraries;
|
||||
Ref<vm::Cell> global_config;
|
||||
td::BitArray<256> block_rand_seed;
|
||||
bool with_vm_log{false};
|
||||
ComputePhaseConfig(td::uint64 _gas_price = 0, td::uint64 _gas_limit = 0, td::uint64 _gas_credit = 0)
|
||||
: gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_gas_limit), gas_credit(_gas_credit) {
|
||||
compute_threshold();
|
||||
|
@ -171,6 +172,7 @@ struct ComputePhase {
|
|||
Ref<vm::Cell> in_msg;
|
||||
Ref<vm::Cell> new_data;
|
||||
Ref<vm::Cell> actions;
|
||||
std::string vm_log;
|
||||
};
|
||||
|
||||
struct ActionPhase {
|
||||
|
|
|
@ -2326,7 +2326,12 @@ td::Result<std::unique_ptr<block::Transaction>> Collator::impl_create_ordinary_t
|
|||
if (!trans->compute_phase->accepted) {
|
||||
if (external) {
|
||||
// inbound external message was not accepted
|
||||
return td::Status::Error(-701,"inbound external message rejected by transaction "s + acc->addr.to_hex());
|
||||
auto const& cp = *trans->compute_phase;
|
||||
return td::Status::Error(
|
||||
-701,
|
||||
PSLICE() << "inbound external message rejected by transaction " << acc->addr.to_hex() << ":\n" <<
|
||||
"exitcode=" << cp.exit_code << ", steps=" << cp.vm_steps << ", gas_used=" << cp.gas_used <<
|
||||
(cp.vm_log.empty() ? "" : "\nVM Log (truncated):\n..." + cp.vm_log));
|
||||
} else if (trans->compute_phase->skip_reason == block::ComputePhase::sk_none) {
|
||||
return td::Status::Error(-669,"new ordinary transaction for smart contract "s + acc->addr.to_hex() +
|
||||
" has not been accepted by the smart contract (?)");
|
||||
|
|
|
@ -112,10 +112,12 @@ void ExtMessageQ::run_message(td::BufferSlice data, td::actor::ActorId<ton::vali
|
|||
if(!acc.unpack(shard_acc, {}, utime, false)) {
|
||||
promise.set_error(td::Status::Error(PSLICE() << "Failed to unpack account state"));
|
||||
} else {
|
||||
if(run_message_on_account(wc, &acc, utime, lt + 1, msg_root, std::move(config))) {
|
||||
auto status = run_message_on_account(wc, &acc, utime, lt + 1, msg_root, std::move(config));
|
||||
if (status.is_ok()) {
|
||||
promise.set_value(td::Unit());
|
||||
} else {
|
||||
promise.set_error(td::Status::Error(PSLICE() << "External message was not accepted"));
|
||||
promise.set_error(td::Status::Error(
|
||||
PSLICE() << "External message was not accepted\n" << status.message()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,11 +125,11 @@ void ExtMessageQ::run_message(td::BufferSlice data, td::actor::ActorId<ton::vali
|
|||
);
|
||||
}
|
||||
|
||||
bool ExtMessageQ::run_message_on_account(ton::WorkchainId wc,
|
||||
block::Account* acc,
|
||||
UnixTime utime, LogicalTime lt,
|
||||
td::Ref<vm::Cell> msg_root,
|
||||
std::unique_ptr<block::ConfigInfo> config) {
|
||||
td::Status ExtMessageQ::run_message_on_account(ton::WorkchainId wc,
|
||||
block::Account* acc,
|
||||
UnixTime utime, LogicalTime lt,
|
||||
td::Ref<vm::Cell> msg_root,
|
||||
std::unique_ptr<block::ConfigInfo> config) {
|
||||
|
||||
Ref<vm::Cell> old_mparams;
|
||||
std::vector<block::StoragePrices> storage_prices_;
|
||||
|
@ -143,28 +145,29 @@ bool ExtMessageQ::run_message_on_account(ton::WorkchainId wc,
|
|||
&action_phase_cfg_, &masterchain_create_fee,
|
||||
&basechain_create_fee, wc);
|
||||
if(fetch_res.is_error()) {
|
||||
auto error = fetch_res.move_as_error();
|
||||
LOG(DEBUG) << "Cannot fetch config params" << error.message();
|
||||
return false;
|
||||
auto error = fetch_res.move_as_error();
|
||||
LOG(DEBUG) << "Cannot fetch config params: " << error.message();
|
||||
return error.move_as_error_prefix("Cannot fetch config params: ");
|
||||
}
|
||||
compute_phase_cfg_.with_vm_log = true;
|
||||
|
||||
auto res = Collator::impl_create_ordinary_transaction(msg_root, acc, utime, lt,
|
||||
&storage_phase_cfg_, &compute_phase_cfg_,
|
||||
&action_phase_cfg_,
|
||||
true, lt);
|
||||
if(res.is_error()) {
|
||||
auto error = res.move_as_error();
|
||||
LOG(DEBUG) << "Cannot run message on account" << error.message();
|
||||
return false;
|
||||
auto error = res.move_as_error();
|
||||
LOG(DEBUG) << "Cannot run message on account: " << error.message();
|
||||
return error.move_as_error_prefix("Cannot run message on account: ");
|
||||
}
|
||||
std::unique_ptr<block::Transaction> trans = res.move_as_ok();
|
||||
|
||||
auto trans_root = trans->commit(*acc);
|
||||
if (trans_root.is_null()) {
|
||||
LOG(DEBUG) << "cannot commit new transaction for smart contract ";
|
||||
return false;
|
||||
LOG(DEBUG) << "Cannot commit new transaction for smart contract";
|
||||
return td::Status::Error("Cannot commit new transaction for smart contract");
|
||||
}
|
||||
return true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -63,11 +63,11 @@ class ExtMessageQ : public ExtMessage {
|
|||
static td::Result<td::Ref<ExtMessageQ>> create_ext_message(td::BufferSlice data);
|
||||
static void run_message(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
td::Promise<td::Unit> promise);
|
||||
static bool run_message_on_account(ton::WorkchainId wc,
|
||||
block::Account* acc,
|
||||
UnixTime utime, LogicalTime lt,
|
||||
td::Ref<vm::Cell> msg_root,
|
||||
std::unique_ptr<block::ConfigInfo> config);
|
||||
static td::Status run_message_on_account(ton::WorkchainId wc,
|
||||
block::Account* acc,
|
||||
UnixTime utime, LogicalTime lt,
|
||||
td::Ref<vm::Cell> msg_root,
|
||||
std::unique_ptr<block::ConfigInfo> config);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -458,18 +458,20 @@ void LiteQuery::continue_getZeroState(BlockIdExt blkid, td::BufferSlice state) {
|
|||
|
||||
void LiteQuery::perform_sendMessage(td::BufferSlice data) {
|
||||
LOG(INFO) << "started a sendMessage(<" << data.size() << " bytes>) liteserver query";
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::check_external_message, data.clone(),
|
||||
[Self = actor_id(this), data = std::move(data), manager = manager_](td::Result<td::Unit> res) {
|
||||
auto copy = data.clone();
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::check_external_message, std::move(copy),
|
||||
[Self = actor_id(this), data = std::move(data), manager = manager_](td::Result<td::Unit> res) mutable {
|
||||
if(res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot apply external message to current state : "s));
|
||||
res.move_as_error_prefix("cannot apply external message to current state : "s));
|
||||
} else {
|
||||
auto crm = ton::validator::create_ext_message(data.clone());
|
||||
auto crm = ton::validator::create_ext_message(std::move(data));
|
||||
if (crm.is_error()) {
|
||||
//UNREACHABLE, checks in check_external_message,
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
crm.move_as_error());
|
||||
crm.move_as_error());
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "sending an external message to validator manager";
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::send_external_message, crm.move_as_ok());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue