mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated tonlib, block routing
- upated tonlib - fixed bug in message routing
This commit is contained in:
parent
ac3eb1a7b8
commit
fd7a8de970
33 changed files with 1002 additions and 381 deletions
|
@ -552,7 +552,9 @@ bool MsgProcessedUpto::already_processed(const EnqueuedMsgDescr& msg) const {
|
|||
if (msg.lt_ == last_inmsg_lt && last_inmsg_hash < msg.hash_) {
|
||||
return false;
|
||||
}
|
||||
if (ton::shard_contains(shard, msg.cur_prefix_.account_id_prefix)) {
|
||||
if (msg.same_workchain() && ton::shard_contains(shard, msg.cur_prefix_.account_id_prefix)) {
|
||||
// this branch is needed only for messages generated in the same shard
|
||||
// (such messages could have been processed without a reference from the masterchain)
|
||||
// ? enable this branch only if an extra boolean parameter is set ?
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -145,6 +145,9 @@ struct EnqueuedMsgDescr {
|
|||
return false;
|
||||
}
|
||||
bool unpack(vm::CellSlice& cs);
|
||||
bool same_workchain() const {
|
||||
return cur_prefix_.workchain == next_prefix_.workchain;
|
||||
}
|
||||
};
|
||||
|
||||
using compute_shard_end_lt_func_t = std::function<ton::LogicalTime(ton::AccountIdPrefixFull)>;
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace block {
|
|||
using namespace std::literals::string_literals;
|
||||
|
||||
td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blkid, ton::Bits256* store_shard_hash_to,
|
||||
bool check_state_hash) {
|
||||
bool check_state_hash, td::uint32* save_utime) {
|
||||
ton::RootHash vhash{root->get_hash().bits()};
|
||||
if (vhash != blkid.root_hash) {
|
||||
return td::Status::Error(PSTRING() << " block header for block " << blkid.to_str() << " has incorrect root hash "
|
||||
|
@ -47,6 +47,9 @@ td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blki
|
|||
if (!(tlb::unpack_cell(root, blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
return td::Status::Error(std::string{"cannot unpack header for block "} + blkid.to_str());
|
||||
}
|
||||
if (save_utime) {
|
||||
*save_utime = info.gen_utime;
|
||||
}
|
||||
if (store_shard_hash_to) {
|
||||
vm::CellSlice upd_cs{vm::NoVmSpec(), blk.state_update};
|
||||
if (!(upd_cs.is_special() && upd_cs.prefetch_long(8) == 4 // merkle update
|
||||
|
@ -153,7 +156,8 @@ td::Status check_shard_proof(ton::BlockIdExt blk, ton::BlockIdExt shard_blk, td:
|
|||
}
|
||||
|
||||
td::Status check_account_proof(td::Slice proof, ton::BlockIdExt shard_blk, const block::StdAddress& addr,
|
||||
td::Ref<vm::Cell> root, ton::LogicalTime* last_trans_lt, ton::Bits256* last_trans_hash) {
|
||||
td::Ref<vm::Cell> root, ton::LogicalTime* last_trans_lt, ton::Bits256* last_trans_hash,
|
||||
td::uint32* save_utime) {
|
||||
TRY_RESULT_PREFIX(Q_roots, vm::std_boc_deserialize_multi(std::move(proof)), "cannot deserialize account proof");
|
||||
if (Q_roots.size() != 2) {
|
||||
return td::Status::Error(PSLICE() << "account state proof must have exactly two roots");
|
||||
|
@ -169,9 +173,9 @@ td::Status check_account_proof(td::Slice proof, ton::BlockIdExt shard_blk, const
|
|||
return td::Status::Error("account state proof is invalid");
|
||||
}
|
||||
ton::Bits256 state_hash = state_root->get_hash().bits();
|
||||
TRY_STATUS_PREFIX(
|
||||
check_block_header_proof(vm::MerkleProof::virtualize(std::move(Q_roots[0]), 1), shard_blk, &state_hash, true),
|
||||
"error in account shard block header proof : ");
|
||||
TRY_STATUS_PREFIX(check_block_header_proof(vm::MerkleProof::virtualize(std::move(Q_roots[0]), 1), shard_blk,
|
||||
&state_hash, true, save_utime),
|
||||
"error in account shard block header proof : ");
|
||||
block::gen::ShardStateUnsplit::Record sstate;
|
||||
if (!(tlb::unpack_cell(std::move(state_root), sstate))) {
|
||||
return td::Status::Error("cannot unpack state header");
|
||||
|
@ -233,8 +237,8 @@ td::Result<AccountState::Info> AccountState::validate(ton::BlockIdExt ref_blk, b
|
|||
TRY_STATUS(block::check_shard_proof(blk, shard_blk, shard_proof.as_slice()));
|
||||
|
||||
Info res;
|
||||
TRY_STATUS(
|
||||
block::check_account_proof(proof.as_slice(), shard_blk, addr, root, &res.last_trans_lt, &res.last_trans_hash));
|
||||
TRY_STATUS(block::check_account_proof(proof.as_slice(), shard_blk, addr, root, &res.last_trans_lt,
|
||||
&res.last_trans_hash, &res.gen_utime));
|
||||
res.root = std::move(root);
|
||||
|
||||
return res;
|
||||
|
|
|
@ -25,11 +25,12 @@ namespace block {
|
|||
using td::Ref;
|
||||
|
||||
td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blkid,
|
||||
ton::Bits256* store_shard_hash_to = nullptr, bool check_state_hash = false);
|
||||
ton::Bits256* store_shard_hash_to = nullptr, bool check_state_hash = false,
|
||||
td::uint32* save_utime = nullptr);
|
||||
td::Status check_shard_proof(ton::BlockIdExt blk, ton::BlockIdExt shard_blk, td::Slice shard_proof);
|
||||
td::Status check_account_proof(td::Slice proof, ton::BlockIdExt shard_blk, const block::StdAddress& addr,
|
||||
td::Ref<vm::Cell> root, ton::LogicalTime* last_trans_lt = nullptr,
|
||||
ton::Bits256* last_trans_hash = nullptr);
|
||||
ton::Bits256* last_trans_hash = nullptr, td::uint32* save_utime = nullptr);
|
||||
td::Result<td::Bits256> check_state_proof(ton::BlockIdExt blkid, td::Slice proof);
|
||||
td::Result<Ref<vm::Cell>> check_extract_state_proof(ton::BlockIdExt blkid, td::Slice proof, td::Slice data);
|
||||
|
||||
|
@ -47,6 +48,7 @@ struct AccountState {
|
|||
td::Ref<vm::Cell> root;
|
||||
ton::LogicalTime last_trans_lt = 0;
|
||||
ton::Bits256 last_trans_hash;
|
||||
td::uint32 gen_utime{0};
|
||||
};
|
||||
|
||||
td::Result<Info> validate(ton::BlockIdExt ref_blk, block::StdAddress addr) const;
|
||||
|
|
|
@ -1027,6 +1027,12 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
|
|||
break;
|
||||
case block::gen::OutAction::action_send_msg:
|
||||
err_code = try_action_send_msg(cs, ap, cfg);
|
||||
if (err_code == -2) {
|
||||
err_code = try_action_send_msg(cs, ap, cfg, 1);
|
||||
if (err_code == -2) {
|
||||
err_code = try_action_send_msg(cs, ap, cfg, 2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case block::gen::OutAction::action_reserve_currency:
|
||||
err_code = try_action_reserve_currency(cs, ap, cfg);
|
||||
|
@ -1240,22 +1246,60 @@ bool Transaction::check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const A
|
|||
return true;
|
||||
}
|
||||
|
||||
int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg) {
|
||||
int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, const ActionPhaseConfig& cfg,
|
||||
int redoing) {
|
||||
block::gen::OutAction::Record_action_send_msg act_rec;
|
||||
// mode: +128 = attach all remaining balance, +64 = attach all remaining balance of the inbound message, +1 = pay message fees, +2 = skip if message cannot be sent
|
||||
vm::CellSlice cs{cs0};
|
||||
if (!tlb::unpack_exact(cs, act_rec) || (act_rec.mode & ~0xc3) || (act_rec.mode & 0xc0) == 0xc0) {
|
||||
return -1;
|
||||
}
|
||||
bool skip_invalid = (act_rec.mode & 2);
|
||||
auto cs2 = vm::load_cell_slice(act_rec.out_msg);
|
||||
// try to parse suggested message in cs2
|
||||
// try to parse suggested message in act_rec.out_msg
|
||||
td::RefInt256 fwd_fee, ihr_fee;
|
||||
bool ext_msg = cs2.prefetch_ulong(1);
|
||||
block::gen::MessageRelaxed::Record msg;
|
||||
if (!tlb::type_unpack_cell(act_rec.out_msg, block::gen::t_MessageRelaxed_Any, msg)) {
|
||||
return -1;
|
||||
}
|
||||
if (redoing >= 1) {
|
||||
if (msg.init->size_refs() >= 2) {
|
||||
LOG(DEBUG) << "moving the StateInit of a suggested outbound message into a separate cell";
|
||||
// init:(Maybe (Either StateInit ^StateInit))
|
||||
// transform (just (left z:StateInit)) into (just (right z:^StateInit))
|
||||
CHECK(msg.init.write().fetch_ulong(2) == 2);
|
||||
vm::CellBuilder cb;
|
||||
Ref<vm::Cell> cell;
|
||||
CHECK(cb.append_cellslice_bool(std::move(msg.init)) // StateInit
|
||||
&& cb.finalize_to(cell) // -> ^StateInit
|
||||
&& cb.store_long_bool(3, 2) // (just (right ... ))
|
||||
&& cb.store_ref_bool(std::move(cell)) // z:^StateInit
|
||||
&& cb.finalize_to(cell));
|
||||
msg.init = vm::load_cell_slice_ref(std::move(cell));
|
||||
} else {
|
||||
redoing = 2;
|
||||
}
|
||||
}
|
||||
if (redoing >= 2 && msg.body->size_ext() > 1 && msg.body->prefetch_ulong(1) == 0) {
|
||||
LOG(DEBUG) << "moving the body of a suggested outbound message into a separate cell";
|
||||
// body:(Either X ^X)
|
||||
// transform (left x:X) into (right x:^X)
|
||||
CHECK(msg.body.write().fetch_ulong(1) == 0);
|
||||
vm::CellBuilder cb;
|
||||
Ref<vm::Cell> cell;
|
||||
CHECK(cb.append_cellslice_bool(std::move(msg.body)) // X
|
||||
&& cb.finalize_to(cell) // -> ^X
|
||||
&& cb.store_long_bool(1, 1) // (right ... )
|
||||
&& cb.store_ref_bool(std::move(cell)) // x:^X
|
||||
&& cb.finalize_to(cell));
|
||||
msg.body = vm::load_cell_slice_ref(std::move(cell));
|
||||
}
|
||||
|
||||
block::gen::CommonMsgInfoRelaxed::Record_int_msg_info info;
|
||||
bool ext_msg = msg.info->prefetch_ulong(1);
|
||||
if (ext_msg) {
|
||||
// ext_out_msg_info$11 constructor of CommonMsgInfoRelaxed
|
||||
block::gen::CommonMsgInfoRelaxed::Record_ext_out_msg_info erec;
|
||||
if (!tlb::unpack(cs2, erec)) {
|
||||
if (!tlb::csr_unpack(msg.info, erec)) {
|
||||
return -1;
|
||||
}
|
||||
info.src = std::move(erec.src);
|
||||
|
@ -1267,7 +1311,7 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
|
|||
fwd_fee = ihr_fee = td::RefInt256{true, 0};
|
||||
} else {
|
||||
// int_msg_info$0 constructor
|
||||
if (!tlb::unpack(cs2, info) || !block::tlb::t_CurrencyCollection.validate_csr(info.value)) {
|
||||
if (!tlb::csr_unpack(msg.info, info) || !block::tlb::t_CurrencyCollection.validate_csr(info.value)) {
|
||||
return -1;
|
||||
}
|
||||
fwd_fee = block::tlb::t_Grams.as_integer(info.fwd_fee);
|
||||
|
@ -1295,12 +1339,11 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
|
|||
// compute size of message
|
||||
vm::CellStorageStat sstat; // for message size
|
||||
// preliminary storage estimation of the resulting message
|
||||
sstat.compute_used_storage(cs2); // message body
|
||||
sstat.add_used_storage(msg.init, true, 3); // message init
|
||||
sstat.add_used_storage(msg.body, true, 3); // message body (the root cell itself is not counted)
|
||||
if (!ext_msg) {
|
||||
sstat.add_used_storage(info.value->prefetch_ref());
|
||||
}
|
||||
sstat.bits -= cs2.size(); // bits in the root cells are free
|
||||
sstat.cells--; // the root cell itself is not counted as a cell
|
||||
LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits";
|
||||
if (sstat.bits > max_msg_bits || sstat.cells > max_msg_cells) {
|
||||
LOG(DEBUG) << "message too large, invalid";
|
||||
|
@ -1397,17 +1440,15 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
|
|||
|
||||
// re-pack message value
|
||||
CHECK(req.pack_to(info.value));
|
||||
vm::CellBuilder cb;
|
||||
CHECK(block::tlb::t_Grams.store_integer_ref(cb, fwd_fee_remain) &&
|
||||
(info.fwd_fee = load_cell_slice_ref(cb.finalize())).not_null());
|
||||
CHECK(block::tlb::t_Grams.store_integer_ref(cb, ihr_fee) &&
|
||||
(info.ihr_fee = load_cell_slice_ref(cb.finalize())).not_null());
|
||||
CHECK(block::tlb::t_Grams.pack_integer(info.fwd_fee, fwd_fee_remain));
|
||||
CHECK(block::tlb::t_Grams.pack_integer(info.ihr_fee, ihr_fee));
|
||||
|
||||
// serialize message
|
||||
CHECK(tlb::pack(cb, info));
|
||||
if (!cb.append_cellslice_bool(cs2)) {
|
||||
CHECK(tlb::csr_pack(msg.info, info));
|
||||
vm::CellBuilder cb;
|
||||
if (!tlb::type_pack(cb, block::gen::t_MessageRelaxed_Any, msg)) {
|
||||
LOG(DEBUG) << "outbound message does not fit into a cell after rewriting";
|
||||
return 39;
|
||||
return redoing < 2 ? -2 : (skip_invalid ? 0 : 39);
|
||||
}
|
||||
|
||||
new_msg_bits = cb.size();
|
||||
|
@ -1438,11 +1479,11 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
|
|||
erec.dest = info.dest;
|
||||
erec.created_at = info.created_at;
|
||||
erec.created_lt = info.created_lt;
|
||||
CHECK(tlb::csr_pack(msg.info, erec));
|
||||
vm::CellBuilder cb;
|
||||
CHECK(tlb::pack(cb, erec));
|
||||
if (!cb.append_cellslice_bool(cs2)) {
|
||||
if (!tlb::type_pack(cb, block::gen::t_MessageRelaxed_Any, msg)) {
|
||||
LOG(DEBUG) << "outbound message does not fit into a cell after rewriting";
|
||||
return 39;
|
||||
return redoing < 2 ? -2 : (skip_invalid ? 0 : 39);
|
||||
}
|
||||
|
||||
new_msg_bits = cb.size();
|
||||
|
@ -1461,6 +1502,8 @@ int Transaction::try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const A
|
|||
}
|
||||
if (!block::gen::t_Message_Any.validate_ref(new_msg)) {
|
||||
LOG(ERROR) << "generated outbound message is not a valid (Message Any) according to automated check";
|
||||
block::gen::t_Message_Any.print_ref(std::cerr, new_msg);
|
||||
vm::load_cell_slice(new_msg).print_rec(std::cerr);
|
||||
return -1;
|
||||
}
|
||||
if (verbosity > 2) {
|
||||
|
|
|
@ -390,7 +390,7 @@ struct Transaction {
|
|||
Ref<vm::Tuple> prepare_vm_c7(const ComputePhaseConfig& cfg) const;
|
||||
bool prepare_rand_seed(td::BitArray<256>& rand_seed, const ComputePhaseConfig& cfg) const;
|
||||
int try_action_set_code(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg);
|
||||
int try_action_send_msg(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg);
|
||||
int try_action_send_msg(const vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg, int redoing = 0);
|
||||
int try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg);
|
||||
bool check_replace_src_addr(Ref<vm::CellSlice>& src_addr) const;
|
||||
bool check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const ActionPhaseConfig& cfg,
|
||||
|
|
|
@ -77,6 +77,7 @@ struct IntCtx {
|
|||
vm::TonDb* ton_db{nullptr};
|
||||
Dictionary* dictionary{nullptr};
|
||||
SourceLookup* source_lookup{nullptr};
|
||||
int* now{nullptr};
|
||||
|
||||
private:
|
||||
std::string str;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/Time.h"
|
||||
|
||||
namespace fift {
|
||||
class FileLoader {
|
||||
|
@ -43,10 +44,21 @@ class OsFileLoader : public FileLoader {
|
|||
bool is_file_exists(td::CSlice filename) override;
|
||||
};
|
||||
|
||||
class OsTime {
|
||||
public:
|
||||
virtual ~OsTime() = default;
|
||||
virtual td::uint32 now() = 0;
|
||||
};
|
||||
|
||||
//TODO: rename SourceLookup
|
||||
class SourceLookup {
|
||||
public:
|
||||
SourceLookup() = default;
|
||||
explicit SourceLookup(std::unique_ptr<FileLoader> file_loader) : file_loader_(std::move(file_loader)) {
|
||||
explicit SourceLookup(std::unique_ptr<FileLoader> file_loader, std::unique_ptr<OsTime> os_time = {})
|
||||
: file_loader_(std::move(file_loader)), os_time_(std::move(os_time)) {
|
||||
}
|
||||
void set_os_time(std::unique_ptr<OsTime> os_time) {
|
||||
os_time_ = std::move(os_time);
|
||||
}
|
||||
void add_include_path(td::string path);
|
||||
td::Result<FileLoader::File> lookup_source(std::string filename, std::string current_dir);
|
||||
|
@ -63,9 +75,16 @@ class SourceLookup {
|
|||
bool is_file_exists(td::CSlice filename) {
|
||||
return file_loader_->is_file_exists(filename);
|
||||
}
|
||||
td::uint32 now() {
|
||||
if (os_time_) {
|
||||
return os_time_->now();
|
||||
}
|
||||
return static_cast<td::uint32>(td::Time::now());
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<FileLoader> file_loader_;
|
||||
std::unique_ptr<OsTime> os_time_;
|
||||
std::vector<std::string> source_include_path_;
|
||||
};
|
||||
} // namespace fift
|
||||
|
|
|
@ -1289,8 +1289,8 @@ void interpret_file_exists(IntCtx& ctx) {
|
|||
|
||||
// custom and crypto
|
||||
|
||||
void interpret_now(vm::Stack& stack) {
|
||||
stack.push_smallint(std::time(nullptr));
|
||||
void interpret_now(IntCtx& ctx) {
|
||||
ctx.stack.push_smallint(ctx.source_lookup->now());
|
||||
}
|
||||
|
||||
void interpret_new_keypair(vm::Stack& stack) {
|
||||
|
@ -2534,7 +2534,7 @@ void init_words_common(Dictionary& d) {
|
|||
d.def_ctx_word("B>file ", interpret_write_file);
|
||||
d.def_ctx_word("file-exists? ", interpret_file_exists);
|
||||
// custom & crypto
|
||||
d.def_stack_word("now ", interpret_now);
|
||||
d.def_ctx_word("now ", interpret_now);
|
||||
d.def_stack_word("newkeypair ", interpret_new_keypair);
|
||||
d.def_stack_word("priv>pub ", interpret_priv_key_to_pub);
|
||||
d.def_stack_word("ed25519_sign ", interpret_ed25519_sign);
|
||||
|
|
62
crypto/smartcont/new-wallet-v2.fif
Normal file
62
crypto/smartcont/new-wallet-v2.fif
Normal file
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env fift -s
|
||||
"TonUtil.fif" include
|
||||
"Asm.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <workchain-id> [<filename-base>]" cr
|
||||
."Creates a new advanced wallet in specified workchain, with private key saved to or loaded from <filename-base>.pk" cr
|
||||
."('new-wallet.pk' by default)" cr 1 halt
|
||||
} : usage
|
||||
$# 1- -2 and ' usage if
|
||||
|
||||
$1 parse-workchain-id =: wc // set workchain id from command line argument
|
||||
def? $2 { @' $2 } { "new-wallet" } cond constant file-base
|
||||
|
||||
."Creating new advanced wallet in workchain " wc . cr
|
||||
|
||||
// Create new advanced wallet; code adapted from `wallet-code.fif`
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
|
||||
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU // signature in_msg msg_seqno valid_until cs
|
||||
SWAP NOW LEQ 35 THROWIF // signature in_msg msg_seqno cs
|
||||
c4 PUSH CTOS 32 LDU 256 LDU ENDS // signature in_msg msg_seqno cs stored_seqno public_key
|
||||
s3 s1 XCPU // signature in_msg public_key cs stored_seqno msg_seqno stored_seqno
|
||||
EQUAL 33 THROWIFNOT // signature in_msg public_key cs stored_seqno
|
||||
s0 s3 XCHG HASHSU // signature stored_seqno public_key cs hash
|
||||
s0 s4 s2 XC2PU CHKSIGNU 34 THROWIFNOT // cs stored_seqno public_key
|
||||
ACCEPT
|
||||
s0 s2 XCHG // public_key stored_seqno cs
|
||||
WHILE:<{
|
||||
DUP SREFS // public_key stored_seqno cs _40
|
||||
}>DO<{ // public_key stored_seqno cs
|
||||
// 3 INT 35 LSHIFT# 3 INT RAWRESERVE // reserve all but 103 Grams from the balance
|
||||
8 LDU LDREF s0 s2 XCHG // public_key stored_seqno cs _45 mode
|
||||
SENDRAWMSG // public_key stored_seqno cs
|
||||
}>
|
||||
ENDS INC // public_key seqno'
|
||||
NEWC 32 STU 256 STU ENDC c4 POP
|
||||
}>c // >libref
|
||||
// code
|
||||
<b 0 32 u,
|
||||
file-base +".pk" load-generate-keypair
|
||||
constant wallet_pk
|
||||
B,
|
||||
b> // data
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hash wc swap 2dup 2constant wallet_addr
|
||||
."new wallet address = " 2dup .addr cr
|
||||
2dup file-base +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
."Bounceable address (for later access): " 6 .Addr cr
|
||||
<b 0 32 u, -1 32 i, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash wallet_pk ed25519_sign_uint rot
|
||||
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
|
||||
dup ."External message for initialization is " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
file-base +"-query.boc" tuck B>file
|
||||
."(Saved wallet creating query to file " type .")" cr
|
|
@ -8,7 +8,7 @@
|
|||
var signature = in_msg~load_bits(512);
|
||||
var cs = in_msg;
|
||||
var (msg_seqno, valid_until) = (cs~load_uint(32), cs~load_uint(32));
|
||||
throw_if(35, valid_until < now());
|
||||
throw_if(35, valid_until <= now());
|
||||
var ds = get_data().begin_parse();
|
||||
var (stored_seqno, public_key) = (ds~load_uint(32), ds~load_uint(256));
|
||||
ds.end_parse();
|
||||
|
|
48
crypto/smartcont/wallet-v2.fif
Normal file
48
crypto/smartcont/wallet-v2.fif
Normal file
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env fift -s
|
||||
"TonUtil.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <dest-addr> <seqno> <amount> [-B <body-boc>] [<savefile>]" cr
|
||||
."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)" cr 1 halt
|
||||
} : usage
|
||||
def? $6 { @' $5 "-B" $= { @' $6 =: body-boc-file [forget] $6 def? $7 { @' $7 =: $5 [forget] $7 } { [forget] $5 } cond
|
||||
@' $# 2- =: $# } if } if
|
||||
$# dup 4 < swap 5 > or ' usage if
|
||||
|
||||
true constant bounce
|
||||
|
||||
$1 =: file-base
|
||||
$2 bounce parse-load-address =: bounce 2=: dest_addr
|
||||
$3 parse-int =: seqno
|
||||
$4 $>GR =: amount
|
||||
def? $5 { @' $5 } { "wallet-query" } cond constant savefile
|
||||
3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 constant timeout // external message expires in 60 seconds
|
||||
|
||||
file-base +".addr" load-address
|
||||
2dup 2constant wallet_addr
|
||||
."Source wallet address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant wallet_pk
|
||||
|
||||
def? body-boc-file { @' body-boc-file file>B B>boc } { <b 0 32 u, "TESTv2" $, b> } cond
|
||||
constant body-cell
|
||||
|
||||
."Transferring " amount .GR ."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{000100} s, dest_addr addr, amount Gram, 0 9 64 32 + + 1+ u,
|
||||
body-cell <s 2dup s-fits? 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>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash wallet_pk ed25519_sign_uint
|
||||
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
savefile +".boc" tuck B>file
|
||||
."Query expires in " timeout . ."seconds" cr
|
||||
."(Saved to file " type .")" cr
|
|
@ -176,6 +176,10 @@ class TLB {
|
|||
virtual bool store_integer_ref(vm::CellBuilder& cb, td::RefInt256 value) const {
|
||||
return value.not_null() && store_integer_value(cb, *value);
|
||||
}
|
||||
bool pack_integer(Ref<vm::CellSlice>& csr, td::RefInt256 value) const {
|
||||
vm::CellBuilder cb;
|
||||
return store_integer_ref(cb, value) && (csr = vm::load_cell_slice_ref(cb.finalize())).not_null();
|
||||
}
|
||||
virtual bool add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
|
||||
td::RefInt256 x = as_integer_skip(cs1), y = as_integer_skip(cs2);
|
||||
return x.not_null() && y.not_null() && store_integer_ref(cb, x += std::move(y));
|
||||
|
|
|
@ -988,27 +988,27 @@ td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> roots
|
|||
*
|
||||
*/
|
||||
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, bool skip_count_root) {
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cs_ref), kill_dup, skip_count_root) && clear_seen();
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup, bool skip_count_root) {
|
||||
bool CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(cs, kill_dup, skip_count_root) && clear_seen();
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup, bool skip_count_root) {
|
||||
bool CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cs), kill_dup, skip_count_root) && clear_seen();
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup, bool skip_count_root) {
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cell), kill_dup, skip_count_root) && clear_seen();
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, bool skip_count_root) {
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
|
||||
if (cs_ref->is_unique()) {
|
||||
return add_used_storage(std::move(cs_ref.unique_write()), kill_dup, skip_count_root);
|
||||
} else {
|
||||
|
@ -1016,11 +1016,13 @@ bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
|
|||
}
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, bool skip_count_root) {
|
||||
if (!skip_count_root) {
|
||||
bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
if (!(skip_count_root & 1)) {
|
||||
++cells;
|
||||
}
|
||||
bits += cs.size();
|
||||
if (!(skip_count_root & 2)) {
|
||||
bits += cs.size();
|
||||
}
|
||||
for (unsigned i = 0; i < cs.size_refs(); i++) {
|
||||
if (!add_used_storage(cs.prefetch_ref(i), kill_dup)) {
|
||||
return false;
|
||||
|
@ -1029,11 +1031,13 @@ bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, bool
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, bool skip_count_root) {
|
||||
if (!skip_count_root) {
|
||||
bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
if (!(skip_count_root & 1)) {
|
||||
++cells;
|
||||
}
|
||||
bits += cs.size();
|
||||
if (!(skip_count_root & 2)) {
|
||||
bits += cs.size();
|
||||
}
|
||||
while (cs.size_refs()) {
|
||||
if (!add_used_storage(cs.fetch_ref(), kill_dup)) {
|
||||
return false;
|
||||
|
@ -1042,7 +1046,7 @@ bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, bool skip_
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup, bool skip_count_root) {
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
|
||||
if (cell.is_null()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -122,15 +122,15 @@ struct CellStorageStat {
|
|||
cells = bits = public_cells = 0;
|
||||
clear_seen();
|
||||
}
|
||||
bool compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool compute_used_storage(const CellSlice& cs, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool compute_used_storage(CellSlice&& cs, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
|
||||
bool add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool add_used_storage(const CellSlice& cs, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool add_used_storage(CellSlice&& cs, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, bool skip_count_root = false);
|
||||
bool add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
};
|
||||
|
||||
struct CellSerializationInfo {
|
||||
|
|
|
@ -207,9 +207,8 @@ bool CellBuilder::store_bits_bool(const unsigned char* str, std::size_t bit_coun
|
|||
|
||||
CellBuilder& CellBuilder::store_bits(const unsigned char* str, std::size_t bit_count, int bit_offset) {
|
||||
unsigned pos = bits;
|
||||
if (prepare_reserve(bit_count)) {
|
||||
td::bitstring::bits_memcpy(data, pos, str, bit_offset, bit_count);
|
||||
}
|
||||
ensure_throw(prepare_reserve(bit_count));
|
||||
td::bitstring::bits_memcpy(data, pos, str, bit_offset, bit_count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue