Skip to content

Commit 82f92a9

Browse files
committed
Merge branch 'wfr-ph' of https://github.com/stotiks/chia-plotter into windows-fury-road
2 parents a53cf8e + 9e7b4c3 commit 82f92a9

File tree

5 files changed

+111
-22
lines changed

5 files changed

+111
-22
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "lib/BLAKE3"]
55
path = lib/BLAKE3
66
url = https://github.com/BLAKE3-team/BLAKE3.git
7+
[submodule "lib/libbech32"]
8+
path = lib/libbech32
9+
url = https://github.com/dcdpr/libbech32.git

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ endif()
4646

4747
add_subdirectory(lib/bls-signatures)
4848

49+
add_subdirectory(lib/libbech32)
4950

5051
set(BLAKE3_PATH lib/BLAKE3/c)
5152
set(FSE_PATH lib/FSE/lib)
@@ -54,6 +55,7 @@ include_directories(
5455
lib
5556
include
5657
lib/bls-signatures/src
58+
lib/libbech32/include/libbech32
5759
${BLAKE3_PATH}
5860
${CMAKE_BINARY_DIR}/_deps/relic-src/include
5961
${CMAKE_BINARY_DIR}/_deps/relic-build/include
@@ -110,9 +112,9 @@ add_library(chia_plotter STATIC
110112
)
111113

112114
if (MSVC)
113-
target_link_libraries(chia_plotter blake3 fse)
115+
target_link_libraries(chia_plotter blake3 fse bech32)
114116
else()
115-
target_link_libraries(chia_plotter blake3 fse Threads::Threads)
117+
target_link_libraries(chia_plotter blake3 fse bech32 Threads::Threads)
116118
endif()
117119

118120
if(CHIA_PLOT_BUILD_TESTS)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Usage:
2929
-d, --finaldir arg Final directory (default = <tmpdir>)
3030
-w, --waitforcopy Wait for copy to start next plot
3131
-p, --poolkey arg Pool Public Key (48 bytes)
32+
-c, --contract arg Pool Contract Address (64 chars)
3233
-f, --farmerkey arg Farmer Public Key (48 bytes)
3334
-G, --tmptoggle Alternate tmpdir/tmpdir2 (default = false)
3435
--help Print help

lib/libbech32

Submodule libbech32 added at 954b14f

src/chia_plot.cpp

Lines changed: 102 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <bls.hpp>
1616
#include <sodium.h>
1717
#include <cxxopts.hpp>
18+
#include <libbech32.h>
1819

1920
#include <string>
2021
#include <csignal>
@@ -54,17 +55,44 @@ static void interrupt_handler(int sig)
5455
}
5556
}
5657

