15
15
#include < bls.hpp>
16
16
#include < sodium.h>
17
17
#include < cxxopts.hpp>
18
+ #include < libbech32.h>
18
19
19
20
#include < string>
20
21
#include < csignal>
@@ -54,17 +55,44 @@ static void interrupt_handler(int sig)
54
55
}
55
56
}
56
57
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
+
57
83
inline
58
84
phase4::output_t create_plot ( const int num_threads,
59
85
const int log_num_buckets,
60
86
const int log_num_buckets_3,
61
87
const vector<uint8_t >& pool_key_bytes,
88
+ const vector<uint8_t >& puzzle_hash_bytes,
62
89
const vector<uint8_t >& farmer_key_bytes,
63
90
const std::string& tmp_dir,
64
91
const std::string& tmp_dir_2)
65
92
{
66
93
const auto total_begin = get_wall_time_micros ();
67
-
94
+ const bool have_puzzle = !puzzle_hash_bytes.empty ();
95
+
68
96
std::cout << " Process ID: " << GETPID () << std::endl;
69
97
std::cout << " Number of Threads: " << num_threads << std::endl;
70
98
std::cout << " Number of Buckets P1: 2^" << log_num_buckets
@@ -74,19 +102,25 @@ phase4::output_t create_plot( const int num_threads,
74
102
75
103
bls::G1Element pool_key;
76
104
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
+ }
82
112
}
83
113
try {
84
114
farmer_key = bls::G1Element::FromByteVector (farmer_key_bytes);
85
115
} catch (std::exception& ex) {
86
116
std::cout << " Invalid farmerkey: " << bls::Util::HexStr (farmer_key_bytes) << std::endl;
87
117
throw ;
88
118
}
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
+ }
90
124
std::cout << " Farmer Public Key: " << bls::Util::HexStr (farmer_key.Serialize ()) << std::endl;
91
125
92
126
vector<uint8_t > seed (32 );
@@ -100,11 +134,31 @@ phase4::output_t create_plot( const int num_threads,
100
134
local_sk = MPL.DeriveChildSk (local_sk, i);
101
135
}
102
136
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
+ }
104
158
105
159
phase1::input_t params;
106
160
{
107
- vector<uint8_t > bytes = pool_key.Serialize ();
161
+ vector<uint8_t > bytes = have_puzzle ? puzzle_hash_bytes : pool_key.Serialize ();
108
162
{
109
163
const auto plot_bytes = plot_key.Serialize ();
110
164
bytes.insert (bytes.end (), plot_bytes.begin (), plot_bytes.end ());
@@ -118,8 +172,11 @@ phase4::output_t create_plot( const int num_threads,
118
172
std::cout << " Working Directory 2: " << (tmp_dir_2.empty () ? " $PWD" : tmp_dir_2) << std::endl;
119
173
std::cout << " Plot Name: " << plot_name << std::endl;
120
174
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
+ }
123
180
params.memo .insert (params.memo .end (), farmer_key_bytes.begin (), farmer_key_bytes.end ());
124
181
{
125
182
const auto bytes = master_sk.Serialize ();
@@ -160,6 +217,7 @@ int _main(int argc, char** argv)
160
217
161
218
cxxopts::Options options (" chia_plot" ,
162
219
" 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 "
163
221
" <tmpdir> needs about 220 GiB space, it will handle about 25% of all writes. (Examples: './', '/mnt/tmp/')\n "
164
222
" <tmpdir2> needs about 110 GiB space and ideally is a RAM drive, it will handle about 75% of all writes.\n "
165
223
" Combined (tmpdir + tmpdir2) peak disk usage is less than 256 GiB.\n "
@@ -168,6 +226,7 @@ int _main(int argc, char** argv)
168
226
);
169
227
170
228
std::string pool_key_str;
229
+ std::string contract_addr_str;
171
230
std::string farmer_key_str;
172
231
std::string tmp_dir;
173
232
std::string tmp_dir2;
@@ -189,6 +248,7 @@ int _main(int argc, char** argv)
189
248
" d, finaldir" , " Final directory (default = <tmpdir>)" , cxxopts::value<std::string>(final_dir))(
190
249
" w, waitforcopy" , " Wait for copy to start next plot" , cxxopts::value<bool >(waitforcopy))(
191
250
" 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))(
192
252
" f, farmerkey" , " Farmer Public Key (48 bytes)" , cxxopts::value<std::string>(farmer_key_str))(
193
253
" G, tmptoggle" , " Alternate tmpdir/tmpdir2" , cxxopts::value<bool >(tmptoggle))(
194
254
" help" , " Print help" );
@@ -203,12 +263,16 @@ int _main(int argc, char** argv)
203
263
std::cout << options.help ({" " }) << std::endl;
204
264
return 0 ;
205
265
}
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;
208
272
return -2 ;
209
273
}
210
274
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;
212
276
return -2 ;
213
277
}
214
278
if (tmp_dir.empty ()) {
@@ -224,15 +288,33 @@ int _main(int argc, char** argv)
224
288
if (num_buckets_3 <= 0 ) {
225
289
num_buckets_3 = num_buckets;
226
290
}
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;
228
293
const auto farmer_key = hex_to_bytes (farmer_key_str);
229
294
const int log_num_buckets = num_buckets >= 16 ? int (log2 (num_buckets)) : num_buckets;
230
295
const int log_num_buckets_3 = num_buckets_3 >= 16 ? int (log2 (num_buckets_3)) : num_buckets_3;
231
296
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
+ }
236
318
}
237
319
if (farmer_key.size () != bls::G1Element::SIZE) {
238
320
std::cout << " Invalid farmerkey: " << bls::Util::HexStr (farmer_key) << " , '" << farmer_key_str
@@ -372,7 +454,7 @@ int _main(int argc, char** argv)
372
454
std::cout << " Crafting plot " << i+1 << " out of " << num_plots << std::endl;
373
455
const auto out = create_plot (
374
456
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);
376
458
377
459
if (final_dir != tmp_dir)
378
460
{
0 commit comments