1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-14 20:22:19 +00:00

vm: bugfixes

This commit is contained in:
ton 2020-03-02 17:52:55 +04:00
parent 27aaa11524
commit ba76f1404e
30 changed files with 396 additions and 178 deletions

View file

@ -91,7 +91,7 @@ class AdnlAddressList {
void update(td::IPAddress addr);
bool public_only() const;
td::uint32 size() const {
return static_cast<td::uint32>(addrs_.size());
return td::narrow_cast<td::uint32>(addrs_.size());
}
td::uint32 serialized_size() const;
tl_object_ptr<ton_api::adnl_addressList> tl() const;

View file

@ -175,18 +175,20 @@ void AdnlLocalId::publish_address_list() {
std::move(P));
}
AdnlLocalId::AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<dht::Dht> dht_node) {
id_ = std::move(id);
AdnlLocalId::AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode,
td::actor::ActorId<AdnlPeerTable> peer_table, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<dht::Dht> dht_node)
: peer_table_(std::move(peer_table))
, keyring_(std::move(keyring))
, dht_node_(std::move(dht_node))
, addr_list_(std::move(addr_list))
, id_(std::move(id))
, mode_(mode) {
short_id_ = id_.compute_short_id();
addr_list_ = std::move(addr_list);
if (!addr_list_.empty()) {
addr_list_.set_reinit_date(Adnl::adnl_start_time());
addr_list_.set_version(static_cast<td::int32>(td::Clocks::system()));
}
peer_table_ = peer_table;
keyring_ = keyring;
dht_node_ = dht_node;
VLOG(ADNL_INFO) << this << ": created local id " << short_id_;
}

View file

@ -67,8 +67,9 @@ class AdnlLocalId : public td::actor::Actor {
void sign_batch_async(std::vector<td::BufferSlice> data,
td::Promise<std::vector<td::Result<td::BufferSlice>>> promise);
AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<dht::Dht> dht_node);
AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode,
td::actor::ActorId<AdnlPeerTable> peer_table, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<dht::Dht> dht_node);
void start_up() override;
void alarm() override;
@ -76,6 +77,10 @@ class AdnlLocalId : public td::actor::Actor {
void update_packet(AdnlPacket packet, bool update_id, bool sign, td::int32 update_addr_list_if,
td::int32 update_priority_addr_list_if, td::Promise<AdnlPacket> promise);
td::uint32 get_mode() {
return mode_;
}
struct PrintId {
AdnlNodeIdShort id;
};
@ -94,6 +99,8 @@ class AdnlLocalId : public td::actor::Actor {
AdnlNodeIdFull id_;
AdnlNodeIdShort short_id_;
td::uint32 mode_;
void publish_address_list();
};

View file

@ -58,9 +58,9 @@ void AdnlPeerTableImpl::receive_packet(td::IPAddress addr, td::BufferSlice data)
AdnlNodeIdShort dst{data.as_slice().truncate(32)};
data.confirm_read(32);
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::receive, addr, std::move(data));
auto it = local_ids_.find(dst);
if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::receive, addr, std::move(data));
return;
}
@ -103,21 +103,22 @@ void AdnlPeerTableImpl::receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket
CHECK(it != peers_.end());
}
auto it2 = local_ids_own_.find(dst);
if (it2 == local_ids_own_.end()) {
auto it2 = local_ids_.find(dst);
if (it2 == local_ids_.end()) {
VLOG(ADNL_ERROR) << this << ": dropping IN message [" << packet.from_short() << "->" << dst
<< "]: unknown dst (but how did we decrypt message?)";
return;
}
td::actor::send_closure(it->second, &AdnlPeer::receive_packet, dst, it2->second.get(), std::move(packet));
td::actor::send_closure(it->second, &AdnlPeer::receive_packet, dst, it2->second.second, it2->second.first.get(),
std::move(packet));
}
void AdnlPeerTableImpl::add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) {
auto id_short = id.compute_short_id();
VLOG(ADNL_DEBUG) << this << ": adding peer " << id_short << " for local id " << local_id;
auto it2 = local_ids_own_.find(local_id);
CHECK(it2 != local_ids_own_.end());
auto it2 = local_ids_.find(local_id);
CHECK(it2 != local_ids_.end());
auto it = peers_.find(id_short);
if (it == peers_.end()) {
@ -126,7 +127,8 @@ void AdnlPeerTableImpl::add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, Ad
}
td::actor::send_closure(it->second, &AdnlPeer::update_id, std::move(id));
if (!addr_list.empty()) {
td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.get(), std::move(addr_list));
td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.second,
it2->second.first.get(), std::move(addr_list));
}
}
@ -143,13 +145,14 @@ void AdnlPeerTableImpl::send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst
it = peers_.emplace(dst, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, dst)).first;
}
auto it2 = local_ids_own_.find(src);
if (it2 == local_ids_own_.end()) {
auto it2 = local_ids_.find(src);
if (it2 == local_ids_.end()) {
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst << "]: unknown src";
return;
}
td::actor::send_closure(it->second, &AdnlPeer::send_one_message, src, it2->second.get(), std::move(message));
td::actor::send_closure(it->second, &AdnlPeer::send_one_message, src, it2->second.second, it2->second.first.get(),
std::move(message));
}
void AdnlPeerTableImpl::answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id,
@ -175,59 +178,61 @@ void AdnlPeerTableImpl::send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std
it = peers_.emplace(dst, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, dst)).first;
}
auto it2 = local_ids_own_.find(src);
if (it2 == local_ids_own_.end()) {
auto it2 = local_ids_.find(src);
if (it2 == local_ids_.end()) {
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst << "]: unknown src";
return;
}
td::actor::send_closure(it->second, &AdnlPeer::send_query, src, it2->second.get(), name, std::move(promise), timeout,
std::move(data));
td::actor::send_closure(it->second, &AdnlPeer::send_query, src, it2->second.second, it2->second.first.get(), name,
std::move(promise), timeout, std::move(data));
}
void AdnlPeerTableImpl::add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) {
void AdnlPeerTableImpl::add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode) {
auto a = id.compute_short_id();
VLOG(ADNL_INFO) << "adnl: adding local id " << a;
auto it = local_ids_own_.find(a);
auto it = local_ids_.find(a);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::update_address_list, std::move(addr_list));
if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::update_address_list, std::move(addr_list));
} else {
local_ids_own_[a] = td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list),
actor_id(this), keyring_, dht_node_);
local_ids_.emplace(
a, std::make_pair(td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list), mode,
actor_id(this), keyring_, dht_node_),
mode));
}
}
void AdnlPeerTableImpl::del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) {
VLOG(ADNL_INFO) << "adnl: deleting local id " << id;
local_ids_own_.erase(id);
local_ids_.erase(id);
promise.set_value(td::Unit());
}
void AdnlPeerTableImpl::subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) {
auto it = local_ids_own_.find(dst);
LOG_CHECK(it != local_ids_own_.end()) << "dst=" << dst;
auto it = local_ids_.find(dst);
LOG_CHECK(it != local_ids_.end()) << "dst=" << dst;
td::actor::send_closure(it->second, &AdnlLocalId::subscribe, prefix, std::move(callback));
td::actor::send_closure(it->second.first, &AdnlLocalId::subscribe, prefix, std::move(callback));
}
void AdnlPeerTableImpl::unsubscribe(AdnlNodeIdShort dst, std::string prefix) {
auto it = local_ids_own_.find(dst);
auto it = local_ids_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::unsubscribe, prefix);
if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::unsubscribe, prefix);
}
}
void AdnlPeerTableImpl::register_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
dht_node_ = dht_node;
for (auto it = peers_.begin(); it != peers_.end(); it++) {
td::actor::send_closure(it->second, &AdnlPeer::update_dht_node, dht_node_);
for (auto &peer : peers_) {
td::actor::send_closure(peer.second, &AdnlPeer::update_dht_node, dht_node_);
}
for (auto it = local_ids_own_.begin(); it != local_ids_own_.end(); it++) {
td::actor::send_closure(it->second, &AdnlLocalId::update_dht_node, dht_node_);
for (auto &local_id : local_ids_) {
td::actor::send_closure(local_id.second.first, &AdnlLocalId::update_dht_node, dht_node_);
}
}
@ -251,21 +256,21 @@ void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkM
}
void AdnlPeerTableImpl::get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) {
auto it = local_ids_own_.find(id);
if (it == local_ids_own_.end()) {
auto it = local_ids_.find(id);
if (it == local_ids_.end()) {
promise.set_error(td::Status::Error(ErrorCode::notready));
return;
}
td::actor::send_closure(it->second, &AdnlLocalId::get_addr_list_async, std::move(promise));
td::actor::send_closure(it->second.first, &AdnlLocalId::get_addr_list_async, std::move(promise));
}
void AdnlPeerTableImpl::get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) {
auto it = local_ids_own_.find(id);
if (it == local_ids_own_.end()) {
auto it = local_ids_.find(id);
if (it == local_ids_.end()) {
promise.set_error(td::Status::Error(ErrorCode::notready));
return;
}
td::actor::send_closure(it->second, &AdnlLocalId::get_self_node, std::move(promise));
td::actor::send_closure(it->second.first, &AdnlLocalId::get_self_node, std::move(promise));
}
void AdnlPeerTableImpl::register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) {
@ -309,16 +314,16 @@ AdnlPeerTableImpl::AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<key
}
void AdnlPeerTableImpl::deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) {
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::deliver, src, std::move(data));
auto it = local_ids_.find(dst);
if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::deliver, src, std::move(data));
}
}
void AdnlPeerTableImpl::deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::deliver_query, src, std::move(data), std::move(promise));
auto it = local_ids_.find(dst);
if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::deliver_query, src, std::move(data), std::move(promise));
} else {
LOG(WARNING) << "deliver query: unknown dst " << dst;
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot deliver: unknown DST"));
@ -327,9 +332,9 @@ void AdnlPeerTableImpl::deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst,
void AdnlPeerTableImpl::decrypt_message(AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::decrypt_message, std::move(data), std::move(promise));
auto it = local_ids_.find(dst);
if (it != local_ids_.end()) {
td::actor::send_closure(it->second.first, &AdnlLocalId::decrypt_message, std::move(data), std::move(promise));
} else {
LOG(WARNING) << "decrypt message: unknown dst " << dst;
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot decrypt: unknown DST"));

View file

@ -61,7 +61,7 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
td::Timestamp timeout, td::BufferSlice data, td::uint64 max_answer_size) override {
send_query(src, dst, name, std::move(promise), timeout, std::move(data));
}
void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) override;
void add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode) override;
void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) override;
void subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) override;
void unsubscribe(AdnlNodeIdShort dst, std::string prefix) override;
@ -111,7 +111,7 @@ class AdnlPeerTableImpl : public AdnlPeerTable {
void deliver_one_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message);
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeer>> peers_;
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlLocalId>> local_ids_own_;
std::map<AdnlNodeIdShort, std::pair<td::actor::ActorOwn<AdnlLocalId>, td::uint32>> local_ids_;
std::map<AdnlChannelIdShort, td::actor::ActorId<AdnlChannel>> channels_;
td::actor::ActorOwn<AdnlDb> db_;