58+
std::vector<uint8_t> bech32_address_decode(const std::string& addr)
59+
{
60+
const auto res = bech32::decode(addr);
61+
if(res.encoding != bech32::Bech32m) {
62+
throw std::logic_error("invalid contract address (!Bech32m): " + addr);
63+
}
64+
if(res.hrp != "xch" && res.hrp != "txch") {
65+
throw std::logic_error("invalid contract address (" + res.hrp + " != xch): " + addr);
66+
}
67+
if(res.dp.size() != 52) {
68+
throw std::logic_error("invalid contract address (size != 52): " + addr);
69+
}
70+
Bits bits;
71+
for(int i = 0; i < 51; ++i) {
72+
bits.AppendValue(res.dp[i], 5);
73+
}
74+
bits.AppendValue(res.dp[51] >> 4, 1);
75+
if(bits.GetSize() != 32 * 8) {
76+
throw std::logic_error("invalid contract address (bits != 256): " + addr);
77+
}
78+
std::vector<uint8_t> hash(32);
79+
bits.ToBytes(hash.data());
80+
return hash;
81+
}
82+
5783
inline
5884
phase4::output_t create_plot( const int num_threads,
5985
const int log_num_buckets,
6086
const int log_num_buckets_3,
6187
const vector<uint8_t>& pool_key_bytes,
88+
const vector<uint8_t>& puzzle_hash_bytes,
6289
const vector<uint8_t>& farmer_key_bytes,
6390
const std::string& tmp_dir,
6491
const std::string& tmp_dir_2)
6592
{
6693
const auto total_begin = get_wall_time_micros();
67-
94+
const bool have_puzzle = !puzzle_hash_bytes.empty();
95+
6896
std::cout << "Process ID: " << GETPID() << std::endl;
6997
std::cout << "Number of Threads: " << num_threads << std::endl;
7098
std::cout << "Number of Buckets P1: 2^" << log_num_buckets
@@ -74,19 +102,25 @@ phase4::output_t create_plot( const int num_threads,
74102

75103
bls::G1Element pool_key;
76104
bls::G1Element farmer_key;
77-
try {
78-
pool_key = bls::G1Element::FromByteVector(pool_key_bytes);
79-
} catch(std::exception& ex) {
80-
std::cout << "Invalid poolkey: " << bls::Util::HexStr(pool_key_bytes) << std::endl;
81-
throw;
105+
if(!have_puzzle) {
106+
try {
107+
pool_key = bls::G1Element::FromByteVector(pool_key_bytes);
108+
} catch(std::exception& ex) {
109+
std::cout << "Invalid poolkey: " << bls::Util::HexStr(pool_key_bytes) << std::endl;
110+
throw;
111+
}
82112
}
83113
try {
84114
farmer_key = bls::G1Element::FromByteVector(farmer_key_bytes);
85115
} catch(std::exception& ex) {
86116
std::cout << "Invalid farmerkey: " << bls::Util::HexStr(farmer_key_bytes) << std::endl;
87117
throw;
88118
}
89-
std::cout << "Pool Public Key: " << bls::Util::HexStr(pool_key.Serialize()) << std::endl;
119+
if(have_puzzle) {
120+
std::cout << "Pool Puzzle Hash: " << bls::Util::HexStr(puzzle_hash_bytes) << std::endl;
121+
} else {
122+
std::cout << "Pool Public Key: " << bls::Util::HexStr(pool_key.Serialize()) << std::endl;
123+
}
90124
std::cout << "Farmer Public Key: " << bls::Util::HexStr(farmer_key.Serialize()) << std::endl;
91125

92126
vector<uint8_t> seed(32);
@@ -100,11 +134,31 @@ phase4::output_t create_plot( const int num_threads,
100134
local_sk = MPL.DeriveChildSk(local_sk, i);
101135
}
102136
const bls::G1Element local_key = local_sk.GetG1Element();
103-
const bls::G1Element plot_key = local_key + farmer_key;
137+
138+
bls::G1Element plot_key;
139+
if(have_puzzle) {
140+
vector<uint8_t> bytes = (local_key + farmer_key).Serialize();
141+
{
142+
const auto more_bytes = local_key.Serialize();
143+
bytes.insert(bytes.end(), more_bytes.begin(), more_bytes.end());
144+
}
145+
{
146+
const auto more_bytes = farmer_key.Serialize();
147+
bytes.insert(bytes.end(), more_bytes.begin(), more_bytes.end());
148+
}
149+
std::vector<uint8_t> hash(32);
150+
bls::Util::Hash256(hash.data(), bytes.data(), bytes.size());
151+
152+
const auto taproot_sk = MPL.KeyGen(hash);
153+
plot_key = local_key + farmer_key + taproot_sk.GetG1Element();
154+
}
155+
else {
156+
plot_key = local_key + farmer_key;
157+
}
104158

105159
phase1::input_t params;
106160
{
107-
vector<uint8_t> bytes = pool_key.Serialize();
161+
vector<uint8_t> bytes = have_puzzle ? puzzle_hash_bytes : pool_key.Serialize();
108162
{
109163
const auto plot_bytes = plot_key.Serialize();
110164
bytes.insert(bytes.end(), plot_bytes.begin(), plot_bytes.end());
@@ -118,8 +172,11 @@ phase4::output_t create_plot( const int num_threads,
118172
std::cout << "Working Directory 2: " << (tmp_dir_2.empty() ? "$PWD" : tmp_dir_2) << std::endl;
119173
std::cout << "Plot Name: " << plot_name << std::endl;
120174

121-
// memo = bytes(pool_public_key) + bytes(farmer_public_key) + bytes(local_master_sk)
122-
params.memo.insert(params.memo.end(), pool_key_bytes.begin(), pool_key_bytes.end());
175+
if(have_puzzle) {
176+
params.memo.insert(params.memo.end(), puzzle_hash_bytes.begin(), puzzle_hash_bytes.end());
177+
} else {
178+
params.memo.insert(params.memo.end(), pool_key_bytes.begin(), pool_key_bytes.end());
179+
}
123180
params.memo.insert(params.memo.end(), farmer_key_bytes.begin(), farmer_key_bytes.end());
124181
{
125182
const auto bytes = master_sk.Serialize();
@@ -160,6 +217,7 @@ int _main(int argc, char** argv)
160217

161218
cxxopts::Options options("chia_plot",
162219
"For <poolkey> and <farmerkey> see output of `chia keys show`.\n"
220+
"To plot for pools, specify <contract> address instead of <poolkey>, see `chia plotnft show`.\n"
163221
"<tmpdir> needs about 220 GiB space, it will handle about 25% of all writes. (Examples: './', '/mnt/tmp/')\n"
164222
"<tmpdir2> needs about 110 GiB space and ideally is a RAM drive, it will handle about 75% of all writes.\n"
165223
"Combined (tmpdir + tmpdir2) peak disk usage is less than 256 GiB.\n"
@@ -168,6 +226,7 @@ int _main(int argc, char** argv)
168226
);
169227

170228
std::string pool_key_str;
229+
std::string contract_addr_str;
171230
std::string farmer_key_str;
172231
std::string tmp_dir;
173232
std::string tmp_dir2;
@@ -189,6 +248,7 @@ int _main(int argc, char** argv)
189248
"d, finaldir", "Final directory (default = <tmpdir>)", cxxopts::value<std::string>(final_dir))(
190249
"w, waitforcopy", "Wait for copy to start next plot", cxxopts::value<bool>(waitforcopy))(
191250
"p, poolkey", "Pool Public Key (48 bytes)", cxxopts::value<std::string>(pool_key_str))(
251+
"c, contract", "Pool Contract Address (64 chars)", cxxopts::value<std::string>(contract_addr_str))(
192252
"f, farmerkey", "Farmer Public Key (48 bytes)", cxxopts::value<std::string>(farmer_key_str))(
193253
"G, tmptoggle", "Alternate tmpdir/tmpdir2", cxxopts::value<bool>(tmptoggle))(
194254
"help", "Print help");
@@ -203,12 +263,16 @@ int _main(int argc, char** argv)
203263
std::cout << options.help({""}) << std::endl;
204264
return 0;
205265
}
206-
if(pool_key_str.empty()) {
207-
std::cout << "Pool Public Key (48 bytes) needs to be specified via -p <hex>, see `chia keys show`." << std::endl;
266+
if(contract_addr_str.empty() && pool_key_str.empty()) {
267+
std::cout << "Pool Public Key (for solo farming) or Pool Contract Address (for pool farming) needs to be specified via -p or -c, see `chia_plot --help`." << std::endl;
268+
return -2;
269+
}
270+
if(!contract_addr_str.empty() && !pool_key_str.empty()) {
271+
std::cout << "Choose either Pool Public Key (for solo farming) or Pool Contract Address (for pool farming), see `chia_plot --help`." << std::endl;
208272
return -2;
209273
}
210274
if(farmer_key_str.empty()) {
211-
std::cout << "Farmer Public Key (48 bytes) needs to be specified via -f <hex>, see `chia keys show`." << std::endl;
275+
std::cout << "Farmer Public Key (48 bytes) needs to be specified via -f, see `chia keys show`." << std::endl;
212276
return -2;
213277
}
214278
if(tmp_dir.empty()) {
@@ -224,15 +288,33 @@ int _main(int argc, char** argv)
224288
if(num_buckets_3 <= 0) {
225289
num_buckets_3 = num_buckets;
226290
}
227-
const auto pool_key = hex_to_bytes(pool_key_str);
291+
std::vector<uint8_t> pool_key;
292+
std::vector<uint8_t> puzzle_hash;
228293
const auto farmer_key = hex_to_bytes(farmer_key_str);
229294
const int log_num_buckets = num_buckets >= 16 ? int(log2(num_buckets)) : num_buckets;
230295
const int log_num_buckets_3 = num_buckets_3 >= 16 ? int(log2(num_buckets_3)) : num_buckets_3;
231296

232-
if(pool_key.size() != bls::G1Element::SIZE) {
233-
std::cout << "Invalid poolkey: " << bls::Util::HexStr(pool_key) << ", '" << pool_key_str
234-
<< "' (needs to be " << bls::G1Element::SIZE << " bytes, see `chia keys show`)" << std::endl;
235-
return -2;
297+
if(contract_addr_str.empty()) {
298+
pool_key = hex_to_bytes(pool_key_str);
299+
if(pool_key.size() != bls::G1Element::SIZE) {
300+
std::cout << "Invalid poolkey: " << bls::Util::HexStr(pool_key) << ", '" << pool_key_str
301+
<< "' (needs to be " << bls::G1Element::SIZE << " bytes, see `chia keys show`)" << std::endl;
302+
return -2;
303+
}
304+
}
305+
else {
306+
try {
307+
puzzle_hash = bech32_address_decode(contract_addr_str);
308+
if(puzzle_hash.size() != 32) {
309+
throw std::logic_error("pool puzzle hash needs to be 32 bytes");
310+
}
311+
}
312+
catch(std::exception& ex) {
313+
std::cout << "Invalid contract (address): 0x"
314+
<< bls::Util::HexStr(puzzle_hash) << ", '" << contract_addr_str
315+
<< "' (" << ex.what() << ", see `chia plotnft show`)" << std::endl;
316+
return -2;
317+
}
236318
}
237319
if(farmer_key.size() != bls::G1Element::SIZE) {
238320
std::cout << "Invalid farmerkey: " << bls::Util::HexStr(farmer_key) << ", '" << farmer_key_str
@@ -372,7 +454,7 @@ int _main(int argc, char** argv)
372454
std::cout << "Crafting plot " << i+1 << " out of " << num_plots << std::endl;
373455
const auto out = create_plot(
374456
num_threads, log_num_buckets, log_num_buckets_3,
375-
pool_key, farmer_key, tmp_dir, tmp_dir2);
457+
pool_key, puzzle_hash, farmer_key, tmp_dir, tmp_dir2);
376458

377459
if(final_dir != tmp_dir)
378460
{

0 commit comments

Comments
 (0)