mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated smartcontracts
- updated smartcontracts - updated fullnode database layout - fixed memory leak in blockchain-explorer - updated tonlib
This commit is contained in:
parent
9c9248a9ae
commit
c860ce3d1e
104 changed files with 7309 additions and 1335 deletions
99
crypto/smc-envelope/GenericAccount.cpp
Normal file
99
crypto/smc-envelope/GenericAccount.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#include "GenericAccount.h"
|
||||
|
||||
#include "block/block-auto.h"
|
||||
#include "block/block-parse.h"
|
||||
namespace ton {
|
||||
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept {
|
||||
return vm::CellBuilder()
|
||||
.store_zeroes(2)
|
||||
.store_ones(2)
|
||||
.store_zeroes(1)
|
||||
.store_ref(std::move(code))
|
||||
.store_ref(std::move(data))
|
||||
.finalize();
|
||||
}
|
||||
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id,
|
||||
const td::Ref<vm::Cell>& init_state) noexcept {
|
||||
return block::StdAddress(workchain_id, init_state->get_hash().bits(), true /*bounce*/);
|
||||
}
|
||||
|
||||
void GenericAccount::store_int_message(vm::CellBuilder& cb, const block::StdAddress& dest_address, td::int64 gramms) {
|
||||
td::BigInt256 dest_addr;
|
||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||
cb.store_zeroes(1)
|
||||
.store_ones(1)
|
||||
.store_long(dest_address.bounceable, 1)
|
||||
.store_zeroes(3)
|
||||
.store_ones(1)
|
||||
.store_zeroes(2)
|
||||
.store_long(dest_address.workchain, 8)
|
||||
.store_int256(dest_addr, 256);
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
cb.store_zeroes(9 + 64 + 32 + 1 + 1);
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body) noexcept {
|
||||
block::gen::Message::Record message;
|
||||
/*info*/ {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
/* src */
|
||||
tlb::csr_pack(info.src, block::gen::MsgAddressExt::Record_addr_none{});
|
||||
/* dest */ {
|
||||
block::gen::MsgAddressInt::Record_addr_std dest;
|
||||
dest.anycast = vm::CellBuilder().store_zeroes(1).as_cellslice_ref();
|
||||
dest.workchain_id = address.workchain;
|
||||
dest.address = address.addr;
|
||||
|
||||
tlb::csr_pack(info.dest, dest);
|
||||
}
|
||||
/* import_fee */ {
|
||||
vm::CellBuilder cb;
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(0));
|
||||
info.import_fee = cb.as_cellslice_ref();
|
||||
}
|
||||
|
||||
tlb::csr_pack(message.info, info);
|
||||
}
|
||||
/* init */ {
|
||||
if (new_state.not_null()) {
|
||||
// Just(Left(new_state))
|
||||
message.init = vm::CellBuilder()
|
||||
.store_ones(1)
|
||||
.store_zeroes(1)
|
||||
.append_cellslice(vm::load_cell_slice(new_state))
|
||||
.as_cellslice_ref();
|
||||
} else {
|
||||
message.init = vm::CellBuilder().store_zeroes(1).as_cellslice_ref();
|
||||
CHECK(message.init.not_null());
|
||||
}
|
||||
}
|
||||
/* body */ {
|
||||
message.body = vm::CellBuilder().store_zeroes(1).append_cellslice(vm::load_cell_slice_ref(body)).as_cellslice_ref();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> res;
|
||||
tlb::type_pack_cell(res, block::gen::t_Message_Any, message);
|
||||
CHECK(res.not_null());
|
||||
|
||||
return res;
|
||||
}
|
||||
} // namespace ton
|
31
crypto/smc-envelope/GenericAccount.h
Normal file
31
crypto/smc-envelope/GenericAccount.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
#include "vm/cells.h"
|
||||
#include "block/block.h"
|
||||
namespace ton {
|
||||
class GenericAccount {
|
||||
public:
|
||||
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept;
|
||||
static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) noexcept;
|
||||
static td::Ref<vm::Cell> create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body) noexcept;
|
||||
static void store_int_message(vm::CellBuilder& cb, const block::StdAddress& dest_address, td::int64 gramms);
|
||||
};
|
||||
} // namespace ton
|
171
crypto/smc-envelope/MultisigWallet.cpp
Normal file
171
crypto/smc-envelope/MultisigWallet.cpp
Normal file
|
@ -0,0 +1,171 @@
|
|||
#include "MultisigWallet.h"
|
||||
|
||||
#include "SmartContractCode.h"
|
||||
|
||||
#include "vm/dict.h"
|
||||
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
MultisigWallet::QueryBuilder::QueryBuilder(td::int64 query_id, td::Ref<vm::Cell> msg, int mode) {
|
||||
msg_ = vm::CellBuilder().store_long(query_id, 64).store_long(mode, 8).store_ref(std::move(msg)).finalize();
|
||||
}
|
||||
void MultisigWallet::QueryBuilder::sign(td::int32 id, td::Ed25519::PrivateKey& pk) {
|
||||
CHECK(id < td::narrow_cast<td::int32>(mask_.size()));
|
||||
auto signature = pk.sign(msg_->get_hash().as_slice()).move_as_ok();
|
||||
mask_.set(id);
|
||||
vm::CellBuilder cb;
|
||||
cb.store_bytes(signature.as_slice());
|
||||
cb.store_long(id, 8);
|
||||
cb.ensure_throw(cb.store_maybe_ref(std::move(dict_)));
|
||||
dict_ = cb.finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MultisigWallet::QueryBuilder::create_inner() const {
|
||||
vm::CellBuilder cb;
|
||||
cb.ensure_throw(cb.store_maybe_ref(dict_));
|
||||
return cb.append_cellslice(vm::load_cell_slice(msg_)).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MultisigWallet::QueryBuilder::create(td::int32 id, td::Ed25519::PrivateKey& pk) const {
|
||||
auto cell = create_inner();
|
||||
vm::CellBuilder cb;
|
||||
cb.store_long(id, 8);
|
||||
cb.append_cellslice(vm::load_cell_slice(cell));
|
||||
cell = cb.finalize();
|
||||
|
||||
auto signature = pk.sign(cell->get_hash().as_slice()).move_as_ok();
|
||||
vm::CellBuilder cb2;
|
||||
cb2.store_bytes(signature.as_slice());
|
||||
cb2.append_cellslice(vm::load_cell_slice(cell));
|
||||
return cb2.finalize();
|
||||
}
|
||||
|
||||
td::Ref<MultisigWallet> MultisigWallet::create(td::Ref<vm::Cell> data) {
|
||||
return td::Ref<MultisigWallet>(true, State{ton::SmartContractCode::multisig(), std::move(data)});
|
||||
}
|
||||
|
||||
int MultisigWallet::processed(td::uint64 query_id) const {
|
||||
auto res = run_get_method("processed?", {td::make_refint(query_id)});
|
||||
return res.stack.write().pop_smallint_range(1, -1);
|
||||
}
|
||||
|
||||
MultisigWallet::QueryState MultisigWallet::get_query_state(td::uint64 query_id) const {
|
||||
auto ans = run_get_method("get_query_state", {td::make_refint(query_id)});
|
||||
|
||||
auto mask = ans.stack.write().pop_int();
|
||||
auto state = ans.stack.write().pop_smallint_range(1, -1);
|
||||
|
||||
QueryState res;
|
||||
if (state == 1) {
|
||||
res.state = QueryState::Unknown;
|
||||
} else if (state == 0) {
|
||||
res.state = QueryState::NotReady;
|
||||
for (size_t i = 0; i < res.mask.size(); i++) {
|
||||
if (mask->get_bit(static_cast<int>(i))) {
|
||||
res.mask.set(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res.state = QueryState::Sent;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<td::SecureString> MultisigWallet::get_public_keys() const {
|
||||
auto ans = run_get_method("get_public_keys");
|
||||
auto dict_root = ans.stack.write().pop_cell();
|
||||
vm::Dictionary dict(std::move(dict_root), 8);
|
||||
std::vector<td::SecureString> res;
|
||||
dict.check_for_each([&](auto cs, auto x, auto y) {
|
||||
td::SecureString key(32);
|
||||
cs->prefetch_bytes(key.as_mutable_slice().ubegin(), td::narrow_cast<int>(key.size()));
|
||||
res.push_back(std::move(key));
|
||||
return true;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MultisigWallet::create_init_data(std::vector<td::SecureString> public_keys, int k) const {
|
||||
vm::Dictionary pk(8);
|
||||
for (size_t i = 0; i < public_keys.size(); i++) {
|
||||
auto key = pk.integer_key(td::make_refint(i), 8, false);
|
||||
pk.set_builder(key.bits(), 8, vm::CellBuilder().store_bytes(public_keys[i].as_slice()));
|
||||
}
|
||||
auto res = run_get_method("create_init_state",
|
||||
{td::make_refint(public_keys.size()), td::make_refint(k), pk.get_root_cell()});
|
||||
CHECK(res.code == 0);
|
||||
return res.stack.write().pop_cell();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MultisigWallet::create_init_data_fast(std::vector<td::SecureString> public_keys, int k) {
|
||||
vm::Dictionary pk(8);
|
||||
for (size_t i = 0; i < public_keys.size(); i++) {
|
||||
auto key = pk.integer_key(td::make_refint(i), 8, false);
|
||||
pk.set_builder(key.bits(), 8, vm::CellBuilder().store_bytes(public_keys[i].as_slice()));
|
||||
}
|
||||
|
||||
vm::CellBuilder cb;
|
||||
cb.store_long(public_keys.size(), 8).store_long(k, 8).store_long(0, 64);
|
||||
cb.ensure_throw(cb.store_maybe_ref(pk.get_root_cell()));
|
||||
cb.ensure_throw(cb.store_maybe_ref({}));
|
||||
return cb.finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MultisigWallet::merge_queries(td::Ref<vm::Cell> a, td::Ref<vm::Cell> b) const {
|
||||
auto res = run_get_method("merge_queries", {a, b});
|
||||
return res.stack.write().pop_cell();
|
||||
}
|
||||
|
||||
MultisigWallet::Mask MultisigWallet::to_mask(td::RefInt256 mask) const {
|
||||
Mask res_mask;
|
||||
for (size_t i = 0; i < res_mask.size(); i++) {
|
||||
if (mask->get_bit(static_cast<int>(i))) {
|
||||
res_mask.set(i);
|
||||
}
|
||||
}
|
||||
return res_mask;
|
||||
}
|
||||
|
||||
std::pair<int, MultisigWallet::Mask> MultisigWallet::check_query_signatures(td::Ref<vm::Cell> a) const {
|
||||
auto ans = run_get_method("check_query_signatures", {a});
|
||||
|
||||
auto mask = ans.stack.write().pop_int();
|
||||
auto cnt = ans.stack.write().pop_smallint_range(128);
|
||||
return std::make_pair(cnt, to_mask(mask));
|
||||
}
|
||||
|
||||
std::pair<int, int> MultisigWallet::get_n_k() const {
|
||||
auto ans = run_get_method("get_n_k");
|
||||
auto k = ans.stack.write().pop_smallint_range(128);
|
||||
auto n = ans.stack.write().pop_smallint_range(128);
|
||||
return std::make_pair(n, k);
|
||||
}
|
||||
|
||||
std::vector<MultisigWallet::Message> MultisigWallet::get_unsigned_messaged(int id) const {
|
||||
SmartContract::Answer ans;
|
||||
if (id == -1) {
|
||||
ans = run_get_method("get_messages_unsigned");
|
||||
} else {
|
||||
ans = run_get_method("get_messages_unsigned_by_id", {td::make_refint(id)});
|
||||
}
|
||||
auto n_k = get_n_k();
|
||||
|
||||
auto cell = ans.stack.write().pop_maybe_cell();
|
||||
vm::Dictionary dict(std::move(cell), 64);
|
||||
std::vector<Message> res;
|
||||
dict.check_for_each([&](auto cs, auto ptr, auto ptr_bits) {
|
||||
cs.write().skip_first(8);
|
||||
Message message;
|
||||
td::BigInt256 query_id;
|
||||
query_id.import_bits(ptr, ptr_bits, false);
|
||||
message.query_id = static_cast<td::uint64>(query_id.to_long());
|
||||
message.signed_by = to_mask(cs.write().fetch_int256(n_k.first, false));
|
||||
message.message = cs.write().fetch_ref();
|
||||
res.push_back(std::move(message));
|
||||
return true;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
} // namespace ton
|
64
crypto/smc-envelope/MultisigWallet.h
Normal file
64
crypto/smc-envelope/MultisigWallet.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
#include "vm/cells.h"
|
||||
|
||||
#include "SmartContract.h"
|
||||
#include "Ed25519.h"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
namespace ton {
|
||||
class MultisigWallet : public ton::SmartContract {
|
||||
public:
|
||||
MultisigWallet(State state) : SmartContract(std::move(state)) {
|
||||
}
|
||||
|
||||
using Mask = std::bitset<128>;
|
||||
struct QueryState {
|
||||
enum State { Unknown, NotReady, Sent } state = Unknown;
|
||||
Mask mask;
|
||||
};
|
||||
|
||||
class QueryBuilder {
|
||||
public:
|
||||
QueryBuilder(td::int64 query_id, td::Ref<vm::Cell> msg, int mode = 3);
|
||||
void sign(td::int32 id, td::Ed25519::PrivateKey& pk);
|
||||
|
||||
td::Ref<vm::Cell> create_inner() const;
|
||||
td::Ref<vm::Cell> create(td::int32 id, td::Ed25519::PrivateKey& pk) const;
|
||||
Mask get_mask() const {
|
||||
return mask_;
|
||||
}
|
||||
|
||||
private:
|
||||
vm::Ref<vm::Cell> dict_;
|
||||
td::Ref<vm::Cell> msg_;
|
||||
Mask mask_;
|
||||
};
|
||||
|
||||
MultisigWallet* make_copy() const override {
|
||||
return new MultisigWallet{state_};
|
||||
}
|
||||
|
||||
// creation
|
||||
static td::Ref<MultisigWallet> create(td::Ref<vm::Cell> data = {});
|
||||
|
||||
td::Ref<vm::Cell> create_init_data(std::vector<td::SecureString> public_keys, int k) const;
|
||||
static td::Ref<vm::Cell> create_init_data_fast(std::vector<td::SecureString> public_keys, int k);
|
||||
|
||||
// get methods
|
||||
int processed(td::uint64 query_id) const;
|
||||
QueryState get_query_state(td::uint64 query_id) const;
|
||||
std::vector<td::SecureString> get_public_keys() const;
|
||||
td::Ref<vm::Cell> merge_queries(td::Ref<vm::Cell> a, td::Ref<vm::Cell> b) const;
|
||||
std::pair<int, Mask> check_query_signatures(td::Ref<vm::Cell> a) const;
|
||||
std::pair<int, int> get_n_k() const;
|
||||
Mask to_mask(td::RefInt256 mask) const;
|
||||
|
||||
struct Message {
|
||||
td::uint64 query_id;
|
||||
Mask signed_by;
|
||||
td::Ref<vm::Cell> message;
|
||||
};
|
||||
std::vector<Message> get_unsigned_messaged(int id = -1) const;
|
||||
};
|
||||
} // namespace ton
|
188
crypto/smc-envelope/SmartContract.cpp
Normal file
188
crypto/smc-envelope/SmartContract.cpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#include "SmartContract.h"
|
||||
|
||||
#include "GenericAccount.h"
|
||||
|
||||
#include "block/block.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "vm/cellslice.h"
|
||||
#include "vm/cp0.h"
|
||||
#include "vm/continuation.h"
|
||||
|
||||
#include "td/utils/crypto.h"
|
||||
|
||||
namespace ton {
|
||||
namespace {
|
||||
td::int32 get_method_id(td::Slice method_name) {
|
||||
unsigned crc = td::crc16(method_name);
|
||||
return (crc & 0xffff) | 0x10000;
|
||||
}
|
||||
td::Ref<vm::Stack> prepare_vm_stack(td::Ref<vm::CellSlice> body) {
|
||||
td::Ref<vm::Stack> stack_ref{true};
|
||||
td::RefInt256 acc_addr{true};
|
||||
//CHECK(acc_addr.write().import_bits(account.addr.cbits(), 256));
|
||||
vm::Stack& stack = stack_ref.write();
|
||||
stack.push_int(td::RefInt256{true, 10000000000});
|
||||
stack.push_int(td::RefInt256{true, 10000000000});
|
||||
stack.push_cell(vm::CellBuilder().finalize());
|
||||
stack.push_cellslice(std::move(body));
|
||||
return stack_ref;
|
||||
}
|
||||
|
||||
td::Ref<vm::Tuple> prepare_vm_c7() {
|
||||
// TODO: fix initialization of c7
|
||||
td::BitArray<256> rand_seed;
|
||||
rand_seed.as_slice().fill(0);
|
||||
td::RefInt256 rand_seed_int{true};
|
||||
rand_seed_int.unique_write().import_bits(rand_seed.cbits(), 256, false);
|
||||
auto tuple = vm::make_tuple_ref(
|
||||
td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
|
||||
td::make_refint(0), // actions:Integer
|
||||
td::make_refint(0), // msgs_sent:Integer
|
||||
td::make_refint(0), // unixtime:Integer
|
||||
td::make_refint(0), // block_lt:Integer
|
||||
td::make_refint(0), // trans_lt:Integer
|
||||
std::move(rand_seed_int), // rand_seed:Integer
|
||||
block::CurrencyCollection(1000000000).as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
||||
vm::load_cell_slice_ref(vm::CellBuilder().finalize()) // myself:MsgAddressInt
|
||||
//vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
||||
); // global_config:(Maybe Cell) ] = SmartContractInfo;
|
||||
//LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string();
|
||||
return vm::make_tuple_ref(std::move(tuple));
|
||||
}
|
||||
|
||||
SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stack> stack, td::Ref<vm::Tuple> c7,
|
||||
vm::GasLimits gas, bool ignore_chksig) {
|
||||
auto gas_credit = gas.gas_credit;
|
||||
vm::init_op_cp0();
|
||||
vm::DictionaryBase::get_empty_dictionary();
|
||||
|
||||
class Logger : public td::LogInterface {
|
||||
public:
|
||||
void append(td::CSlice slice) override {
|
||||
res.append(slice.data(), slice.size());
|
||||
}
|
||||
std::string res;
|
||||
};
|
||||
Logger logger;
|
||||
vm::VmLog log{&logger, td::LogOptions::plain()};
|
||||
|
||||
if (GET_VERBOSITY_LEVEL() >= VERBOSITY_NAME(DEBUG)) {
|
||||
log.log_options.level = 4;
|
||||
log.log_options.fix_newlines = true;
|
||||
log.log_mask |= vm::VmLog::DumpStack;
|
||||
} else {
|
||||
log.log_options.level = 0;
|
||||
log.log_mask = 0;
|
||||
}
|
||||
|
||||
SmartContract::Answer res;
|
||||
vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log};
|
||||
vm.set_c7(std::move(c7));
|
||||
vm.set_chksig_always_succeed(ignore_chksig);
|
||||
try {
|
||||
res.code = ~vm.run();
|
||||
} catch (...) {
|
||||
LOG(FATAL) << "catch unhandled exception";
|
||||
}
|
||||
res.new_state = std::move(state);
|
||||
res.stack = vm.get_stack_ref();
|
||||
gas = vm.get_gas_limits();
|
||||
res.gas_used = gas.gas_consumed();
|
||||
res.accepted = gas.gas_credit == 0;
|
||||
res.success = (res.accepted && (unsigned)res.code <= 1);
|
||||
if (GET_VERBOSITY_LEVEL() >= VERBOSITY_NAME(DEBUG)) {
|
||||
LOG(DEBUG) << "VM log\n" << logger.res;
|
||||
std::ostringstream os;
|
||||
res.stack->dump(os);
|
||||
LOG(DEBUG) << "VM stack:\n" << os.str();
|
||||
LOG(DEBUG) << "VM exit code: " << res.code;
|
||||
LOG(DEBUG) << "VM accepted: " << res.accepted;
|
||||
LOG(DEBUG) << "VM success: " << res.success;
|
||||
}
|
||||
if (res.success) {
|
||||
res.new_state.data = vm.get_c4();
|
||||
res.actions = vm.get_d(5);
|
||||
}
|
||||
LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success))
|
||||
<< "Accepted but failed with code " << res.code << "\n"
|
||||
<< res.gas_used << "\n";
|
||||
return res;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
td::Ref<vm::CellSlice> SmartContract::empty_slice() {
|
||||
return vm::load_cell_slice_ref(vm::CellBuilder().finalize());
|
||||
}
|
||||
|
||||
size_t SmartContract::code_size() const {
|
||||
return vm::std_boc_serialize(state_.code).ok().size();
|
||||
}
|
||||
size_t SmartContract::data_size() const {
|
||||
return vm::std_boc_serialize(state_.data).ok().size();
|
||||
}
|
||||
|
||||
block::StdAddress SmartContract::get_address(WorkchainId workchain_id) const {
|
||||
return GenericAccount::get_address(workchain_id, get_init_state());
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> SmartContract::get_init_state() const {
|
||||
return GenericAccount::get_init_state(get_state().code, get_state().data);
|
||||
}
|
||||
|
||||
SmartContract::Answer SmartContract::run_method(Args args) {
|
||||
if (!args.c7) {
|
||||
args.c7 = prepare_vm_c7();
|
||||
}
|
||||
if (!args.limits) {
|
||||
args.limits = vm::GasLimits{(long long)0, (long long)1000000, (long long)10000};
|
||||
}
|
||||
CHECK(args.stack);
|
||||
CHECK(args.method_id);
|
||||
args.stack.value().write().push_smallint(args.method_id.unwrap());
|
||||
auto res =
|
||||
run_smartcont(get_state(), args.stack.unwrap(), args.c7.unwrap(), args.limits.unwrap(), args.ignore_chksig);
|
||||
state_ = res.new_state;
|
||||
return res;
|
||||
}
|
||||
|
||||
SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
||||
if (!args.c7) {
|
||||
args.c7 = prepare_vm_c7();
|
||||
}
|
||||
if (!args.limits) {
|
||||
args.limits = vm::GasLimits{1000000};
|
||||
}
|
||||
if (!args.stack) {
|
||||
args.stack = td::Ref<vm::Stack>(true);
|
||||
}
|
||||
CHECK(args.method_id);
|
||||
args.stack.value().write().push_smallint(args.method_id.unwrap());
|
||||
return run_smartcont(get_state(), args.stack.unwrap(), args.c7.unwrap(), args.limits.unwrap(), args.ignore_chksig);
|
||||
}
|
||||
|
||||
SmartContract::Answer SmartContract::run_get_method(td::Slice method, Args args) const {
|
||||
return run_get_method(args.set_method_id(method));
|
||||
}
|
||||
|
||||
SmartContract::Answer SmartContract::send_external_message(td::Ref<vm::Cell> cell, Args args) {
|
||||
return run_method(args.set_stack(prepare_vm_stack(vm::load_cell_slice_ref(cell))).set_method_id(-1));
|
||||
}
|
||||
} // namespace ton
|
116
crypto/smc-envelope/SmartContract.h
Normal file
116
crypto/smc-envelope/SmartContract.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "vm/cells.h"
|
||||
#include "vm/stack.hpp"
|
||||
#include "vm/continuation.h"
|
||||
|
||||
#include "td/utils/optional.h"
|
||||
#include "td/utils/crypto.h"
|
||||
|
||||
#include "block/block.h"
|
||||
|
||||
namespace ton {
|
||||
class SmartContract : public td::CntObject {
|
||||
static td::Ref<vm::CellSlice> empty_slice();
|
||||
|
||||
public:
|
||||
struct State {
|
||||
td::Ref<vm::Cell> code;
|
||||
td::Ref<vm::Cell> data;
|
||||
};
|
||||
|
||||
SmartContract(State state) : state_(std::move(state)) {
|
||||
}
|
||||
|
||||
struct Answer {
|
||||
SmartContract::State new_state;
|
||||
bool accepted;
|
||||
bool success;
|
||||
td::Ref<vm::Stack> stack;
|
||||
td::Ref<vm::Cell> actions;
|
||||
td::int32 code;
|
||||
td::int64 gas_used;
|
||||
};
|
||||
|
||||
struct Args {
|
||||
td::optional<td::int32> method_id;
|
||||
td::optional<vm::GasLimits> limits;
|
||||
td::optional<td::Ref<vm::Tuple>> c7;
|
||||
td::optional<td::Ref<vm::Stack>> stack;
|
||||
bool ignore_chksig{false};
|
||||
|
||||
Args() {
|
||||
}
|
||||
Args(std::initializer_list<vm::StackEntry> stack)
|
||||
: stack(td::Ref<vm::Stack>(true, std::vector<vm::StackEntry>(std::move(stack)))) {
|
||||
}
|
||||
Args&& set_method_id(td::Slice method_name) {
|
||||
unsigned crc = td::crc16(method_name);
|
||||
return set_method_id((crc & 0xffff) | 0x10000);
|
||||
}
|
||||
Args&& set_method_id(td::int32 method_id) {
|
||||
this->method_id = method_id;
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_limits(vm::GasLimits limits) {
|
||||
this->limits = std::move(limits);
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_c7(td::Ref<vm::Tuple> c7) {
|
||||
this->c7 = std::move(c7);
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_stack(std::vector<vm::StackEntry> stack) {
|
||||
this->stack = td::Ref<vm::Stack>(true, std::move(stack));
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_stack(td::Ref<vm::Stack> stack) {
|
||||
this->stack = std::move(stack);
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_ignore_chksig(bool ignore_chksig) {
|
||||
this->ignore_chksig = ignore_chksig;
|
||||
return std::move(*this);
|
||||
}
|
||||
};
|
||||
|
||||
Answer run_method(Args args = {});
|
||||
Answer run_get_method(Args args = {}) const;
|
||||
Answer run_get_method(td::Slice method, Args args = {}) const;
|
||||
Answer send_external_message(td::Ref<vm::Cell> cell, Args args = {});
|
||||
|
||||
size_t code_size() const;
|
||||
size_t data_size() const;
|
||||
static td::Ref<SmartContract> create(State state) {
|
||||
return td::Ref<SmartContract>{true, std::move(state)};
|
||||
}
|
||||
|
||||
block::StdAddress get_address(WorkchainId workchain_id = basechainId) const;
|
||||
td::Ref<vm::Cell> get_init_state() const;
|
||||
|
||||
const State& get_state() const {
|
||||
return state_;
|
||||
}
|
||||
|
||||
protected:
|
||||
State state_;
|
||||
};
|
||||
} // namespace ton
|
72
crypto/smc-envelope/SmartContractCode.cpp
Normal file
72
crypto/smc-envelope/SmartContractCode.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#include "SmartContractCode.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include <map>
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
namespace ton {
|
||||
namespace {
|
||||
const auto& get_map() {
|
||||
static auto map = [] {
|
||||
class Cmp : public std::less<> {
|
||||
public:
|
||||
using is_transparent = void;
|
||||
};
|
||||
std::map<std::string, td::Ref<vm::Cell>, Cmp> map;
|
||||
auto with_tvm_code = [&](auto name, td::Slice code_str) {
|
||||
map[name] = vm::std_boc_deserialize(td::base64_decode(code_str).move_as_ok()).move_as_ok();
|
||||
};
|
||||
#include "smartcont/auto/multisig-code.cpp"
|
||||
#include "smartcont/auto/simple-wallet-ext-code.cpp"
|
||||
#include "smartcont/auto/simple-wallet-code.cpp"
|
||||
#include "smartcont/auto/wallet-code.cpp"
|
||||
return map;
|
||||
}();
|
||||
return map;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
td::Result<td::Ref<vm::Cell>> SmartContractCode::load(td::Slice name) {
|
||||
auto& map = get_map();
|
||||
auto it = map.find(name);
|
||||
if (it == map.end()) {
|
||||
return td::Status::Error(PSLICE() << "Can't load td::ref<vm::cell " << name);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
td::Ref<vm::Cell> SmartContractCode::multisig() {
|
||||
auto res = load("multisig").move_as_ok();
|
||||
return res;
|
||||
}
|
||||
td::Ref<vm::Cell> SmartContractCode::wallet() {
|
||||
auto res = load("wallet").move_as_ok();
|
||||
return res;
|
||||
}
|
||||
td::Ref<vm::Cell> SmartContractCode::simple_wallet() {
|
||||
auto res = load("simple-wallet").move_as_ok();
|
||||
return res;
|
||||
}
|
||||
td::Ref<vm::Cell> SmartContractCode::simple_wallet_ext() {
|
||||
static auto res = load("simple-wallet-ext").move_as_ok();
|
||||
return res;
|
||||
}
|
||||
} // namespace ton
|
30
crypto/smc-envelope/SmartContractCode.h
Normal file
30
crypto/smc-envelope/SmartContractCode.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#include "vm/cells.h"
|
||||
|
||||
namespace ton {
|
||||
class SmartContractCode {
|
||||
public:
|
||||
static td::Result<td::Ref<vm::Cell>> load(td::Slice name);
|
||||
static td::Ref<vm::Cell> multisig();
|
||||
static td::Ref<vm::Cell> wallet();
|
||||
static td::Ref<vm::Cell> simple_wallet();
|
||||
static td::Ref<vm::Cell> simple_wallet_ext();
|
||||
};
|
||||
} // namespace ton
|
62
crypto/smc-envelope/TestGiver.cpp
Normal file
62
crypto/smc-envelope/TestGiver.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#include "TestGiver.h"
|
||||
#include "GenericAccount.h"
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
namespace ton {
|
||||
const block::StdAddress& TestGiver::address() noexcept {
|
||||
static block::StdAddress res =
|
||||
block::StdAddress::parse("kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny").move_as_ok();
|
||||
//static block::StdAddress res =
|
||||
//block::StdAddress::parse("kf9tswzQaryeJ4aAYLy_phLhx4afF1aEvpUVak-2BuA0CmZi").move_as_ok();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash TestGiver::get_init_code_hash() noexcept {
|
||||
return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok());
|
||||
//return vm::CellHash::from_slice(td::base64_decode("YV/IANhoI22HVeatFh6S5LbCHp+5OilARfzW+VQPZgQ=").move_as_ok());
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept {
|
||||
vm::CellBuilder cb;
|
||||
GenericAccount::store_int_message(cb, dest_address, gramms);
|
||||
cb.store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
|
||||
}
|
||||
|
||||
td::Result<td::uint32> TestGiver::get_seqno() const {
|
||||
return TRY_VM(get_seqno_or_throw());
|
||||
}
|
||||
|
||||
td::Result<td::uint32> TestGiver::get_seqno_or_throw() const {
|
||||
if (state_.data.is_null()) {
|
||||
return 0;
|
||||
}
|
||||
auto seqno = vm::load_cell_slice(state_.data).fetch_ulong(32);
|
||||
if (seqno == vm::CellSlice::fetch_ulong_eof) {
|
||||
return td::Status::Error("Failed to parse seq_no");
|
||||
}
|
||||
return static_cast<td::uint32>(seqno);
|
||||
}
|
||||
} // namespace ton
|
39
crypto/smc-envelope/TestGiver.h
Normal file
39
crypto/smc-envelope/TestGiver.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
#include "SmartContract.h"
|
||||
#include "block/block.h"
|
||||
#include "vm/cells/CellString.h"
|
||||
namespace ton {
|
||||
class TestGiver : public SmartContract {
|
||||
public:
|
||||
explicit TestGiver(State state) : ton::SmartContract(std::move(state)) {
|
||||
}
|
||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||
static const block::StdAddress& address() noexcept;
|
||||
static vm::CellHash get_init_code_hash() noexcept;
|
||||
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept;
|
||||
|
||||
td::Result<td::uint32> get_seqno() const;
|
||||
|
||||
private:
|
||||
td::Result<td::uint32> get_seqno_or_throw() const;
|
||||
};
|
||||
} // namespace ton
|
91
crypto/smc-envelope/TestWallet.cpp
Normal file
91
crypto/smc-envelope/TestWallet.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#include "TestWallet.h"
|
||||
#include "GenericAccount.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
namespace ton {
|
||||
td::Ref<vm::Cell> TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
auto code = get_init_code();
|
||||
auto data = get_init_data(public_key);
|
||||
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept {
|
||||
std::string seq_no(4, 0);
|
||||
auto signature =
|
||||
private_key.sign(vm::CellBuilder().store_bytes(seq_no).finalize()->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).store_bytes(seq_no).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept {
|
||||
td::int32 send_mode = 3;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
send_mode += 128;
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
GenericAccount::store_int_message(cb, dest_address, gramms);
|
||||
cb.store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
auto message_outer =
|
||||
vm::CellBuilder().store_long(seqno, 32).store_long(send_mode, 8).store_ref(message_inner).finalize();
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::get_init_code() noexcept {
|
||||
static auto res = [] {
|
||||
auto serialized_code = td::base64_decode(
|
||||
"te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/"
|
||||
"0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA==")
|
||||
.move_as_ok();
|
||||
return vm::std_boc_deserialize(serialized_code).move_as_ok();
|
||||
}();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash TestWallet::get_init_code_hash() noexcept {
|
||||
return get_init_code()->get_hash();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> TestWallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
||||
}
|
||||
|
||||
td::Result<td::uint32> TestWallet::get_seqno() const {
|
||||
return TRY_VM(get_seqno_or_throw());
|
||||
}
|
||||
|
||||
td::Result<td::uint32> TestWallet::get_seqno_or_throw() const {
|
||||
if (state_.data.is_null()) {
|
||||
return 0;
|
||||
}
|
||||
auto seqno = vm::load_cell_slice(state_.data).fetch_ulong(32);
|
||||
if (seqno == vm::CellSlice::fetch_ulong_eof) {
|
||||
return td::Status::Error("Failed to parse seq_no");
|
||||
}
|
||||
return static_cast<td::uint32>(seqno);
|
||||
}
|
||||
|
||||
} // namespace ton
|
48
crypto/smc-envelope/TestWallet.h
Normal file
48
crypto/smc-envelope/TestWallet.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "smc-envelope/SmartContract.h"
|
||||
#include "vm/cells.h"
|
||||
#include "Ed25519.h"
|
||||
#include "block/block.h"
|
||||
#include "vm/cells/CellString.h"
|
||||
|
||||
namespace ton {
|
||||
class TestWallet : public ton::SmartContract {
|
||||
public:
|
||||
explicit TestWallet(State state) : ton::SmartContract(std::move(state)) {
|
||||
}
|
||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept;
|
||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept;
|
||||
|
||||
static td::Ref<vm::Cell> get_init_code() noexcept;
|
||||
static vm::CellHash get_init_code_hash() noexcept;
|
||||
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
|
||||
td::Result<td::uint32> get_seqno() const;
|
||||
|
||||
private:
|
||||
td::Result<td::uint32> get_seqno_or_throw() const;
|
||||
};
|
||||
} // namespace ton
|
100
crypto/smc-envelope/Wallet.cpp
Normal file
100
crypto/smc-envelope/Wallet.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#include "Wallet.h"
|
||||
#include "GenericAccount.h"
|
||||
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cells/CellString.h"
|
||||
#include "td/utils/base64.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace ton {
|
||||
td::Ref<vm::Cell> Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
auto code = get_init_code();
|
||||
auto data = get_init_data(public_key);
|
||||
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept {
|
||||
td::uint32 seqno = 0;
|
||||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max();
|
||||
auto signature =
|
||||
private_key
|
||||
.sign(vm::CellBuilder().store_long(seqno, 32).store_long(valid_until, 32).finalize()->get_hash().as_slice())
|
||||
.move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).store_long(seqno, 32).store_long(valid_until, 32).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept {
|
||||
td::int32 send_mode = 3;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
send_mode += 128;
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
GenericAccount::store_int_message(cb, dest_address, gramms);
|
||||
cb.store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
|
||||
auto message_outer = vm::CellBuilder()
|
||||
.store_long(seqno, 32)
|
||||
.store_long(valid_until, 32)
|
||||
.store_long(send_mode, 8)
|
||||
.store_ref(message_inner)
|
||||
.finalize();
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_code() noexcept {
|
||||
static auto res = [] {
|
||||
auto serialized_code = td::base64_decode(
|
||||
"te6ccgEEAQEAAAAAVwAAqv8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/"
|
||||
"0VExuvKhA/kBVBBC+RDyovgAApMg10qW0wfUAvsA6NGkyMsfy//J7VQ=")
|
||||
.move_as_ok();
|
||||
return vm::std_boc_deserialize(serialized_code).move_as_ok();
|
||||
}();
|
||||
return res;
|
||||
}
|
||||
|
||||
vm::CellHash Wallet::get_init_code_hash() noexcept {
|
||||
return get_init_code()->get_hash();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
||||
}
|
||||
|
||||
td::Result<td::uint32> Wallet::get_seqno() const {
|
||||
return TRY_VM(get_seqno_or_throw());
|
||||
}
|
||||
|
||||
td::Result<td::uint32> Wallet::get_seqno_or_throw() const {
|
||||
if (state_.data.is_null()) {
|
||||
return 0;
|
||||
}
|
||||
//FIXME use get method
|
||||
return static_cast<td::uint32>(vm::load_cell_slice(state_.data).fetch_ulong(32));
|
||||
}
|
||||
|
||||
} // namespace ton
|
48
crypto/smc-envelope/Wallet.h
Normal file
48
crypto/smc-envelope/Wallet.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "smc-envelope/SmartContract.h"
|
||||
#include "vm/cells.h"
|
||||
#include "Ed25519.h"
|
||||
#include "block/block.h"
|
||||
#include "vm/cells/CellString.h"
|
||||
|
||||
namespace ton {
|
||||
class Wallet : ton::SmartContract {
|
||||
public:
|
||||
explicit Wallet(State state) : ton::SmartContract(std::move(state)) {
|
||||
}
|
||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept;
|
||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||
const block::StdAddress& dest_address) noexcept;
|
||||
|
||||
static td::Ref<vm::Cell> get_init_code() noexcept;
|
||||
static vm::CellHash get_init_code_hash() noexcept;
|
||||
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||
|
||||
td::Result<td::uint32> get_seqno() const;
|
||||
|
||||
private:
|
||||
td::Result<td::uint32> get_seqno_or_throw() const;
|
||||
};
|
||||
} // namespace ton
|
Loading…
Add table
Add a link
Reference in a new issue