1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

pow-testgiver support

This commit is contained in:
ton 2020-07-06 17:07:20 +03:00
parent dbde9c1c40
commit f064b1047a
257 changed files with 6665 additions and 2608 deletions

View file

@ -259,6 +259,7 @@ set(FIFT_TEST_SOURCE
PARENT_SCOPE
)
add_library(ton_crypto STATIC ${TON_CRYPTO_SOURCE})
target_include_directories(ton_crypto PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
@ -306,6 +307,12 @@ if (WINGETOPT_FOUND)
target_link_libraries_system(tlbc wingetopt)
endif()
add_executable(pow-miner util/pow-miner.cpp util/Miner.cpp util/Miner.h)
target_link_libraries(pow-miner PUBLIC ton_crypto ton_block)
if (WINGETOPT_FOUND)
target_link_libraries_system(fift wingetopt)
endif()
add_library(ton_block ${BLOCK_SOURCE})
target_include_directories(ton_block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/block> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
@ -371,6 +378,7 @@ if (NOT CMAKE_CROSSCOMPILING)
GenFif(DEST smartcont/auto/restricted-wallet-code SOURCE smartcont/restricted-wallet-code.fc NAME restricted-wallet)
GenFif(DEST smartcont/auto/restricted-wallet2-code SOURCE smartcont/restricted-wallet2-code.fc NAME restricted-wallet2)
GenFif(DEST smartcont/auto/restricted-wallet3-code SOURCE smartcont/restricted-wallet3-code.fc NAME restricted-wallet3)
GenFif(DEST smartcont/auto/pow-testgiver-code SOURCE smartcont/pow-testgiver-code.fc NAME pow-testgiver)
GenFif(DEST smartcont/auto/dns-manual-code SOURCE smartcont/dns-manual-code.fc NAME dns-manual)
GenFif(DEST smartcont/auto/dns-auto-code SOURCE smartcont/dns-auto-code.fc NAME dns-auto)

View file

@ -267,6 +267,9 @@ class AnyIntView {
return size() > 1 ? (double)digits[size() - 1] + (double)digits[size() - 2] * (1.0 / Tr::Base)
: (double)digits[size() - 1];
}
bool is_odd_any() const {
return size() > 0 && (digits[0] & 1);
}
word_t to_long_any() const;
int parse_hex_any(const char* str, int str_len, int* frac = nullptr);
int parse_binary_any(const char* str, int str_len, int* frac = nullptr);
@ -658,6 +661,15 @@ class BigIntG {
word_t to_long() const {
return as_any_int().to_long_any();
}
bool is_odd() const {
return n > 0 && (digits[0] & 1);
}
bool is_even() const {
return n > 0 && !(digits[0] & 1);
}
word_t mod_pow2_short(int pow) const {
return n > 0 ? digits[0] & ((1 << pow) - 1) : 0;
}
private:
word_t top_word() const {

View file

@ -19,6 +19,7 @@
#pragma once
#include <string>
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/buffer.h"
#include "bitstring.h"

View file

@ -399,6 +399,18 @@ x{B7B5} @Defop(8u+1) QUFITS
x{B7B600} @Defop QFITSX
x{B7B601} @Defop QUFITSX
// advanced integer constants
{ 0 { over 1 and 0= } { 1+ swap 2/ swap } while } : pow2decomp
{ dup 8 fits { PUSHINT } {
dup pow2decomp over 1 = { nip nip PUSHPOW2 } {
over -1 = { nip nip PUSHNEGPOW2 } {
dup 20 >= { rot drop -rot PUSHINT swap LSHIFT# } {
{ drop PUSHINT } {
not pow2decomp swap -1 = { nip PUSHPOW2DEC } {
drop PUSHINT
} cond } cond } cond } cond } cond } cond
} dup : PUSHINTX : INTX
// integer comparison
x{B8} @Defop SGN
x{B9} @Defop LESS

View file

@ -20,6 +20,7 @@
#include "words.h"
#include "td/utils/PathView.h"
#include "td/utils/filesystem.h"
#include "td/utils/misc.h"
#include "td/utils/port/path.h"
namespace fift {

View file

@ -183,6 +183,9 @@ AsmOp AsmOp::IntConst(td::RefInt256 x) {
if (k >= 0) {
return AsmOp::Const(k, "PUSHNEGPOW2");
}
if (!x->mod_pow2_short(23)) {
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINTX");
}
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT");
}

View file

@ -0,0 +1,59 @@
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include
{ ."usage: " $0 type ." <workchain-id> <giver-id> <amount> <interval> <min-complexity> <init-complexity> <max-complexity> [<filename-base>]" cr
."Creates a new proof-of-work testgiver with unique 32-bit identifier <giver-id> designed to deliver <amount> every <interval> seconds, with SHA256 hash complexity between 2**<min-complexity> and 2**<max-complexity>, with private key saved to or loaded from <filename-base>.pk" cr
."('pow-giver.pk' by default)" cr 1 halt
} : usage
$# 7 - -2 and ' usage if
8 :$1..n
$1 parse-workchain-id =: wc // set workchain id from command line argument
$2 parse-int dup =: subwallet-id
0= abort"giver-id must be non-zero"
$3 $>GR =: amount
$4 parse-int dup =: interval
dup 24 ufits and 0= abort"invalid interval"
$5 parse-int dup =: min-cpl
1- 8 ufits not abort"invalid minimal log-complexity (must be 1..256)"
$6 parse-int dup =: init-cpl
1- 8 ufits not abort"invalid initial log-complexity (must be 1..256)"
$7 parse-int dup =: max-cpl
1- 8 ufits not abort"invalid maximal log-complexity (must be 1..256)"
$8 "pow-giver" replace-if-null =: file-base
min-cpl init-cpl > abort"initial complexity cannot be below minimal complexity"
max-cpl init-cpl < abort"initial complexity cannot exceed maximal complexity"
subwallet-id (.) 1 ' $+ does : +subwallet
."Creating new proof-of-work testgiver in workchain " wc .
."with unique giver id " subwallet-id . cr
."Designed to give " amount .GR ."approximately every " interval . ."seconds" cr
."Complexity (in SHA256 hashes): min=" min-cpl 1<< . ."init=" init-cpl 1<< . ."max=" max-cpl 1<< . cr
"auto/pow-testgiver-code.fif" include // code
{ 256 swap - 8 u, } : cpl,
<b 0 32 u, subwallet-id 32 u, // seqno wallet-id
file-base +".pk" load-generate-keypair constant wallet_pk B, // pubkey
newkeypair nip 16 B| drop B, // seed
256 init-cpl - 1<< 256 u, // pow_complexity
-1 32 i, // last_success
<b amount Gram, interval 32 u, max-cpl cpl, min-cpl cpl, b> ref,
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 hashu wc swap 2dup 2constant wallet_addr
."new PoW testgiver address = " 2dup .addr cr
2dup file-base +subwallet +".addr" save-address-verbose
."Non-bounceable address (for init): " 2dup 7 .Addr cr
."Bounceable address (for later access): " 6 .Addr cr
<b subwallet-id 32 u, -1 32 i, 0 32 u, b>
dup ."signing message: " <s csr. cr
dup hashu 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 +subwallet +"-query.boc" tuck B>file
."(Saved proof-of-work testgiver creating query to file " type .")" cr

View file

@ -0,0 +1,158 @@
;; Advanced TestGiver smart contract with Proof-of-Work verification
int ufits(int x, int bits) impure asm "UFITSX";
() recv_internal(slice in_msg) impure {
;; do nothing for internal messages
}
() check_proof_of_work(slice cs) impure inline_ref {
var hash = slice_hash(cs);
var ds = get_data().begin_parse();
var (stored_seqno_sw, public_key, seed, pow_complexity) = (ds~load_uint(64), ds~load_uint(256), ds~load_uint(128), ds~load_uint(256));
throw_unless(24, hash < pow_complexity); ;; hash problem NOT solved
var (op, flags, expire, whom, rdata1, rseed, rdata2) = (cs~load_uint(32), cs~load_int(8), cs~load_uint(32), cs~load_uint(256), cs~load_uint(256), cs~load_uint(128), cs~load_uint(256));
cs.end_parse();
ufits(expire - now(), 10);
throw_unless(25, (rseed == seed) & (rdata1 == rdata2));
;; Proof of Work correct
accept_message();
randomize_lt();
randomize(rdata1);
var (last_success, xdata) = (ds~load_uint(32), ds~load_ref());
ds.end_parse();
ds = xdata.begin_parse();
var (amount, target_delta, min_cpl, max_cpl) = (ds~load_grams(), ds~load_uint(32), ds~load_uint(8), ds~load_uint(8));
ds.end_parse();
;; recompute complexity
int delta = now() - last_success;
if (delta > 0) {
int factor = muldivr(delta, 1 << 128, target_delta);
factor = min(max(factor, 7 << 125), 9 << 125); ;; factor must be in range 7/8 .. 9/8
pow_complexity = muldivr(pow_complexity, factor, 1 << 128); ;; rescale complexity
pow_complexity = min(max(pow_complexity, 1 << min_cpl), 1 << max_cpl);
}
;; update data
set_data(begin_cell()
.store_uint(stored_seqno_sw, 64)
.store_uint(public_key, 256)
.store_uint(random() >> 128, 128) ;; new seed
.store_uint(pow_complexity, 256)
.store_uint(now(), 32) ;; new last_success
.store_ref(xdata)
.end_cell());
commit();
;; create outbound message
send_raw_message(begin_cell()
.store_uint(((flags & 1) << 6) | 0x84, 9)
.store_int(flags >> 2, 8)
.store_uint(whom, 256)
.store_grams(amount)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.end_cell(), 3);
}
() rescale_complexity(slice cs) impure inline_ref {
var (op, expire) = (cs~load_uint(32), cs~load_uint(32));
cs.end_parse();
int time = now();
throw_unless(28, time > expire);
var ds = get_data().begin_parse();
var (skipped_data, pow_complexity, last_success, xdata) = (ds~load_bits(64 + 256 + 128), ds~load_uint(256), ds~load_uint(32), ds~load_ref());
ds.end_parse();
throw_unless(29, expire > last_success);
ds = xdata.begin_parse();
var (amount, target_delta) = (ds~load_grams(), ds~load_uint(32));
int delta = time - last_success;
throw_unless(30, delta >= target_delta * 16);
accept_message();
var (min_cpl, max_cpl) = (ds~load_uint(8), ds~load_uint(8));
ds.end_parse();
int factor = muldivr(delta, 1 << 128, target_delta);
int max_complexity = (1 << max_cpl);
int max_factor = muldiv(max_complexity, 1 << 128, pow_complexity);
pow_complexity = (max_factor < factor ? max_complexity : muldivr(pow_complexity, factor, 1 << 128));
last_success = time - target_delta;
set_data(begin_cell()
.store_slice(skipped_data)
.store_uint(pow_complexity, 256)
.store_uint(last_success, 32) ;; new last_success
.store_ref(xdata)
.end_cell());
}
(slice, ()) ~update_params(slice ds, cell pref) inline_ref {
var cs = pref.begin_parse();
var reset_cpl = cs~load_uint(8);
var (seed, pow_complexity, last_success) = (ds~load_uint(128), ds~load_uint(256), ds~load_uint(32));
if (reset_cpl) {
randomize(seed);
pow_complexity = (1 << reset_cpl);
seed = (random() >> 128);
}
var c = begin_cell()
.store_uint(seed, 128)
.store_uint(pow_complexity, 256)
.store_uint(now(), 32)
.store_ref(begin_cell().store_slice(cs).end_cell())
.end_cell();
return (begin_parse(c), ());
}
() recv_external(slice in_msg) impure {
var op = in_msg.preload_uint(32);
if (op == 0x4d696e65) {
;; Mine = Obtain test grams by presenting valid proof of work
return check_proof_of_work(in_msg);
}
if (op == 0x5253636c) {
;; RScl = Rescale complexity if no success for long time
return rescale_complexity(in_msg);
}
var signature = in_msg~load_bits(512);
var cs = in_msg;
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
throw_if(35, valid_until <= now());
var ds = get_data().begin_parse();
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
throw_unless(33, msg_seqno == stored_seqno);
throw_unless(34, (subwallet_id == stored_subwallet) | (subwallet_id == 0));
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
accept_message();
cs~touch();
while (cs.slice_refs()) {
var ref = cs~load_ref();
var mode = cs~load_uint(8);
if (mode < 0xff) {
send_raw_message(ref, mode);
} else {
ds~update_params(ref);
}
}
set_data(begin_cell()
.store_uint(stored_seqno + 1, 32)
.store_uint(stored_subwallet, 32)
.store_uint(public_key, 256)
.store_slice(ds)
.end_cell());
}
;; Get methods
int seqno() method_id {
return get_data().begin_parse().preload_uint(32);
}
;; gets (seed, pow_complexity, amount, interval)
(int, int, int, int) get_pow_params() method_id {
var ds = get_data().begin_parse().skip_bits(32 + 32 + 256);
var (seed, pow_complexity, xdata) = (ds~load_uint(128), ds~load_uint(256), ds.preload_ref());
ds = xdata.begin_parse();
return (seed, pow_complexity, ds~load_grams(), ds.preload_uint(32));
}
int get_public_key() method_id {
var ds = get_data().begin_parse();
ds~load_uint(32 + 32);
return ds.preload_uint(256);
}

View file

@ -46,8 +46,10 @@ $3 parse-int =: subwallet_id
$4 parse-int =: seqno
$5 $>cc extra-cc+! extra-currencies @ 2=: amount
$6 "wallet-query" replace-if-null =: savefile
subwallet_id (.) 1 ' $+ does : +subwallet
file-base +".addr" load-address
file-base +subwallet +".addr" dup file-exists? { drop file-base +".addr" } ifnot
load-address
2dup 2constant wallet_addr
."Source wallet address = " 2dup .addr cr 6 .Addr cr
file-base +".pk" load-keypair nip constant wallet_pk

View file

@ -1,3 +1,22 @@
/*
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-2020 Telegram Systems LLP
*/
#include "PaymentChannel.h"
#include "GenericAccount.h"
#include "vm/cells.h"

View file

@ -1,3 +1,22 @@
/*
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-2020 Telegram Systems LLP
*/
#pragma once
#include "vm/cells.h"
#include "vm/cellslice.h"

View file

@ -288,7 +288,8 @@ std::string wycheproof_ed25519() {
"sig" : "7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab07a9155711ecfaf7f99f277bad0c6ae7e39d4eef676573336a5c51eb6f946b30d2020",
"result" : "invalid",
"flags" : []
},)abcd" R"abcd(
},)abcd"
R"abcd(
{
"tcId" : 34,
"comment" : "include pk in signature",
@ -570,7 +571,8 @@ std::string wycheproof_ed25519() {
"flags" : [
"SignatureMalleability"
]
},)abcd" R"abcd(
},)abcd"
R"abcd(
{
"tcId" : 68,
"comment" : "checking malleability ",
@ -858,7 +860,8 @@ std::string wycheproof_ed25519() {
"flags" : []
}
]
},)abcd" R"abcd(
},)abcd"
R"abcd(
{
"key" : {
"curve" : "edwards25519",

View file

@ -20,6 +20,7 @@
#include <iostream>
#include <map>
#include "vm/cellslice.h"
#include <functional>
namespace tlb {

108
crypto/util/Miner.cpp Normal file
View file

@ -0,0 +1,108 @@
#include "Miner.h"
#include "td/utils/Random.h"
#include "td/utils/misc.h"
#include "td/utils/crypto.h"
#include "td/utils/port/Clocks.h"
#include <openssl/sha.h>
namespace ton {
#pragma pack(push, 1)
struct HData {
unsigned char op[4];
signed char flags = -4;
unsigned char expire[4] = {}, myaddr[32] = {}, rdata1[32] = {}, pseed[16] = {}, rdata2[32] = {};
void inc() {
for (long i = 31; !(rdata1[i] = ++(rdata2[i])); --i) {
}
}
void set_expire(unsigned x) {
for (int i = 3; i >= 0; --i) {
expire[i] = (x & 0xff);
x >>= 8;
}
}
td::Slice as_slice() const {
return td::Slice(reinterpret_cast<const td::uint8*>(this), sizeof(*this));
}
};
struct HDataEnv {
unsigned char d1 = 0, d2 = sizeof(HData) * 2;
HData body;
td::Slice as_slice() const {
return td::Slice(reinterpret_cast<const td::uint8*>(this), sizeof(*this));
}
void init(const block::StdAddress& my_address, td::Slice seed) {
std::memcpy(body.myaddr, my_address.addr.data(), sizeof(body.myaddr));
body.flags = static_cast<td::int8>(my_address.workchain * 4 + my_address.bounceable);
CHECK(seed.size() == 16);
std::memcpy(body.pseed, seed.data(), 16);
std::memcpy(body.op, "Mine", 4);
td::Random::secure_bytes(body.rdata1, 32);
std::memcpy(body.rdata2, body.rdata1, 32);
}
};
static_assert(std::is_trivially_copyable<HDataEnv>::value, "HDataEnv must be a trivial type");
#pragma pack(pop)
td::optional<std::string> Miner::run(const Options& options) {
HDataEnv H;
H.init(options.my_address, td::Slice(options.seed.data(), options.seed.size()));
td::Slice data = H.as_slice();
CHECK(data.size() == 123);
constexpr size_t prefix_size = 72;
constexpr size_t guard_pos = prefix_size - (72 - 28);
CHECK(0 <= guard_pos && guard_pos < 32);
size_t got_prefix_size = (const unsigned char*)H.body.rdata1 + guard_pos + 1 - (const unsigned char*)&H;
CHECK(prefix_size == got_prefix_size);
auto head = data.substr(0, prefix_size);
auto tail = data.substr(prefix_size);
SHA256_CTX shactx1, shactx2;
std::array<td::uint8, 32> hash;
SHA256_Init(&shactx1);
auto guard = head.back();
td::int64 i = 0, i0 = 0;
for (; i < options.max_iterations; i++) {
if (!(i & 0xfffff) || head.back() != guard) {
if (options.hashes_computed) {
*options.hashes_computed += i - i0;
}
i0 = i;
if (options.expire_at && options.expire_at.value().is_in_past(td::Timestamp::now())) {
break;
}
H.body.set_expire((unsigned)td::Clocks::system() + 900);
guard = head.back();
SHA256_Init(&shactx1);
SHA256_Update(&shactx1, head.ubegin(), head.size());
}
shactx2 = shactx1;
SHA256_Update(&shactx2, tail.ubegin(), tail.size());
SHA256_Final(hash.data(), &shactx2);
if (memcmp(hash.data(), options.complexity.data(), 32) < 0) {
// FOUND
if (options.hashes_computed) {
*options.hashes_computed += i - i0;
}
return H.body.as_slice().str();
}
H.body.inc();
}
if (options.hashes_computed) {
*options.hashes_computed += i - i0;
}
return {};
}
} // namespace ton

23
crypto/util/Miner.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include "block/block.h"
#include "td/utils/optional.h"
#include "td/utils/Time.h"
#include <atomic>
#include <array>
namespace ton {
class Miner {
public:
struct Options {
block::StdAddress my_address;
std::array<td::uint8, 16> seed;
std::array<td::uint8, 32> complexity;
td::optional<td::Timestamp> expire_at;
td::int64 max_iterations = std::numeric_limits<td::int64>::max();
std::atomic<td::uint64>* hashes_computed{nullptr};
};
static td::optional<std::string> run(const Options& options);
};
} // namespace ton

214
crypto/util/pow-miner.cpp Normal file
View file

@ -0,0 +1,214 @@
#include "common/bigint.hpp"
#include "common/refint.h"
#include "block/block.h"
#include "td/utils/benchmark.h"
#include "td/utils/filesystem.h"
#include "vm/boc.h"
#include "openssl/digest.hpp"
#include <openssl/sha.h>
#include <iostream>
#include <thread>
#include <cstdlib>
#include <getopt.h>
#include "Miner.h"
const char* progname;
int usage() {
std::cerr
<< "usage: " << progname
<< " [-v][-B][-w<threads>] [-t<timeout>] <my-address> <pow-seed> <pow-complexity> <iterations> [<miner-addr> "
"<output-ext-msg-boc>]\n"
"Outputs a valid <rdata> value for proof-of-work testgiver after computing at most <iterations> hashes "
"or terminates with non-zero exit code\n";
std::exit(2);
}
td::RefInt256 parse_bigint(std::string str, int bits) {
int len = (int)str.size();
auto num = td::make_refint();
auto& x = num.write();
if (len >= 3 && str[0] == '0' && str[1] == 'x') {
if (x.parse_hex(str.data() + 2, len - 2) != len - 2) {
return {};
}
} else if (!len || x.parse_dec(str.data(), len) != len) {
return {};
}
return x.unsigned_fits_bits(bits) ? std::move(num) : td::RefInt256{};
}
td::RefInt256 parse_bigint_chk(std::string str, int bits) {
auto x = parse_bigint(std::move(str), bits);
if (x.is_null()) {
std::cerr << "fatal: `" << str << "` is not an integer" << std::endl;
usage();
}
return x;
}
void parse_addr(std::string str, block::StdAddress& addr) {
if (!addr.parse_addr(str) || (addr.workchain != -1 && addr.workchain != 0)) {
std::cerr << "fatal: `" << str.c_str() << "` is not a valid blockchain address" << std::endl;
usage();
}
}
bool make_boc = false;
std::string boc_filename;
block::StdAddress miner_address;
int verbosity = 0;
std::atomic<td::uint64> hashes_computed{0};
td::Timestamp start_at;
void print_stats() {
auto passed = td::Timestamp::now().at() - start_at.at();
if (passed < 1e-9) {
passed = 1;
}
std::cerr << "[ hashes computed: " << hashes_computed << " ]" << std::endl;
std::cerr << "[ speed: " << static_cast<double>(hashes_computed) / passed << " hps ]" << std::endl;
}
int found(td::Slice data) {
for (unsigned i = 0; i < data.size(); i++) {
printf("%02X", data.ubegin()[i]);
}
printf("\n");
if (make_boc) {
vm::CellBuilder cb;
td::Ref<vm::Cell> ext_msg, body;
CHECK(cb.store_bytes_bool(data) // body
&& cb.finalize_to(body) // -> body
&& cb.store_long_bool(0x44, 7) // ext_message_in$10 ...
&& cb.store_long_bool(miner_address.workchain, 8) // workchain
&& cb.store_bytes_bool(miner_address.addr.as_slice()) // miner addr
&& cb.store_long_bool(1, 6) // amount:Grams ...
&& cb.store_ref_bool(std::move(body)) // body:^Cell
&& cb.finalize_to(ext_msg));
auto boc = vm::std_boc_serialize(std::move(ext_msg), 2).move_as_ok();
std::cerr << "Saving " << boc.size() << " bytes of serialized external message into file `" << boc_filename << "`"
<< std::endl;
td::write_file(boc_filename, boc).ensure();
}
if (verbosity > 0) {
print_stats();
}
std::exit(0);
return 0;
}
void miner(const ton::Miner::Options& options) {
auto res = ton::Miner::run(options);
if (res) {
found(res.value());
}
}
class MinerBench : public td::Benchmark {
public:
std::string get_description() const override {
return "Miner";
}
void run(int n) override {
ton::Miner::Options options;
options.my_address.parse_addr("EQDU86V5wyPrLd4nQ0RHPcCLPZq_y1O5wFWyTsMw63vjXTOv");
std::fill(options.seed.begin(), options.seed.end(), 0xa7);
std::fill(options.complexity.begin(), options.complexity.end(), 0);
options.max_iterations = n;
CHECK(!ton::Miner::run(options));
}
};
int main(int argc, char* const argv[]) {
ton::Miner::Options options;
progname = argv[0];
int i, threads = 0;
bool bounce = false, benchmark = false;
while ((i = getopt(argc, argv, "bnvw:t:Bh")) != -1) {
switch (i) {
case 'v':
++verbosity;
break;
case 'w':
threads = atoi(optarg);
CHECK(threads > 0 && threads <= 128);
break;
case 't': {
int timeout = atoi(optarg);
CHECK(timeout > 0);
options.expire_at = td::Timestamp::in(timeout);
break;
}
case 'B':
benchmark = true;
break;
case 'b':
bounce = true;
break;
case 'n':
bounce = false;
break;
case 'h':
return usage();
default:
std::cerr << "unknown option" << std::endl;
return usage();
}
}
if (benchmark && argc == optind) {
td::bench(MinerBench());
return 0;
}
if (argc != optind + 4 && argc != optind + 6) {
return usage();
}
parse_addr(argv[optind], options.my_address);
options.my_address.bounceable = bounce;
CHECK(parse_bigint_chk(argv[optind + 1], 128)->export_bytes(options.seed.data(), 16, false));
auto cmplx = parse_bigint_chk(argv[optind + 2], 256);
CHECK(cmplx->export_bytes(options.complexity.data(), 32, false));
CHECK(!cmplx->unsigned_fits_bits(256 - 62));
td::BigInt256 bigpower, hrate;
bigpower.set_pow2(256).mod_div(*cmplx, hrate);
long long hash_rate = hrate.to_long();
options.max_iterations = parse_bigint_chk(argv[optind + 3], 50)->to_long();
if (argc == optind + 6) {
make_boc = true;
parse_addr(argv[optind + 4], miner_address);
boc_filename = argv[optind + 5];
}
if (verbosity >= 2) {
std::cerr << "[ expected required hashes for success: " << hash_rate << " ]" << std::endl;
}
if (benchmark) {
td::bench(MinerBench());
}
start_at = td::Timestamp::now();
options.hashes_computed = &hashes_computed;
// may invoke several miner threads
if (threads <= 0) {
miner(options);
} else {
std::vector<std::thread> T;
for (int i = 0; i < threads; i++) {
T.emplace_back(miner, options);
}
for (auto& thr : T) {
thr.join();
}
}
if (verbosity > 0) {
print_stats();
}
}

View file

@ -23,9 +23,10 @@
#include "vm/cells.h"
#include "vm/cellslice.h"
#include "td/utils/bits.h"
#include "td/utils/Slice-decl.h"
#include "td/utils/format.h"
#include "td/utils/crypto.h"
#include "td/utils/format.h"
#include "td/utils/misc.h"
#include "td/utils/Slice-decl.h"
namespace vm {
using td::Ref;

View file

@ -35,6 +35,8 @@
#include "td/utils/Span.h"
#include <functional>
namespace td {
extern template class td::Cnt<std::string>;
extern template class td::Ref<td::Cnt<std::string>>;
@ -186,7 +188,7 @@ class StackEntry {
private:
static bool is_list(const StackEntry* se);
template <typename T, Type tag>
Ref<T> dynamic_as() const & {
Ref<T> dynamic_as() const& {
return tp == tag ? static_cast<Ref<T>>(ref) : td::Ref<T>{};
}
template <typename T, Type tag>
@ -198,7 +200,7 @@ class StackEntry {
return tp == tag ? static_cast<Ref<T>>(std::move(ref)) : td::Ref<T>{};
}
template <typename T, Type tag>
Ref<T> as() const & {
Ref<T> as() const& {
return tp == tag ? Ref<T>{td::static_cast_ref(), ref} : td::Ref<T>{};
}
template <typename T, Type tag>
@ -230,31 +232,31 @@ class StackEntry {
return ref;
}
}
td::RefInt256 as_int() const & {
td::RefInt256 as_int() const& {
return as<td::CntInt256, t_int>();
}
td::RefInt256 as_int() && {
return move_as<td::CntInt256, t_int>();
}
Ref<Cell> as_cell() const & {
Ref<Cell> as_cell() const& {
return as<Cell, t_cell>();
}
Ref<Cell> as_cell() && {
return move_as<Cell, t_cell>();
}
Ref<CellBuilder> as_builder() const & {
Ref<CellBuilder> as_builder() const& {
return as<CellBuilder, t_builder>();
}
Ref<CellBuilder> as_builder() && {
return move_as<CellBuilder, t_builder>();
}
Ref<CellSlice> as_slice() const & {
Ref<CellSlice> as_slice() const& {
return as<CellSlice, t_slice>();
}
Ref<CellSlice> as_slice() && {
return move_as<CellSlice, t_slice>();
}
Ref<Continuation> as_cont() const &;
Ref<Continuation> as_cont() const&;
Ref<Continuation> as_cont() &&;
Ref<Cnt<std::string>> as_string_ref() const {
return as<Cnt<std::string>, t_string>();
@ -269,16 +271,16 @@ class StackEntry {
std::string as_bytes() const {
return tp == t_bytes ? *as_bytes_ref() : "";
}
Ref<Box> as_box() const &;
Ref<Box> as_box() const&;
Ref<Box> as_box() &&;
Ref<Tuple> as_tuple() const &;
Ref<Tuple> as_tuple() const&;
Ref<Tuple> as_tuple() &&;
Ref<Tuple> as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) const &;
Ref<Tuple> as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) const&;
Ref<Tuple> as_tuple_range(unsigned max_len = 255, unsigned min_len = 0) &&;
Ref<Atom> as_atom() const &;
Ref<Atom> as_atom() const&;
Ref<Atom> as_atom() &&;
template <class T>
Ref<T> as_object() const & {
Ref<T> as_object() const& {
return dynamic_as<T, t_object>();
}
template <class T>
@ -444,7 +446,7 @@ class Stack : public td::CntObject {
}
return *this;
}
std::vector<StackEntry> extract_contents() const & {
std::vector<StackEntry> extract_contents() const& {
return stack;
}
std::vector<StackEntry> extract_contents() && {