View file

@ -420,7 +420,7 @@ void AdnlPeerPairImpl::alarm_query(AdnlQueryId id) {
}
AdnlPeerPairImpl::AdnlPeerPairImpl(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlPeerTable> peer_table, td::uint32 local_mode,
td::actor::ActorId<AdnlLocalId> local_actor, td::actor::ActorId<AdnlPeer> peer,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
AdnlNodeIdShort peer_id) {
@ -429,6 +429,7 @@ AdnlPeerPairImpl::AdnlPeerPairImpl(td::actor::ActorId<AdnlNetworkManager> networ
local_actor_ = local_actor;
peer_ = peer;
dht_node_ = dht_node;
mode_ = local_mode;
local_id_ = local_id;
peer_id_short_ = peer_id;
@ -683,17 +684,20 @@ void AdnlPeerPairImpl::update_addr_list(AdnlAddressList addr_list) {
const auto addrs = addr_list.addrs();
std::vector<Conn> conns;
conns.resize(std::min(addr_list.size(), 3u));
auto &old_conns = priority ? priority_conns_ : conns_;
for (size_t i = 0; i < conns.size(); i++) {
auto &addr = addrs[i];
auto hash = addr->get_hash();
if (i < old_conns.size() && old_conns[i].addr->get_hash() == hash) {
conns[i] = std::move(old_conns[i]);
} else {
conns[i] = Conn{addr, actor_id(this), network_manager_};
size_t idx = 0;
for (const auto &addr : addrs) {
if ((mode_ & static_cast<td::uint32>(AdnlLocalIdMode::direct_only)) && !addr->is_public()) {
continue;
}
auto hash = addr->get_hash();
if (idx < old_conns.size() && old_conns[idx].addr->get_hash() == hash) {
conns.push_back(std::move(old_conns[idx]));
} else {
conns.push_back(Conn{addr, actor_id(this), network_manager_});
}
idx++;
}
old_conns = std::move(conns);
@ -728,14 +732,12 @@ void AdnlPeerPairImpl::conn_change_state(AdnlConnectionIdShort id, bool ready) {
}
}
td::actor::ActorOwn<AdnlPeerPair> AdnlPeerPair::create(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlLocalId> local_actor,
td::actor::ActorId<AdnlPeer> peer_actor,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
AdnlNodeIdShort peer_id) {
auto X = td::actor::create_actor<AdnlPeerPairImpl>("peerpair", network_manager, peer_table, local_actor, peer_actor,
dht_node, local_id, peer_id);
td::actor::ActorOwn<AdnlPeerPair> AdnlPeerPair::create(
td::actor::ActorId<AdnlNetworkManager> network_manager, td::actor::ActorId<AdnlPeerTable> peer_table,
td::uint32 local_mode, td::actor::ActorId<AdnlLocalId> local_actor, td::actor::ActorId<AdnlPeer> peer_actor,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id) {
auto X = td::actor::create_actor<AdnlPeerPairImpl>("peerpair", network_manager, peer_table, local_mode, local_actor,
peer_actor, dht_node, local_id, peer_id);
return td::actor::ActorOwn<AdnlPeerPair>(std::move(X));
}
@ -746,15 +748,16 @@ td::actor::ActorOwn<AdnlPeer> AdnlPeer::create(td::actor::ActorId<AdnlNetworkMan
return td::actor::ActorOwn<AdnlPeer>(std::move(X));
}
void AdnlPeerImpl::receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket packet) {
void AdnlPeerImpl::receive_packet(AdnlNodeIdShort dst, td::uint32 dst_mode, td::actor::ActorId<AdnlLocalId> dst_actor,
AdnlPacket packet) {
if (packet.inited_from()) {
update_id(packet.from());
}
auto it = peer_pairs_.find(dst);
if (it == peer_pairs_.end()) {
auto X =
AdnlPeerPair::create(network_manager_, peer_table_, dst_actor, actor_id(this), dht_node_, dst, peer_id_short_);
auto X = AdnlPeerPair::create(network_manager_, peer_table_, dst_mode, dst_actor, actor_id(this), dht_node_, dst,
peer_id_short_);
peer_pairs_.emplace(dst, std::move(X));
it = peer_pairs_.find(dst);
CHECK(it != peer_pairs_.end());
@ -767,12 +770,12 @@ void AdnlPeerImpl::receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLo
td::actor::send_closure(it->second.get(), &AdnlPeerPair::receive_packet_checked, std::move(packet));
}
void AdnlPeerImpl::send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
void AdnlPeerImpl::send_messages(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor,
std::vector<AdnlMessage> messages) {
auto it = peer_pairs_.find(src);
if (it == peer_pairs_.end()) {
auto X =
AdnlPeerPair::create(network_manager_, peer_table_, src_actor, actor_id(this), dht_node_, src, peer_id_short_);
auto X = AdnlPeerPair::create(network_manager_, peer_table_, src_mode, src_actor, actor_id(this), dht_node_, src,
peer_id_short_);
peer_pairs_.emplace(src, std::move(X));
it = peer_pairs_.find(src);
CHECK(it != peer_pairs_.end());
@ -785,12 +788,13 @@ void AdnlPeerImpl::send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLoc
td::actor::send_closure(it->second, &AdnlPeerPair::send_messages, std::move(messages));
}
void AdnlPeerImpl::send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) {
void AdnlPeerImpl::send_query(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor,
std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice data) {
auto it = peer_pairs_.find(src);
if (it == peer_pairs_.end()) {
auto X =
AdnlPeerPair::create(network_manager_, peer_table_, src_actor, actor_id(this), dht_node_, src, peer_id_short_);
auto X = AdnlPeerPair::create(network_manager_, peer_table_, src_mode, src_actor, actor_id(this), dht_node_, src,
peer_id_short_);
peer_pairs_.emplace(src, std::move(X));
it = peer_pairs_.find(src);
CHECK(it != peer_pairs_.end());
@ -814,12 +818,12 @@ void AdnlPeerImpl::update_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
}
}
void AdnlPeerImpl::update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
AdnlAddressList addr_list) {
void AdnlPeerImpl::update_addr_list(AdnlNodeIdShort local_id, td::uint32 local_mode,
td::actor::ActorId<AdnlLocalId> local_actor, AdnlAddressList addr_list) {
auto it = peer_pairs_.find(local_id);
if (it == peer_pairs_.end()) {
auto X = AdnlPeerPair::create(network_manager_, peer_table_, local_actor, actor_id(this), dht_node_, local_id,
peer_id_short_);
auto X = AdnlPeerPair::create(network_manager_, peer_table_, local_mode, local_actor, actor_id(this), dht_node_,
local_id, peer_id_short_);
peer_pairs_.emplace(local_id, std::move(X));
it = peer_pairs_.find(local_id);
CHECK(it != peer_pairs_.end());

View file

@ -60,7 +60,7 @@ class AdnlPeerPair : public td::actor::Actor {
virtual void update_addr_list(AdnlAddressList addr_list) = 0;
static td::actor::ActorOwn<AdnlPeerPair> create(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlPeerTable> peer_table, td::uint32 local_mode,
td::actor::ActorId<AdnlLocalId> local_actor,
td::actor::ActorId<AdnlPeer> peer_actor,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
@ -69,20 +69,24 @@ class AdnlPeerPair : public td::actor::Actor {
class AdnlPeer : public td::actor::Actor {
public:
virtual void receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket message) = 0;
virtual void send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
virtual void receive_packet(AdnlNodeIdShort dst, td::uint32 dst_mode, td::actor::ActorId<AdnlLocalId> dst_actor,
AdnlPacket message) = 0;
virtual void send_messages(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor,
std::vector<AdnlMessage> messages) = 0;
virtual void send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) = 0;
void send_one_message(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, AdnlMessage message) {
virtual void send_query(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor,
std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice data) = 0;
void send_one_message(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor,
AdnlMessage message) {
std::vector<AdnlMessage> vec;
vec.push_back(std::move(message));
send_messages(src, src_actor, std::move(vec));
send_messages(src, src_mode, src_actor, std::move(vec));
}
void send_message(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, td::BufferSlice data) {
void send_message(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor,
td::BufferSlice data) {
auto M = AdnlMessage{adnlmessage::AdnlMessageCustom{std::move(data)}};
send_one_message(src, src_actor, std::move(M));
send_one_message(src, src_mode, src_actor, std::move(M));
}
static td::actor::ActorOwn<AdnlPeer> create(td::actor::ActorId<AdnlNetworkManager> network_manager,
@ -91,8 +95,8 @@ class AdnlPeer : public td::actor::Actor {
virtual void del_local_id(AdnlNodeIdShort local_id) = 0;
virtual void update_id(AdnlNodeIdFull id) = 0;
virtual void update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
AdnlAddressList addr_list) = 0;
virtual void update_addr_list(AdnlNodeIdShort local_id, td::uint32 local_mode,
td::actor::ActorId<AdnlLocalId> local_actor, AdnlAddressList addr_list) = 0;
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) = 0;
};

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
@ -58,8 +58,9 @@ class AdnlPeerPairImpl : public AdnlPeerPair {
}
AdnlPeerPairImpl(td::actor::ActorId<AdnlNetworkManager> network_manager, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlLocalId> local_actor, td::actor::ActorId<AdnlPeer> peer,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id);
td::uint32 local_mode, td::actor::ActorId<AdnlLocalId> local_actor,
td::actor::ActorId<AdnlPeer> peer, td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
AdnlNodeIdShort peer_id);
void start_up() override;
void alarm() override;
@ -232,6 +233,8 @@ class AdnlPeerPairImpl : public AdnlPeerPair {
std::map<AdnlQueryId, td::actor::ActorId<AdnlQuery>> out_queries_;
td::uint32 mode_;
td::uint32 received_messages_ = 0;
bool received_from_db_ = false;
bool received_from_static_nodes_ = false;
@ -244,15 +247,16 @@ class AdnlPeerPairImpl : public AdnlPeerPair {
class AdnlPeerImpl : public AdnlPeer {
public:
void receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket packet) override;
void send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
void receive_packet(AdnlNodeIdShort dst, td::uint32 dst_mode, td::actor::ActorId<AdnlLocalId> dst_actor,
AdnlPacket packet) override;
void send_messages(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor,
std::vector<AdnlMessage> messages) override;
void send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
void send_query(AdnlNodeIdShort src, td::uint32 src_mode, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) override;
void del_local_id(AdnlNodeIdShort local_id) override;
void update_id(AdnlNodeIdFull id) override;
void update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
void update_addr_list(AdnlNodeIdShort local_id, td::uint32 local_mode, td::actor::ActorId<AdnlLocalId> local_actor,
AdnlAddressList addr_list) override;
void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) override;
//void check_signature(td::BufferSlice data, td::BufferSlice signature, td::Promise<td::Unit> promise) override;

View file

@ -34,6 +34,8 @@ class Dht;
namespace adnl {
enum class AdnlLocalIdMode : td::uint32 { direct_only = 1, drop_from_net = 2 };
class AdnlNetworkManager;
class AdnlExtServer : public td::actor::Actor {
@ -81,7 +83,10 @@ class Adnl : public AdnlSenderInterface {
virtual void add_static_nodes_from_config(AdnlNodesList nodes) = 0;
// adds local id. After that you can send/receive messages from/to this id
virtual void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) = 0;
void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) {
add_id_ex(std::move(id), std::move(addr_list), 0);
}
virtual void add_id_ex(AdnlNodeIdFull id, AdnlAddressList addr_list, td::uint32 mode) = 0;
virtual void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) = 0;
// subscribe to (some) messages(+queries) to this local id

View file

@ -344,11 +344,11 @@ unsigned long long VarUIntegerPos::as_uint(const vm::CellSlice& cs) const {
bool VarUIntegerPos::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
int k = value.bit_size(false);
return k <= (n - 1) * 8 && value.sgn() > 0 && cb.store_long_bool((k + 7) >> 3, ln) &&
return k <= (n - 1) * 8 && value.sgn() >= (int)store_pos_only && cb.store_long_bool((k + 7) >> 3, ln) &&
cb.store_int256_bool(value, (k + 7) & -8, false);
}
const VarUIntegerPos t_VarUIntegerPos_16{16}, t_VarUIntegerPos_32{32};
const VarUIntegerPos t_VarUIntegerPos_16{16}, t_VarUIntegerPos_32{32}, t_VarUIntegerPosRelaxed_32{32, true};
static inline bool redundant_int(const vm::CellSlice& cs) {
int t = (int)cs.prefetch_long(9);

View file

@ -77,7 +77,8 @@ extern const VarUInteger t_VarUInteger_3, t_VarUInteger_7, t_VarUInteger_16, t_V
struct VarUIntegerPos final : TLB_Complex {
int n, ln;
VarUIntegerPos(int _n) : n(_n) {
bool store_pos_only;
VarUIntegerPos(int _n, bool relaxed = false) : n(_n), store_pos_only(!relaxed) {
ln = 32 - td::count_leading_zeroes32(n - 1);
}
bool skip(vm::CellSlice& cs) const override;
@ -90,7 +91,7 @@ struct VarUIntegerPos final : TLB_Complex {
}
};
extern const VarUIntegerPos t_VarUIntegerPos_16, t_VarUIntegerPos_32;
extern const VarUIntegerPos t_VarUIntegerPos_16, t_VarUIntegerPos_32, t_VarUIntegerPosRelaxed_32;
struct VarInteger final : TLB_Complex {
int n, ln;
@ -325,7 +326,7 @@ extern const MsgAddress t_MsgAddress;
struct ExtraCurrencyCollection final : TLB {
HashmapE dict_type, dict_type2;
ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32), dict_type2(32, t_VarUInteger_32) {
ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32), dict_type2(32, t_VarUIntegerPosRelaxed_32) {
}
int get_size(const vm::CellSlice& cs) const override {
return dict_type.get_size(cs);

View file

@ -724,7 +724,12 @@ void interpret_tlb_validate_skip(vm::Stack& stack) {
stack.push_bool(ok);
}
void interpret_tlb_type_const(vm::Stack& stack, const tlb::TLB* ptr) {
stack.push_make_object<tlb::TlbTypeHolder>(ptr);
}
void init_words_tlb(fift::Dictionary& d) {
using namespace std::placeholders;
tlb_dict.register_types(block::gen::register_simple_types);
d.def_stack_word("tlb-type-lookup ", interpret_tlb_type_lookup);
d.def_stack_word("tlb-type-name ", interpret_tlb_type_name);
@ -733,6 +738,7 @@ void init_words_tlb(fift::Dictionary& d) {
d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str);
d.def_stack_word("tlb-skip ", interpret_tlb_skip);
d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip);
d.def_stack_word("ExtraCurrencyCollection", std::bind(interpret_tlb_type_const, _1, &block::tlb::t_ExtraCurrencyCollection));
}
void usage(const char* progname) {

View file

@ -111,6 +111,8 @@ variable base
{ cdr cdr } : cddr
{ cdr cdr car } : caddr
{ null ' cons rot times } : list
{ -rot pair swap ! } : 2!
{ @ unpair } : 2@
{ true (atom) drop } : atom
{ bl word atom 1 'nop } ::_ `
{ hole dup 1 { @ execute } does create } : recursive
@ -121,13 +123,18 @@ variable base
{ 0 word -trailing scan-until-word 1 'nop } ::_ $<<
{ 0x40 runvmx } : runvmcode
{ 0x48 runvmx } : gasrunvmcode
{ 0xc8 runvmx } : gas2runvmcode
{ 0x43 runvmx } : runvmdict
{ 0x4b runvmx } : gasrunvmdict
{ 0xcb runvmx } : gas2runvmdict
{ 0x45 runvmx } : runvm
{ 0x4d runvmx } : gasrunvm
{ 0xcd runvmx } : gas2runvm
{ 0x55 runvmx } : runvmctx
{ 0x5d runvmx } : gasrunvmctx
{ 0xdd runvmx } : gas2runvmctx
{ 0x75 runvmx } : runvmctxact
{ 0x7d runvmx } : gasrunvmctxact
{ 0xfd runvmx } : gas2runvmctxact
{ 0x35 runvmx } : runvmctxactq
{ 0x3d runvmx } : gasrunvmctxactq

View file

@ -77,9 +77,10 @@ library TonUtil // TON Blockchain Fift Library
1000000000 constant Gram
{ Gram swap */r } : Gram*/
{ Gram * } : Gram*
{ (number) dup { 1- ' Gram*/ ' Gram* cond true } if
} : $>GR?
// ( S -- nanograms )
{ (number) ?dup 0= abort"not a valid Gram amount"
1- ' Gram*/ ' Gram* cond
{ $>GR? not abort"not a valid Gram amount"
} : $>GR
{ bl word $>GR 1 'nop } ::_ GR$
// ( nanograms -- S )
@ -119,7 +120,7 @@ dictnew constant cc0 // zero currency collection
{ swap cc-key-bits { rot { ."+" } if .val ."*$" ._ true true } idictforeach drop } : (.cc)
{ false (.cc) { ."0" } ifnot } : .cc_
{ .cc_ space } : .cc
{ true (.cc) } : .+cc_
{ true (.cc) drop } : .+cc_
{ .+cc_ space } : .+cc
{ cc-key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-cc-diff
{ cc-key-bits { val@ swap val@ + val, true } dictmerge } : cc+
@ -141,13 +142,30 @@ forget val, forget val@ forget .val
} cond } cond } cond } cond
} : cc-key-value?
// ( S -- D -1 or 0 ) Parses an extra currency collection
// e.g. "10000*$3+7777*$-11" means "10000 units of currency #3 and 7777 units of currency #-11"
{ dictnew { // S D
swap dup "+" $pos dup 0< { drop null -rot } { $| 1 $| nip -rot } cond
cc-key-value? { +ccpair over null? dup { rot drop true } if } { 2drop false true } cond
} until
} : $>xcc?
{ $>xcc? not abort"invalid extra currency collection" } : $>xcc
{ char } word dup $len { $>xcc } { drop dictnew } cond 1 'nop } ::_ CX{
// complete currency collections
{ $>xcc? { true } { drop false } cond } : end-parse-cc
// ( S -- x D -1 or 0 ) Parses a currency collection
// e.g. "1.2+300*$2" means "1200000000ng plus 300 units of currency #2"
{ 0 swap dup "+" $pos dup 0< { drop dup
$>GR? { nip nip dictnew true } { end-parse-cc } cond
} { over swap $| swap $>GR? { 2swap 2drop swap 1 $| nip } { drop
} cond end-parse-cc } cond
} : $>cc?
{ $>cc? not abort"invalid extra currency collection" } : $>cc
{ char } word dup $len { $>cc } { drop dictnew } cond 1 'nop } ::_ CX{
{ $>cc? not abort"invalid currency collection" } : $>cc
{ char } word dup $len { $>cc } { drop 0 dictnew } cond 2 'nop } ::_ CC{
// ( x D -- )
{ swap ?dup { .GR_ .+cc_ } { .cc_ } cond } : .GR+cc_
{ .GR+cc_ space } : .GR+cc
{ -rot Gram, swap dict, } : Gram+cc,
// Libraries
// ( -- D ) New empty library collection

View file

@ -2242,6 +2242,7 @@ std::vector<Ref<vm::Cell>> get_vm_libraries() {
// +16 = load c7 (smart-contract context)
// +32 = return c5 (actions)
// +64 = log vm ops to stderr
// +128 = pop hard gas limit (enabled by ACCEPT) from stack as well
void interpret_run_vm(IntCtx& ctx, int mode) {
if (mode < 0) {
mode = ctx.stack.pop_smallint_range(0xff);
@ -2249,7 +2250,13 @@ void interpret_run_vm(IntCtx& ctx, int mode) {
bool with_data = mode & 4;
Ref<vm::Tuple> c7;
Ref<vm::Cell> data, actions;
long long gas_max = (mode & 128) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty;
long long gas_limit = (mode & 8) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty;
if (!(mode & 128)) {
gas_max = gas_limit;
} else {
gas_max = std::max(gas_max, gas_limit);
}
if (mode & 16) {
c7 = ctx.stack.pop_tuple();
}
@ -2259,7 +2266,7 @@ void interpret_run_vm(IntCtx& ctx, int mode) {
auto cs = ctx.stack.pop_cellslice();
OstreamLogger ostream_logger(ctx.error_stream);
auto log = create_vm_log((mode & 64) && ctx.error_stream ? &ostream_logger : nullptr);
vm::GasLimits gas{gas_limit};
vm::GasLimits gas{gas_limit, gas_max};
int res =
vm::run_vm_code(cs, ctx.stack, mode & 3, &data, log, nullptr, &gas, get_vm_libraries(), std::move(c7), &actions);
ctx.stack.push_smallint(res);

View file

@ -9,9 +9,11 @@ true =: allow-bounce
false =: force-bounce
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
60 =: timeout // external message expires in 60 seconds
variable extra-currencies
{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+!
begin-options
" <filename-base> <dest-addr> <seqno> <amount> [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
" <filename-base> <dest-addr> <seqno> <amount> [-x <extra-amount>*<extra-currency-id>] [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
+"Creates a request to advanced wallet created by new-wallet-v2.fif, with private key loaded from file <filename-base>.pk "
+"and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
disable-digit-options generic-help-setopt
@ -19,6 +21,8 @@ begin-options
"Clears bounce flag" option-help
"b" "--force-bounce" { true =: force-bounce } short-long-option
"Forces bounce flag" option-help
"x" "--extra" { $>xcc extra-cc+! } short-long-option-arg
"Indicates the amount of extra currencies to be transfered" option-help
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
"B" "--body" { =: body-boc-file } short-long-option-arg
@ -38,7 +42,7 @@ true constant bounce
$1 =: file-base
$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr
$3 parse-int =: seqno
$4 $>GR =: amount
$4 $>cc extra-cc+! extra-currencies @ 2=: amount
$5 "wallet-query" replace-if-null =: savefile
file-base +".addr" load-address
@ -49,13 +53,13 @@ file-base +".pk" load-keypair nip constant wallet_pk
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
constant body-cell
."Transferring " amount .GR ."to account "
."Transferring " amount .GR+cc ."to account "
dest_addr 2dup bounce 7 + .Addr ." = " .addr
."seqno=0x" seqno x. ."bounce=" bounce . cr
."Body of transfer message is " body-cell <s csr. cr
// create a message
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, 0 9 64 32 + + 1+ u,
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
b>
<b seqno 32 u, now timeout + 32 u, send-mode 8 u, swap ref, b>

View file

@ -9,9 +9,11 @@ true =: allow-bounce
false =: force-bounce
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
60 =: timeout // external message expires in 60 seconds
variable extra-currencies
{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+!
begin-options
" <filename-base> <dest-addr> <subwallet-id> <seqno> <amount> [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
" <filename-base> <dest-addr> <subwallet-id> <seqno> <amount> [-x <extra-amount>*<extra-currency-id>] [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
+"Creates a request to advanced wallet created by new-wallet-v3.fif, with private key loaded from file <filename-base>.pk "
+"and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
disable-digit-options generic-help-setopt
@ -19,6 +21,8 @@ begin-options
"Clears bounce flag" option-help
"b" "--force-bounce" { true =: force-bounce } short-long-option
"Forces bounce flag" option-help
"x" "--extra" { $>xcc extra-cc+! } short-long-option-arg
"Indicates the amount of extra currencies to be transfered" option-help
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
"B" "--body" { =: body-boc-file } short-long-option-arg
@ -40,7 +44,7 @@ $1 =: file-base
$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr
$3 parse-int =: subwallet_id
$4 parse-int =: seqno
$5 $>GR =: amount
$5 $>cc extra-cc+! extra-currencies @ 2=: amount
$6 "wallet-query" replace-if-null =: savefile
file-base +".addr" load-address
@ -51,14 +55,14 @@ file-base +".pk" load-keypair nip constant wallet_pk
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
constant body-cell
."Transferring " amount .GR ."to account "
."Transferring " amount .GR+cc ."to account "
dest_addr 2dup bounce 7 + .Addr ." = " .addr
."subwallet_id=0x" subwallet_id x.
."seqno=0x" seqno x. ."bounce=" bounce . cr
."Body of transfer message is " body-cell <s csr. cr
// create a message
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, 0 9 64 32 + + 1+ u,
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
b>
<b subwallet_id 32 u, now timeout + 32 u, seqno 32 u, send-mode 8 u, swap ref, b>

View file

@ -9,6 +9,7 @@ true =: allow-bounce
false =: force-bounce
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
variable extra-currencies
{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+!
begin-options
" <filename-base> <dest-addr> <seqno> <amount> [-x <extra-amount>*<extra-currency-id>] [-n|-b] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
@ -19,7 +20,7 @@ begin-options
"Clears bounce flag" option-help
"b" "--force-bounce" { true =: force-bounce } short-long-option
"Forces bounce flag" option-help
"x" "--extra" { $>cc extra-currencies @ cc+ extra-currencies ! } short-long-option-arg
"x" "--extra" { $>xcc extra-cc+! } short-long-option-arg
"Indicates the amount of extra currencies to be transfered" option-help
"B" "--body" { =: body-boc-file } short-long-option-arg
"Sets the payload of the transfer message" option-help
@ -38,7 +39,7 @@ true =: bounce
$1 =: file-base
$2 bounce parse-load-address allow-bounce and force-bounce or =: bounce 2=: dest_addr
$3 parse-int =: seqno
$4 $>GR =: amount
$4 $>cc extra-cc+! extra-currencies @ 2=: amount
$5 "wallet-query" replace-if-null =: savefile
allow-bounce not force-bounce and abort"cannot have bounce flag both set and cleared"
// "" 1 { 69091 * 1+ 65535 and tuck 2521 / 65 + hold swap } 1000 times drop =: comment
@ -51,13 +52,13 @@ file-base +".pk" load-keypair nip constant wallet_pk
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
constant body-cell
."Transferring " amount .GR_ extra-currencies @ .+cc ."to account "
."Transferring " amount .GR+cc ."to account "
dest_addr 2dup bounce 7 + .Addr ." = " .addr
."seqno=0x" seqno x. ."bounce=" bounce . cr
."Body of transfer message is " body-cell <s csr. cr
// create a message
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, extra-currencies @ dict, 0 9 64 32 + + u,
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
b>
<b seqno 32 u, send-mode 8 u, swap ref, b>

View file

@ -0,0 +1,20 @@
#!/usr/bin/fift -s
"Asm.fif" include
2500 =: N
{ 5 * } : *K
N 100 / =: N/100
N 10 / =: N/10
{ { EXECUTE } 100 times } : 100EXECUTE
{ DUP { 2DUP } 7 times } : 15DUP
{ { 2DUP } 50 times } : 100DUP
{ { 15 -1 SETCONTARGS 15DUP } 10 times } : 10SET&DUP
<{
CONT:<{ }>
15DUP
N/10 INT REPEAT:<{ 10SET&DUP }>
N/100 *K INT REPEAT:<{ 100DUP }>
N/100 *K INT REPEAT:<{ 100EXECUTE }>
}>s =: Code
Code csr.
Code 1000000 gasrunvmcode

View file

@ -0,0 +1,32 @@
#!/usr/bin/create-state -s
{ dup tlb-type-lookup { nip } { "unknown TLB type " swap $+ abort } cond } : $>tlb
{ bl word $>tlb 1 'nop } ::_ tlb:
{ dup null? { drop true } {
<b true 1 i, swap ref, b> <s ExtraCurrencyCollection
tlb-validate-skip { empty? } { false } cond
} cond
} : cc-valid?
{ cc-valid? { ."(valid)" } { ."(invalid)" } cond } : .cc-valid
{ { dup .cc space .cc-valid } { ."<error>" } cond cr } : cshow
{ ."X = " over dup .cc space .cc-valid cr
."Y = " dup dup .cc space .cc-valid cr
."X + Y = " 2dup CC+? cshow
."X - Y = " 2dup CC-? cshow
."Y - X = " 2dup swap CC-? cshow
."X + X = " over dup CC+? cshow
."Y + Y = " dup dup CC+? cshow
."X - X = " over dup CC-? cshow
."Y - Y = " dup dup CC-? cshow
2drop ."********************" cr
} : one-test
CX{666666666666*$239+1000000000000*$-17} =: X
X CX{666666666666*$239+4444*$-17} one-test
X CX{666666666665*$239+4444*$-17} one-test
X CX{666666666667*$239+4444*$-17} one-test
X CX{666666666666*$239} one-test
X CX{666666666665*$239} one-test
X CX{666666666667*$239} one-test
X CX{1111*$1} one-test
X CX{0*$-17} one-test
X cc0 1 0 +newccpair one-test
X cc0 239 0 +newccpair one-test

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "vm/boc.h"
#include "vm/cellslice.h"
@ -694,6 +694,32 @@ TEST(TonDb, BenchCellBuilder3) {
td::bench(BenchCellBuilder3());
}
TEST(TonDb, BocFuzz) {
vm::std_boc_deserialize(td::base64_decode("te6ccgEBAQEAAgAoAAA=").move_as_ok()).ensure_error();
vm::std_boc_deserialize(td::base64_decode("te6ccgQBQQdQAAAAAAEAte6ccgQBB1BBAAAAAAEAAAAAAP/"
"wAACJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJicmJiYmJiYmJiYmJiQ0NDQ0NDQ0NDQ0NDQ0ND"
"Q0NiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiQAA//AAAO4=")
.move_as_ok());
vm::std_boc_deserialize(td::base64_decode("SEkh/w==").move_as_ok()).ensure_error();
vm::std_boc_deserialize(
td::base64_decode(
"te6ccqwBMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMAKCEAAAAgAQ==")
.move_as_ok())
.ensure_error();
}
void test_parse_prefix(td::Slice boc) {
for (size_t i = 0; i <= boc.size(); i++) {
auto prefix = boc.substr(0, i);
vm::BagOfCells::Info info;
auto res = info.parse_serialized_header(prefix);
if (res > 0) {
break;
}
CHECK(res != 0);
CHECK(-res > (int)i);
}
}
TEST(TonDb, Boc) {
td::Random::Xorshift128plus rnd{123};
for (int t = 0; t < 1000; t++) {
@ -704,6 +730,8 @@ TEST(TonDb, Boc) {
auto serialized = serialize_boc(std::move(cell), mode);
CHECK(serialized.size() != 0);
test_parse_prefix(serialized);
auto loaded_cell = deserialize_boc(serialized);
ASSERT_EQ(cell_hash, loaded_cell->get_hash());

View file

@ -22,6 +22,7 @@
#include "fift/utils.h"
#include "common/bigint.hpp"
#include "td/utils/base64.h"
#include "td/utils/tests.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/StringBuilder.h"
@ -53,7 +54,10 @@ std::string run_vm(td::Ref<vm::Cell> cell) {
vm::Stack stack;
try {
vm::run_vm_code(vm::load_cell_slice_ref(cell), stack, 0 /*flags*/, nullptr /*data*/, std::move(log) /*VmLog*/);
vm::GasLimits gas_limit(1000, 1000);
vm::run_vm_code(vm::load_cell_slice_ref(cell), stack, 0 /*flags*/, nullptr /*data*/, std::move(log) /*VmLog*/,
nullptr, &gas_limit);
} catch (...) {
LOG(FATAL) << "catch unhandled exception";
}
@ -77,6 +81,14 @@ void test_run_vm(td::Slice code_hex) {
test_run_vm(to_cell(buff, bits));
}
void test_run_vm_raw(td::Slice code64) {
auto code = td::base64_decode(code64).move_as_ok();
if (code.size() > 127) {
code.resize(127);
}
test_run_vm(vm::CellBuilder().store_bytes(code).finalize());
}
TEST(VM, simple) {
test_run_vm("ABCBABABABA");
}
@ -126,12 +138,12 @@ TEST(VM, unhandled_exception_1) {
TEST(VM, unhandled_exception_2) {
// infinite loop now
// test_run_vm("EBEDB4");
test_run_vm("EBEDB4");
}
TEST(VM, unhandled_exception_3) {
// infinite loop now
// test_run_vm("EBEDC0");
test_run_vm("EBEDC0");
}
TEST(VM, unhandled_exception_4) {
@ -142,6 +154,13 @@ TEST(VM, unhandled_exception_5) {
test_run_vm("738B04016D21F41476A721F49F");
}
TEST(VM, infinity_loop_1) {
test_run_vm_raw("f3r4AJGQ6rDraIQ=");
}
TEST(VM, infinity_loop_2) {
test_run_vm_raw("kpTt7ZLrig==");
}
TEST(VM, bigint) {
td::StringBuilder sb({}, true);

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include <iostream>
#include <iomanip>
@ -94,10 +94,8 @@ td::Result<Ref<DataCell>> CellSerializationInfo::create_data_cell(td::Slice cell
for (int k = 0; k < refs_cnt; k++) {
cb.store_ref(std::move(refs[k]));
}
auto res = cb.finalize_novm(special);
if (res.is_null()) {
return td::Status::Error("CellBuilder::finalize failed");
}
TRY_RESULT(res, cb.finalize_novm_nothrow(special));
CHECK(!res.is_null());
if (res->is_special() != special) {
return td::Status::Error("is_special mismatch");
}
@ -654,10 +652,10 @@ long long BagOfCells::Info::parse_serialized_header(const td::Slice& slice) {
ptr += 6;
sz -= 6;
if (sz < ref_byte_size) {
return -(int)roots_offset;
return -static_cast<int>(roots_offset);
}
cell_count = (int)read_ref(ptr);
if (cell_count < 0) {
if (cell_count <= 0) {
cell_count = -1;
return 0;
}
@ -671,7 +669,7 @@ long long BagOfCells::Info::parse_serialized_header(const td::Slice& slice) {
}
index_offset = roots_offset;
if (magic == boc_generic) {
index_offset += root_count * ref_byte_size;
index_offset += (long long)root_count * ref_byte_size;
has_roots = true;
} else {
if (root_count != 1) {
@ -690,12 +688,18 @@ long long BagOfCells::Info::parse_serialized_header(const td::Slice& slice) {
return 0;
}
if (sz < 3 * ref_byte_size + offset_byte_size) {
return -(int)roots_offset;
return -static_cast<int>(roots_offset);
}
data_size = read_offset(ptr + 3 * ref_byte_size);
if (data_size > ((unsigned long long)cell_count << 10)) {
return 0;
}
if (data_size > (1ull << 40)) {
return 0; // bag of cells with more than 1TiB data is unlikely
}
if (data_size < cell_count * (2ull + ref_byte_size) - ref_byte_size) {
return 0; // invalid header, too many cells for this amount of data bytes
}
valid = true;
total_size = data_offset + data_size + (has_crc32c ? 4 : 0);
return total_size;
@ -747,14 +751,13 @@ td::Result<td::Ref<vm::DataCell>> BagOfCells::deserialize_cell(int idx, td::Slic
return cell_info.create_data_cell(cell_slice, refs);
}
td::Result<long long> BagOfCells::deserialize(const td::Slice& data) {
td::Result<long long> BagOfCells::deserialize(const td::Slice& data, int max_roots) {
clear();
long long size_est = info.parse_serialized_header(data);
//LOG(INFO) << "estimated size " << size_est << ", true size " << data.size();
if (size_est == 0) {
return td::Status::Error(PSLICE() << "cannot deserialize bag-of-cells: invalid header, error " << size_est);
}
if (size_est < 0) {
//LOG(ERROR) << "cannot deserialize bag-of-cells: not enough bytes (" << data.size() << " present, " << -size_est
//<< " required)";
@ -767,6 +770,9 @@ td::Result<long long> BagOfCells::deserialize(const td::Slice& data) {
return -size_est;
}
//LOG(INFO) << "estimated size " << size_est << ", true size " << data.size();
if (info.root_count > max_roots) {
return td::Status::Error("Bag-of-cells has more root cells than expected");
}
if (info.has_crc32c) {
unsigned crc_computed = td::crc32c(td::Slice{data.ubegin(), data.uend() - 4});
unsigned crc_stored = td::as<unsigned>(data.uend() - 4);
@ -906,7 +912,7 @@ td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty) {
return Ref<Cell>();
}
BagOfCells boc;
auto res = boc.deserialize(data);
auto res = boc.deserialize(data, 1);
if (res.is_error()) {
return res.move_as_error();
}
@ -923,12 +929,12 @@ td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty) {
return std::move(root);
}
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data) {
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data, int max_roots) {
if (data.empty()) {
return std::vector<Ref<Cell>>{};
}
BagOfCells boc;
auto res = boc.deserialize(data);
auto res = boc.deserialize(data, max_roots);
if (res.is_error()) {
return res.move_as_error();
}

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include <set>
@ -26,12 +26,6 @@
namespace vm {
using td::Ref;
td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty = false);
td::Result<td::BufferSlice> std_boc_serialize(Ref<Cell> root, int mode = 0);
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data);
td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> root, int mode = 0);
class NewCellStorageStat {
public:
NewCellStorageStat() {
@ -159,7 +153,7 @@ struct CellSerializationInfo {
class BagOfCells {
public:
enum { hash_bytes = vm::Cell::hash_bytes };
enum { hash_bytes = vm::Cell::hash_bytes, default_max_roots = 16384 };
enum Mode { WithIndex = 1, WithCRC32C = 2, WithTopHash = 4, WithIntHashes = 8, WithCacheBits = 16, max = 31 };
enum { max_cell_whs = 64 };
using Hash = Cell::Hash;
@ -259,9 +253,10 @@ class BagOfCells {
std::size_t serialize_to(unsigned char* buffer, std::size_t buff_size, int mode = 0);
std::string extract_string() const;
td::Result<long long> deserialize(const td::Slice& data);
td::Result<long long> deserialize(const unsigned char* buffer, std::size_t buff_size) {
return deserialize(td::Slice{buffer, buff_size});
td::Result<long long> deserialize(const td::Slice& data, int max_roots = default_max_roots);
td::Result<long long> deserialize(const unsigned char* buffer, std::size_t buff_size,
int max_roots = default_max_roots) {
return deserialize(td::Slice{buffer, buff_size}, max_roots);
}
int get_root_count() const {
return root_count;
@ -311,4 +306,11 @@ class BagOfCells {
std::vector<td::uint8>* cell_should_cache);
};
td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty = false);
td::Result<td::BufferSlice> std_boc_serialize(Ref<Cell> root, int mode = 0);
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data,
int max_roots = BagOfCells::default_max_roots);
td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> root, int mode = 0);
} // namespace vm

View file

@ -67,9 +67,14 @@ Ref<DataCell> CellBuilder::finalize_copy(bool special) const {
return cell;
}
Ref<DataCell> CellBuilder::finalize_novm(bool special) {
td::Result<Ref<DataCell>> CellBuilder::finalize_novm_nothrow(bool special) {
auto res = DataCell::create(data, size(), td::mutable_span(refs.data(), size_refs()), special);
bits = refs_cnt = 0;
return res;
}
Ref<DataCell> CellBuilder::finalize_novm(bool special) {
auto res = finalize_novm_nothrow(special);
if (res.is_error()) {
LOG(DEBUG) << res.error();
throw CellWriteError{};
@ -570,11 +575,11 @@ CellBuilder* CellBuilder::make_copy() const {
return c;
}
CellSlice CellBuilder::as_cellslice() const & {
CellSlice CellBuilder::as_cellslice() const& {
return CellSlice{finalize_copy()};
}
Ref<CellSlice> CellBuilder::as_cellslice_ref() const & {
Ref<CellSlice> CellBuilder::as_cellslice_ref() const& {
return Ref<CellSlice>{true, finalize_copy()};
}

View file

@ -177,12 +177,13 @@ class CellBuilder : public td::CntObject {
Ref<DataCell> finalize_copy(bool special = false) const;
Ref<DataCell> finalize(bool special = false);
Ref<DataCell> finalize_novm(bool special = false);
td::Result<Ref<DataCell>> finalize_novm_nothrow(bool special = false);
bool finalize_to(Ref<Cell>& res, bool special = false) {
return (res = finalize(special)).not_null();
}
CellSlice as_cellslice() const &;
CellSlice as_cellslice() const&;
CellSlice as_cellslice() &&;
Ref<CellSlice> as_cellslice_ref() const &;
Ref<CellSlice> as_cellslice_ref() const&;
Ref<CellSlice> as_cellslice_ref() &&;
static td::int64 get_total_cell_builders() {
return get_thread_safe_counter().sum();

View file

@ -492,6 +492,7 @@ int exec_setcontargs_common(VmState* st, int copy, int more) {
} else {
cdata->stack.write().move_from_stack(stack, copy);
}
st->consume_stack_gas(cdata->stack);
if (cdata->nargs >= 0) {
cdata->nargs -= copy;
}
@ -557,6 +558,7 @@ int exec_return_args_common(VmState* st, int count) {
cdata->stack.write().move_from_stack(alt_stk.write(), copy);
alt_stk.clear();
}
st->consume_stack_gas(cdata->stack);
if (cdata->nargs >= 0) {
cdata->nargs -= copy;
}
@ -587,6 +589,7 @@ int exec_bless_args_common(VmState* st, int copy, int more) {
stack.check_underflow(copy + 1);
auto cs = stack.pop_cellslice();
auto new_stk = stack.split_top(copy);
st->consume_stack_gas(new_stk);
stack.push_cont(Ref<OrdCont>{true, std::move(cs), st->get_cp(), std::move(new_stk), more});
return 0;
}

View file

@ -176,8 +176,10 @@ int VmState::call(Ref<Continuation> cont, int pass_args, int ret_args) {
if (skip > 0) {
get_stack().pop_many(skip);
}
consume_stack_gas(new_stk);
} else if (copy >= 0) {
new_stk = get_stack().split_top(copy, skip);
consume_stack_gas(new_stk);
} else {
new_stk = std::move(stack);
stack.clear();
@ -196,7 +198,13 @@ int VmState::call(Ref<Continuation> cont, int pass_args, int ret_args) {
throw VmError{Excno::stk_und, "stack underflow while calling a continuation: not enough arguments on stack"};
}
// create new stack from the top `pass_args` elements of the current stack
Ref<Stack> new_stk = (pass_args >= 0 ? get_stack().split_top(pass_args) : std::move(stack));
Ref<Stack> new_stk;
if (pass_args >= 0) {
new_stk = get_stack().split_top(pass_args);
consume_stack_gas(new_stk);
} else {
new_stk = std::move(stack);
}
// create return continuation using the remainder of the current stack
Ref<OrdCont> ret = Ref<OrdCont>{true, std::move(code), cp, std::move(stack), ret_args};
ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0]));
@ -251,10 +259,12 @@ int VmState::jump(Ref<Continuation> cont, int pass_args) {
new_stk = cont_data->stack;
}
new_stk.write().move_from_stack(get_stack(), copy);
consume_stack_gas(new_stk);
set_stack(std::move(new_stk));
} else {
if (copy >= 0) {
if (copy >= 0 && copy < stack->depth()) {
get_stack().drop_bottom(stack->depth() - copy);
consume_stack_gas(copy);
}
}
return jump_to(std::move(cont));
@ -264,8 +274,10 @@ int VmState::jump(Ref<Continuation> cont, int pass_args) {
int depth = get_stack().depth();
if (pass_args > depth) {
throw VmError{Excno::stk_und, "stack underflow while jumping to a continuation: not enough arguments on stack"};
} else if (pass_args < depth) {
get_stack().drop_bottom(depth - pass_args);
consume_stack_gas(pass_args);
}
get_stack().drop_bottom(depth - pass_args);
}
return jump_to(std::move(cont));
}
@ -303,6 +315,7 @@ Ref<OrdCont> VmState::extract_cc(int save_cr, int stack_copy, int cc_args) {
} else if (stack_copy > 0) {
stack->check_underflow(stack_copy);
new_stk = get_stack().split_top(stack_copy);
consume_stack_gas(new_stk);
} else {
new_stk = Ref<Stack>{true};
}
@ -332,7 +345,7 @@ int VmState::throw_exception(int excno) {
stack_ref.push_smallint(0);
stack_ref.push_smallint(excno);
code.clear();
consume_gas(exception_gas_price);
gas.consume_chk(exception_gas_price);
return jump(get_c2());
}
@ -342,7 +355,7 @@ int VmState::throw_exception(int excno, StackEntry&& arg) {
stack_ref.push(std::move(arg));
stack_ref.push_smallint(excno);
code.clear();
consume_gas(exception_gas_price);
gas.consume_chk(exception_gas_price);
return jump(get_c2());
}
@ -403,7 +416,6 @@ int VmState::run() {
int res;
Guard guard(this);
do {
// LOG(INFO) << "[BS] data cells: " << DataCell::get_total_data_cells();
try {
try {
try {
@ -419,12 +431,10 @@ int VmState::run() {
} catch (const VmError& vme) {
VM_LOG(this) << "handling exception code " << vme.get_errno() << ": " << vme.get_msg();
try {
// LOG(INFO) << "[EX] data cells: " << DataCell::get_total_data_cells();
++steps;
res = throw_exception(vme.get_errno());
} catch (const VmError& vme2) {
VM_LOG(this) << "exception " << vme2.get_errno() << " while handling exception: " << vme.get_msg();
// LOG(INFO) << "[EXX] data cells: " << DataCell::get_total_data_cells();
return ~vme2.get_errno();
}
}
@ -437,7 +447,6 @@ int VmState::run() {
return vmoog.get_errno(); // no ~ for unhandled exceptions (to make their faking impossible)
}
} while (!res);
// LOG(INFO) << "[EN] data cells: " << DataCell::get_total_data_cells();
if ((res | 1) == -1 && !try_commit()) {
VM_LOG(this) << "automatic commit failed (new data or action cells too deep)";
get_stack().clear();

View file

@ -106,6 +106,8 @@ class VmState final : public VmStateInterface {
tuple_entry_gas_price = 1,
implicit_jmpref_gas_price = 10,
implicit_ret_gas_price = 5,
free_stack_depth = 32,
stack_entry_gas_price = 1,
max_data_depth = 512
};
VmState();
@ -141,11 +143,19 @@ class VmState final : public VmStateInterface {
void consume_tuple_gas(unsigned tuple_len) {
consume_gas(tuple_len * tuple_entry_gas_price);
}
void consume_tuple_gas(const Ref<vm::Tuple>& tup) {
void consume_tuple_gas(const Ref<Tuple>& tup) {
if (tup.not_null()) {
consume_tuple_gas((unsigned)tup->size());
}
}
void consume_stack_gas(unsigned stack_depth) {
consume_gas((std::max(stack_depth, (unsigned)free_stack_depth) - free_stack_depth) * stack_entry_gas_price);
}
void consume_stack_gas(const Ref<Stack>& stk) {
if (stk.not_null()) {
consume_stack_gas((unsigned)stk->depth());
}
}
GasLimits get_gas_limits() const {
return gas;
}

View file

@ -27,12 +27,14 @@ Test_Fift_testvmprog_default e5d0b2c68ee568280877c8495be558bfd0054ca5d99a99eebb5
Test_RefInt_main_default 768493e0aef8e09a401a6d369edd1ef503a9215fb09dc460f52b27a8bde767cb
Test_VM_assert_code_not_null_default 05bc07e129181c972b976442f200de9487dee8bfb5ac53dd36ff61c5d4d4291d
Test_VM_assert_extract_minmax_key_default c352309c61bdf62ba7a0ba7280d303c88b0696fe7efa550c05feb2c662275297
Test_VM_assert_lookup_prefix_default 18e4fd70d6fa718bd352a6edf5d550a51355d4fb6f2fac58860a646c27a29bc9
Test_VM_assert_lookup_prefix_default c5b45999b46d324e4008c07e5ce671bbcd833f4e15fb21a4a5136f7b980ca6fc
Test_VM_assert_pfx_dict_lookup_default fa6e3f96b31cf2ed9a9dac6b279ec05acfedf13b8ed7b815789f167d1ed7352f
Test_VM_bigint_default feeb473a4ac51133989e1c145d0f49defa77117d2ae8b66bd7d12e3579e91b9f
Test_VM_bug_div_short_any_default f69aca6873f75d53dd37b6952151a2d858407a04589330762827dbc96d8b7c04
Test_VM_bug_exec_dict_getnear_default db314c2e25b49c1f7f044d271e225f36da546c66242a8ab12f6afae37628a81e
Test_VM_bug_stack_overflow_default 7e0e3e96ca438ac96648d569c55213aa82154cf004e80265b1c481b1c4219719
Test_VM_infinity_loop_1_default 670beda76229922806805e558d50d8f320017c642c3e7e34a7e1f2b7edb83cee
Test_VM_infinity_loop_2_default 22d9bd8cb41ff7b6cced5825e4ab73275b2fc07b1e3cd4588de815e2e6df2963
Test_VM_memory_leak_default e10dc118f3538720a16bcbd39be9a68c3ea07f76b3d2ed5719a5e866d91f0ab3
Test_VM_memory_leak_new_default fd2eec0a1d5ae49fb5ff8ba4b938fd9d0fe330be4a07b2b8be12bab249b00d90
Test_VM_memory_leak_old_default f3076ae38d14000c021597b824d2f0e51de4f00601429ec3e23cca1b32dba844
@ -52,6 +54,8 @@ Test_VM_report3_loop_6_default 5c35b92144debdb61b2020d690669bffbdd96f75ecde827fd
Test_VM_report3_qnot_default dc280444c7e3886cc3412f96f44c803c45287a07fcb9c638643e21bcdfe3905d
Test_VM_simple_default f6733549069427c2beb1a85ee25635540e27aa68cb8ad101d8435e19afeae862
Test_VM_unhandled_exception_1_default 0abe2740dd3b6a6b91eb67fee573f638086fecc72653d2d81c956782186b5d78
Test_VM_unhandled_exception_2_default 5ca67db5a0e957cc106bb47b744177ca959632a352f3629df376c34cbf03d51b
Test_VM_unhandled_exception_3_default b354e897e35a1177fd66d2c6ad7d77ae33a4e18f8678a518d79fea1388853307
Test_VM_unhandled_exception_4_default 412cbfe13745fde55cdcc5e41d7b15ba4d09f0e723f8e4421ae0b7066ca07b8f
Test_VM_unhandled_exception_5_default d760e540cd9c200c207f71c540cdaf06d11c96e32ec19860b9c1046cb1e38855
Test_base64_main_default e90d541bd810871c4a81e162f1fffb555024b72807cb895414d16bc11494b789