mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
Merge pull request #1202 from ton-blockchain/tvm-patch
Fix transaction original_balance and VmState::jump_to
This commit is contained in:
commit
b78199370e
6 changed files with 94 additions and 70 deletions
|
@ -19,6 +19,6 @@
|
||||||
namespace ton {
|
namespace ton {
|
||||||
|
|
||||||
// See doc/GlobalVersions.md
|
// See doc/GlobalVersions.md
|
||||||
const int SUPPORTED_VERSION = 8;
|
const int SUPPORTED_VERSION = 9;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1555,7 +1555,14 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
||||||
// ...
|
// ...
|
||||||
compute_phase = std::make_unique<ComputePhase>();
|
compute_phase = std::make_unique<ComputePhase>();
|
||||||
ComputePhase& cp = *(compute_phase.get());
|
ComputePhase& cp = *(compute_phase.get());
|
||||||
original_balance -= total_fees;
|
if (cfg.global_version >= 9) {
|
||||||
|
original_balance = balance;
|
||||||
|
if (msg_balance_remaining.is_valid()) {
|
||||||
|
original_balance -= msg_balance_remaining;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
original_balance -= total_fees;
|
||||||
|
}
|
||||||
if (td::sgn(balance.grams) <= 0) {
|
if (td::sgn(balance.grams) <= 0) {
|
||||||
// no gas
|
// no gas
|
||||||
cp.skip_reason = ComputePhase::sk_no_gas;
|
cp.skip_reason = ComputePhase::sk_no_gas;
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
int Continuation::jump_w(VmState* st) & {
|
td::Ref<Continuation> Continuation::jump_w(VmState* st, int& exitcode) & {
|
||||||
return static_cast<const Continuation*>(this)->jump(st);
|
return static_cast<const Continuation*>(this)->jump(st, exitcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Continuation::has_c0() const {
|
bool Continuation::has_c0() const {
|
||||||
|
@ -286,7 +286,7 @@ std::string QuitCont::type() const {
|
||||||
return "vmc_quit";
|
return "vmc_quit";
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExcQuitCont::jump(VmState* st) const & {
|
td::Ref<Continuation> ExcQuitCont::jump(VmState* st, int& exitcode) const& {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
try {
|
try {
|
||||||
n = st->get_stack().pop_smallint_range(0xffff);
|
n = st->get_stack().pop_smallint_range(0xffff);
|
||||||
|
@ -294,7 +294,8 @@ int ExcQuitCont::jump(VmState* st) const & {
|
||||||
n = vme.get_errno();
|
n = vme.get_errno();
|
||||||
}
|
}
|
||||||
VM_LOG(st) << "default exception handler, terminating vm with exit code " << n;
|
VM_LOG(st) << "default exception handler, terminating vm with exit code " << n;
|
||||||
return ~n;
|
exitcode = ~n;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ExcQuitCont::type() const {
|
std::string ExcQuitCont::type() const {
|
||||||
|
@ -311,16 +312,16 @@ Ref<ExcQuitCont> ExcQuitCont::deserialize(CellSlice& cs, int mode) {
|
||||||
return cs.fetch_ulong(4) == 9 ? Ref<ExcQuitCont>{true} : Ref<ExcQuitCont>{};
|
return cs.fetch_ulong(4) == 9 ? Ref<ExcQuitCont>{true} : Ref<ExcQuitCont>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
int PushIntCont::jump(VmState* st) const & {
|
td::Ref<Continuation> PushIntCont::jump(VmState* st, int& exitcode) const& {
|
||||||
VM_LOG(st) << "execute implicit PUSH " << push_val << " (slow)";
|
VM_LOG(st) << "execute implicit PUSH " << push_val << " (slow)";
|
||||||
st->get_stack().push_smallint(push_val);
|
st->get_stack().push_smallint(push_val);
|
||||||
return st->jump(next);
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PushIntCont::jump_w(VmState* st) & {
|
td::Ref<Continuation> PushIntCont::jump_w(VmState* st, int& exitcode) & {
|
||||||
VM_LOG(st) << "execute implicit PUSH " << push_val;
|
VM_LOG(st) << "execute implicit PUSH " << push_val;
|
||||||
st->get_stack().push_smallint(push_val);
|
st->get_stack().push_smallint(push_val);
|
||||||
return st->jump(std::move(next));
|
return std::move(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PushIntCont::type() const {
|
std::string PushIntCont::type() const {
|
||||||
|
@ -345,20 +346,20 @@ Ref<PushIntCont> PushIntCont::deserialize(CellSlice& cs, int mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ArgContExt::jump(VmState* st) const & {
|
td::Ref<Continuation> ArgContExt::jump(VmState* st, int& exitcode) const& {
|
||||||
st->adjust_cr(data.save);
|
st->adjust_cr(data.save);
|
||||||
if (data.cp != -1) {
|
if (data.cp != -1) {
|
||||||
st->force_cp(data.cp);
|
st->force_cp(data.cp);
|
||||||
}
|
}
|
||||||
return ext->jump(st);
|
return ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ArgContExt::jump_w(VmState* st) & {
|
td::Ref<Continuation> ArgContExt::jump_w(VmState* st, int& exitcode) & {
|
||||||
st->adjust_cr(std::move(data.save));
|
st->adjust_cr(std::move(data.save));
|
||||||
if (data.cp != -1) {
|
if (data.cp != -1) {
|
||||||
st->force_cp(data.cp);
|
st->force_cp(data.cp);
|
||||||
}
|
}
|
||||||
return st->jump_to(std::move(ext));
|
return std::move(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArgContExt::serialize(CellBuilder& cb) const {
|
bool ArgContExt::serialize(CellBuilder& cb) const {
|
||||||
|
@ -382,32 +383,32 @@ std::string ArgContExt::type() const {
|
||||||
return "vmc_envelope";
|
return "vmc_envelope";
|
||||||
}
|
}
|
||||||
|
|
||||||
int RepeatCont::jump(VmState* st) const & {
|
td::Ref<Continuation> RepeatCont::jump(VmState* st, int& exitcode) const& {
|
||||||
VM_LOG(st) << "repeat " << count << " more times (slow)\n";
|
VM_LOG(st) << "repeat " << count << " more times (slow)\n";
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
return st->jump(after);
|
return after;
|
||||||
}
|
}
|
||||||
if (body->has_c0()) {
|
if (body->has_c0()) {
|
||||||
return st->jump(body);
|
return body;
|
||||||
}
|
}
|
||||||
st->set_c0(Ref<RepeatCont>{true, body, after, count - 1});
|
st->set_c0(Ref<RepeatCont>{true, body, after, count - 1});
|
||||||
return st->jump(body);
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RepeatCont::jump_w(VmState* st) & {
|
td::Ref<Continuation> RepeatCont::jump_w(VmState* st, int& exitcode) & {
|
||||||
VM_LOG(st) << "repeat " << count << " more times\n";
|
VM_LOG(st) << "repeat " << count << " more times\n";
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
body.clear();
|
body.clear();
|
||||||
return st->jump(std::move(after));
|
return std::move(after);
|
||||||
}
|
}
|
||||||
if (body->has_c0()) {
|
if (body->has_c0()) {
|
||||||
after.clear();
|
after.clear();
|
||||||
return st->jump(std::move(body));
|
return std::move(body);
|
||||||
}
|
}
|
||||||
// optimization: since this is unique, reuse *this instead of creating new object
|
// optimization: since this is unique, reuse *this instead of creating new object
|
||||||
--count;
|
--count;
|
||||||
st->set_c0(Ref<RepeatCont>{this});
|
st->set_c0(Ref<RepeatCont>{this});
|
||||||
return st->jump(body);
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RepeatCont::serialize(CellBuilder& cb) const {
|
bool RepeatCont::serialize(CellBuilder& cb) const {
|
||||||
|
@ -443,21 +444,21 @@ int VmState::repeat(Ref<Continuation> body, Ref<Continuation> after, long long c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AgainCont::jump(VmState* st) const & {
|
td::Ref<Continuation> AgainCont::jump(VmState* st, int& exitcode) const& {
|
||||||
VM_LOG(st) << "again an infinite loop iteration (slow)\n";
|
VM_LOG(st) << "again an infinite loop iteration (slow)\n";
|
||||||
if (!body->has_c0()) {
|
if (!body->has_c0()) {
|
||||||
st->set_c0(Ref<AgainCont>{this});
|
st->set_c0(Ref<AgainCont>{this});
|
||||||
}
|
}
|
||||||
return st->jump(body);
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AgainCont::jump_w(VmState* st) & {
|
td::Ref<Continuation> AgainCont::jump_w(VmState* st, int& exitcode) & {
|
||||||
VM_LOG(st) << "again an infinite loop iteration\n";
|
VM_LOG(st) << "again an infinite loop iteration\n";
|
||||||
if (!body->has_c0()) {
|
if (!body->has_c0()) {
|
||||||
st->set_c0(Ref<AgainCont>{this});
|
st->set_c0(Ref<AgainCont>{this});
|
||||||
return st->jump(body);
|
return body;
|
||||||
} else {
|
} else {
|
||||||
return st->jump(std::move(body));
|
return std::move(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,31 +486,31 @@ int VmState::again(Ref<Continuation> body) {
|
||||||
return jump(Ref<AgainCont>{true, std::move(body)});
|
return jump(Ref<AgainCont>{true, std::move(body)});
|
||||||
}
|
}
|
||||||
|
|
||||||
int UntilCont::jump(VmState* st) const & {
|
td::Ref<Continuation> UntilCont::jump(VmState* st, int& exitcode) const& {
|
||||||
VM_LOG(st) << "until loop body end (slow)\n";
|
VM_LOG(st) << "until loop body end (slow)\n";
|
||||||
if (st->get_stack().pop_bool()) {
|
if (st->get_stack().pop_bool()) {
|
||||||
VM_LOG(st) << "until loop terminated\n";
|
VM_LOG(st) << "until loop terminated\n";
|
||||||
return st->jump(after);
|
return after;
|
||||||
}
|
}
|
||||||
if (!body->has_c0()) {
|
if (!body->has_c0()) {
|
||||||
st->set_c0(Ref<UntilCont>{this});
|
st->set_c0(Ref<UntilCont>{this});
|
||||||
}
|
}
|
||||||
return st->jump(body);
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UntilCont::jump_w(VmState* st) & {
|
td::Ref<Continuation> UntilCont::jump_w(VmState* st, int& exitcode) & {
|
||||||
VM_LOG(st) << "until loop body end\n";
|
VM_LOG(st) << "until loop body end\n";
|
||||||
if (st->get_stack().pop_bool()) {
|
if (st->get_stack().pop_bool()) {
|
||||||
VM_LOG(st) << "until loop terminated\n";
|
VM_LOG(st) << "until loop terminated\n";
|
||||||
body.clear();
|
body.clear();
|
||||||
return st->jump(std::move(after));
|
return std::move(after);
|
||||||
}
|
}
|
||||||
if (!body->has_c0()) {
|
if (!body->has_c0()) {
|
||||||
st->set_c0(Ref<UntilCont>{this});
|
st->set_c0(Ref<UntilCont>{this});
|
||||||
return st->jump(body);
|
return body;
|
||||||
} else {
|
} else {
|
||||||
after.clear();
|
after.clear();
|
||||||
return st->jump(std::move(body));
|
return std::move(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,54 +542,54 @@ int VmState::until(Ref<Continuation> body, Ref<Continuation> after) {
|
||||||
return jump(std::move(body));
|
return jump(std::move(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
int WhileCont::jump(VmState* st) const & {
|
td::Ref<Continuation> WhileCont::jump(VmState* st, int& exitcode) const& {
|
||||||
if (chkcond) {
|
if (chkcond) {
|
||||||
VM_LOG(st) << "while loop condition end (slow)\n";
|
VM_LOG(st) << "while loop condition end (slow)\n";
|
||||||
if (!st->get_stack().pop_bool()) {
|
if (!st->get_stack().pop_bool()) {
|
||||||
VM_LOG(st) << "while loop terminated\n";
|
VM_LOG(st) << "while loop terminated\n";
|
||||||
return st->jump(after);
|
return after;
|
||||||
}
|
}
|
||||||
if (!body->has_c0()) {
|
if (!body->has_c0()) {
|
||||||
st->set_c0(Ref<WhileCont>{true, cond, body, after, false});
|
st->set_c0(Ref<WhileCont>{true, cond, body, after, false});
|
||||||
}
|
}
|
||||||
return st->jump(body);
|
return body;
|
||||||
} else {
|
} else {
|
||||||
VM_LOG(st) << "while loop body end (slow)\n";
|
VM_LOG(st) << "while loop body end (slow)\n";
|
||||||
if (!cond->has_c0()) {
|
if (!cond->has_c0()) {
|
||||||
st->set_c0(Ref<WhileCont>{true, cond, body, after, true});
|
st->set_c0(Ref<WhileCont>{true, cond, body, after, true});
|
||||||
}
|
}
|
||||||
return st->jump(cond);
|
return cond;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int WhileCont::jump_w(VmState* st) & {
|
td::Ref<Continuation> WhileCont::jump_w(VmState* st, int& exitcode) & {
|
||||||
if (chkcond) {
|
if (chkcond) {
|
||||||
VM_LOG(st) << "while loop condition end\n";
|
VM_LOG(st) << "while loop condition end\n";
|
||||||
if (!st->get_stack().pop_bool()) {
|
if (!st->get_stack().pop_bool()) {
|
||||||
VM_LOG(st) << "while loop terminated\n";
|
VM_LOG(st) << "while loop terminated\n";
|
||||||
cond.clear();
|
cond.clear();
|
||||||
body.clear();
|
body.clear();
|
||||||
return st->jump(std::move(after));
|
return std::move(after);
|
||||||
}
|
}
|
||||||
if (!body->has_c0()) {
|
if (!body->has_c0()) {
|
||||||
chkcond = false; // re-use current object since we hold the unique pointer to it
|
chkcond = false; // re-use current object since we hold the unique pointer to it
|
||||||
st->set_c0(Ref<WhileCont>{this});
|
st->set_c0(Ref<WhileCont>{this});
|
||||||
return st->jump(body);
|
return body;
|
||||||
} else {
|
} else {
|
||||||
cond.clear();
|
cond.clear();
|
||||||
after.clear();
|
after.clear();
|
||||||
return st->jump(std::move(body));
|
return std::move(body);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VM_LOG(st) << "while loop body end\n";
|
VM_LOG(st) << "while loop body end\n";
|
||||||
if (!cond->has_c0()) {
|
if (!cond->has_c0()) {
|
||||||
chkcond = true; // re-use current object
|
chkcond = true; // re-use current object
|
||||||
st->set_c0(Ref<WhileCont>{this});
|
st->set_c0(Ref<WhileCont>{this});
|
||||||
return st->jump(cond);
|
return cond;
|
||||||
} else {
|
} else {
|
||||||
body.clear();
|
body.clear();
|
||||||
after.clear();
|
after.clear();
|
||||||
return st->jump(std::move(cond));
|
return std::move(cond);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -627,16 +628,16 @@ int VmState::loop_while(Ref<Continuation> cond, Ref<Continuation> body, Ref<Cont
|
||||||
return jump(std::move(cond));
|
return jump(std::move(cond));
|
||||||
}
|
}
|
||||||
|
|
||||||
int OrdCont::jump(VmState* st) const & {
|
td::Ref<Continuation> OrdCont::jump(VmState* st, int& exitcode) const& {
|
||||||
st->adjust_cr(data.save);
|
st->adjust_cr(data.save);
|
||||||
st->set_code(code, data.cp);
|
st->set_code(code, data.cp);
|
||||||
return 0;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int OrdCont::jump_w(VmState* st) & {
|
td::Ref<Continuation> OrdCont::jump_w(VmState* st, int& exitcode) & {
|
||||||
st->adjust_cr(std::move(data.save));
|
st->adjust_cr(std::move(data.save));
|
||||||
st->set_code(std::move(code), data.cp);
|
st->set_code(std::move(code), data.cp);
|
||||||
return 0;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OrdCont::serialize(CellBuilder& cb) const {
|
bool OrdCont::serialize(CellBuilder& cb) const {
|
||||||
|
|
|
@ -161,8 +161,8 @@ struct ControlData {
|
||||||
|
|
||||||
class Continuation : public td::CntObject {
|
class Continuation : public td::CntObject {
|
||||||
public:
|
public:
|
||||||
virtual int jump(VmState* st) const & = 0;
|
virtual td::Ref<Continuation> jump(VmState* st, int& exitcode) const& = 0;
|
||||||
virtual int jump_w(VmState* st) &;
|
virtual td::Ref<Continuation> jump_w(VmState* st, int& exitcode) &;
|
||||||
virtual ControlData* get_cdata() {
|
virtual ControlData* get_cdata() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -203,8 +203,9 @@ class QuitCont : public Continuation {
|
||||||
QuitCont(int _code = 0) : exit_code(_code) {
|
QuitCont(int _code = 0) : exit_code(_code) {
|
||||||
}
|
}
|
||||||
~QuitCont() override = default;
|
~QuitCont() override = default;
|
||||||
int jump(VmState* st) const & override {
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override {
|
||||||
return ~exit_code;
|
exitcode = ~exit_code;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
bool serialize(CellBuilder& cb) const override;
|
bool serialize(CellBuilder& cb) const override;
|
||||||
static Ref<QuitCont> deserialize(CellSlice& cs, int mode = 0);
|
static Ref<QuitCont> deserialize(CellSlice& cs, int mode = 0);
|
||||||
|
@ -215,7 +216,7 @@ class ExcQuitCont : public Continuation {
|
||||||
public:
|
public:
|
||||||
ExcQuitCont() = default;
|
ExcQuitCont() = default;
|
||||||
~ExcQuitCont() override = default;
|
~ExcQuitCont() override = default;
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
bool serialize(CellBuilder& cb) const override;
|
bool serialize(CellBuilder& cb) const override;
|
||||||
static Ref<ExcQuitCont> deserialize(CellSlice& cs, int mode = 0);
|
static Ref<ExcQuitCont> deserialize(CellSlice& cs, int mode = 0);
|
||||||
std::string type() const override;
|
std::string type() const override;
|
||||||
|
@ -229,8 +230,8 @@ class PushIntCont : public Continuation {
|
||||||
PushIntCont(int val, Ref<Continuation> _next) : push_val(val), next(_next) {
|
PushIntCont(int val, Ref<Continuation> _next) : push_val(val), next(_next) {
|
||||||
}
|
}
|
||||||
~PushIntCont() override = default;
|
~PushIntCont() override = default;
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
int jump_w(VmState* st) & override;
|
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
|
||||||
bool serialize(CellBuilder& cb) const override;
|
bool serialize(CellBuilder& cb) const override;
|
||||||
static Ref<PushIntCont> deserialize(CellSlice& cs, int mode = 0);
|
static Ref<PushIntCont> deserialize(CellSlice& cs, int mode = 0);
|
||||||
std::string type() const override;
|
std::string type() const override;
|
||||||
|
@ -245,8 +246,8 @@ class RepeatCont : public Continuation {
|
||||||
: body(std::move(_body)), after(std::move(_after)), count(_count) {
|
: body(std::move(_body)), after(std::move(_after)), count(_count) {
|
||||||
}
|
}
|
||||||
~RepeatCont() override = default;
|
~RepeatCont() override = default;
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
int jump_w(VmState* st) & override;
|
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
|
||||||
bool serialize(CellBuilder& cb) const override;
|
bool serialize(CellBuilder& cb) const override;
|
||||||
static Ref<RepeatCont> deserialize(CellSlice& cs, int mode = 0);
|
static Ref<RepeatCont> deserialize(CellSlice& cs, int mode = 0);
|
||||||
std::string type() const override;
|
std::string type() const override;
|
||||||
|
@ -259,8 +260,8 @@ class AgainCont : public Continuation {
|
||||||
AgainCont(Ref<Continuation> _body) : body(std::move(_body)) {
|
AgainCont(Ref<Continuation> _body) : body(std::move(_body)) {
|
||||||
}
|
}
|
||||||
~AgainCont() override = default;
|
~AgainCont() override = default;
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
int jump_w(VmState* st) & override;
|
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
|
||||||
bool serialize(CellBuilder& cb) const override;
|
bool serialize(CellBuilder& cb) const override;
|
||||||
static Ref<AgainCont> deserialize(CellSlice& cs, int mode = 0);
|
static Ref<AgainCont> deserialize(CellSlice& cs, int mode = 0);
|
||||||
std::string type() const override;
|
std::string type() const override;
|
||||||
|
@ -273,8 +274,8 @@ class UntilCont : public Continuation {
|
||||||
UntilCont(Ref<Continuation> _body, Ref<Continuation> _after) : body(std::move(_body)), after(std::move(_after)) {
|
UntilCont(Ref<Continuation> _body, Ref<Continuation> _after) : body(std::move(_body)), after(std::move(_after)) {
|
||||||
}
|
}
|
||||||
~UntilCont() override = default;
|
~UntilCont() override = default;
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
int jump_w(VmState* st) & override;
|
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
|
||||||
bool serialize(CellBuilder& cb) const override;
|
bool serialize(CellBuilder& cb) const override;
|
||||||
static Ref<UntilCont> deserialize(CellSlice& cs, int mode = 0);
|
static Ref<UntilCont> deserialize(CellSlice& cs, int mode = 0);
|
||||||
std::string type() const override;
|
std::string type() const override;
|
||||||
|
@ -289,8 +290,8 @@ class WhileCont : public Continuation {
|
||||||
: cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)), chkcond(_chk) {
|
: cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)), chkcond(_chk) {
|
||||||
}
|
}
|
||||||
~WhileCont() override = default;
|
~WhileCont() override = default;
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
int jump_w(VmState* st) & override;
|
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
|
||||||
bool serialize(CellBuilder& cb) const override;
|
bool serialize(CellBuilder& cb) const override;
|
||||||
static Ref<WhileCont> deserialize(CellSlice& cs, int mode = 0);
|
static Ref<WhileCont> deserialize(CellSlice& cs, int mode = 0);
|
||||||
std::string type() const override;
|
std::string type() const override;
|
||||||
|
@ -312,8 +313,8 @@ class ArgContExt : public Continuation {
|
||||||
ArgContExt(const ArgContExt&) = default;
|
ArgContExt(const ArgContExt&) = default;
|
||||||
ArgContExt(ArgContExt&&) = default;
|
ArgContExt(ArgContExt&&) = default;
|
||||||
~ArgContExt() override = default;
|
~ArgContExt() override = default;
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
int jump_w(VmState* st) & override;
|
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
|
||||||
ControlData* get_cdata() override {
|
ControlData* get_cdata() override {
|
||||||
return &data;
|
return &data;
|
||||||
}
|
}
|
||||||
|
@ -354,8 +355,8 @@ class OrdCont : public Continuation {
|
||||||
td::CntObject* make_copy() const override {
|
td::CntObject* make_copy() const override {
|
||||||
return new OrdCont{*this};
|
return new OrdCont{*this};
|
||||||
}
|
}
|
||||||
int jump(VmState* st) const & override;
|
td::Ref<Continuation> jump(VmState* st, int& exitcode) const& override;
|
||||||
int jump_w(VmState* st) & override;
|
td::Ref<Continuation> jump_w(VmState* st, int& exitcode) & override;
|
||||||
|
|
||||||
ControlData* get_cdata() override {
|
ControlData* get_cdata() override {
|
||||||
return &data;
|
return &data;
|
||||||
|
|
|
@ -118,6 +118,7 @@ class VmState final : public VmStateInterface {
|
||||||
stack_entry_gas_price = 1,
|
stack_entry_gas_price = 1,
|
||||||
runvm_gas_price = 40,
|
runvm_gas_price = 40,
|
||||||
hash_ext_entry_gas_price = 1,
|
hash_ext_entry_gas_price = 1,
|
||||||
|
free_nested_cont_jump = 8,
|
||||||
|
|
||||||
rist255_mul_gas_price = 2000,
|
rist255_mul_gas_price = 2000,
|
||||||
rist255_mulbase_gas_price = 750,
|
rist255_mulbase_gas_price = 750,
|
||||||
|
@ -366,11 +367,19 @@ class VmState final : public VmStateInterface {
|
||||||
return cond ? c1_envelope(std::move(cont), save) : std::move(cont);
|
return cond ? c1_envelope(std::move(cont), save) : std::move(cont);
|
||||||
}
|
}
|
||||||
void c1_save_set(bool save = true);
|
void c1_save_set(bool save = true);
|
||||||
void fatal(void) const {
|
void fatal() const {
|
||||||
throw VmFatal{};
|
throw VmFatal{};
|
||||||
}
|
}
|
||||||
int jump_to(Ref<Continuation> cont) {
|
int jump_to(Ref<Continuation> cont) {
|
||||||
return cont->is_unique() ? cont.unique_write().jump_w(this) : cont->jump(this);
|
int res = 0, cnt = 0;
|
||||||
|
while (cont.not_null()) {
|
||||||
|
cnt++;
|
||||||
|
cont = cont->is_unique() ? cont.unique_write().jump_w(this, res) : cont->jump(this, res);
|
||||||
|
}
|
||||||
|
if (global_version >= 9 && cnt > free_nested_cont_jump) {
|
||||||
|
consume_gas(cnt - free_nested_cont_jump);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell);
|
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell);
|
||||||
bool try_commit();
|
bool try_commit();
|
||||||
|
|
|
@ -109,4 +109,10 @@ Operations for working with Merkle proofs, where cells can have non-zero level a
|
||||||
- Slightly change random seed generation to fix mix of `addr_rewrite` and `addr`.
|
- Slightly change random seed generation to fix mix of `addr_rewrite` and `addr`.
|
||||||
- Fill in `skipped_actions` for both invalid and valid messages with `IGNORE_ERROR` mode that can't be sent.
|
- Fill in `skipped_actions` for both invalid and valid messages with `IGNORE_ERROR` mode that can't be sent.
|
||||||
- Allow unfreeze through external messages.
|
- Allow unfreeze through external messages.
|
||||||
- Don't use user-provided `fwd_fee` and `ihr_fee` for internal messages.
|
- Don't use user-provided `fwd_fee` and `ihr_fee` for internal messages.
|
||||||
|
|
||||||
|
## Version 9
|
||||||
|
|
||||||
|
- Fix `RAWRESERVE` action with flag `4` (use original balance of the account) by explicitly setting `original_balance` to `balance - msg_balance_remaining`.
|
||||||
|
- Previously it did not work if storage fee was greater than the original balance.
|
||||||
|
- Jumps to nested continuations of depth more than 8 consume 1 gas for eact subsequent continuation (this does not affect most of TVM code).
|
Loading…
Reference in a new issue