mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			129 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    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 "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.token_) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      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
 |